對稱加密用於加密數據,而AES(高級加密標準)是當前的標準。 Apple在Security.framework中提供Common Crypto,並在iOS上快速使用適用的OSX指令和硬件加密。另外將密鑰存儲在鑰匙串中。從棄用文檔部分
實施例:
AES加密CBC模式與隨機IV(SWIFT 3+)
的IV被前綴到加密數據
aesCBC128Encrypt
將創建一個隨機IV並以加密碼爲前綴。
aesCBC128Decrypt
將在解密期間使用前綴IV。
輸入是數據,鍵是數據對象。如果需要的話,如Base64等編碼形式轉換爲和/或從調用方法中轉換。
密鑰的長度應該正好是128位(16字節),192位(24字節)或256位(32字節)。如果使用其他密鑰大小,則會引發錯誤。
PKCS#7 padding默認設置。
這個例子需要公共的密碼
這是需要有一個橋接報的項目:
#import <CommonCrypto/CommonCrypto.h>
添加Security.framework
到項目中。
這是例子,而不是產品代碼。
enum AESError: Error {
case KeyError((String, Int))
case IVError((String, Int))
case CryptorError((String, Int))
}
// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}
let ivSize = kCCBlockSizeAES128;
let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength)
let status = cryptData.withUnsafeMutableBytes {ivBytes in
SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
}
if (status != 0) {
throw AESError.IVError(("IV generation failed", Int(status)))
}
var numBytesEncrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
options,
keyBytes, keyLength,
cryptBytes,
dataBytes, data.count,
cryptBytes+kCCBlockSizeAES128, cryptLength,
&numBytesEncrypted)
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.count = numBytesEncrypted + ivSize
}
else {
throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
}
return cryptData;
}
// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}
let ivSize = kCCBlockSizeAES128;
let clearLength = size_t(data.count - ivSize)
var clearData = Data(count:clearLength)
var numBytesDecrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
options,
keyBytes, keyLength,
dataBytes,
dataBytes+kCCBlockSizeAES128, clearLength,
cryptBytes, clearLength,
&numBytesDecrypted)
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
clearData.count = numBytesDecrypted
}
else {
throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
}
return clearData;
}
實例:
let clearData = "clearData".data(using:String.Encoding.utf8)!
let keyData = "keyData89".data(using:String.Encoding.utf8)!
print("clearData: \(clearData as NSData)")
print("keyData: \(keyData as NSData)")
var cryptData :Data?
do {
cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
print("cryptData: \(cryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCEncrypt: \(status)")
}
let decryptData :Data?
do {
let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCDecrypt: \(status)")
}
示例輸出:
clearData: <636c6561 72446174 61303132 33343536>
keyData: <6b657944 61746138 39303132 33343536>
cryptData: <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>
注:
與CBC模式示例代碼的一個典型問題是,它離開隨機的創建和共享IV給用戶。這個例子包括生成IV,在加密數據前加上前綴,並在解密時使用前綴IV。這使臨時用戶免於CBC mode所需的細節。
爲了安全,加密的數據也應該有認證,這個示例代碼沒有規定爲了小,並且允許其他平臺更好的互操作性。
還缺少的是從密碼中得到密鑰的關鍵推導,建議使用PBKDF2是將文本密碼用作密鑰材料。
要獲得穩健的生產就緒多平臺加密代碼,請參見RNCryptor。 同時考慮RNCryptor的完整實現,包括密碼派生,加密驗證和版本控制。
注意密碼和密鑰:
密碼和密鑰之間有區別。 AES加密密鑰恰好是3種長度中的一種:128,192或256位,並且看起來應該是隨機位。密碼/密碼是人類可讀的文本。當使用密碼時,加密密鑰需要從中派生出來,還有一些功能可以實現,例如PBKDF2(基於密碼的密鑰派生功能2)。 RNCryptor包含這樣的派生函數。
基於密碼的密鑰派生2(SWIFT 3+)
基於密碼的密鑰派生可以用於從密碼文本加密密鑰和保存用於身份驗證密碼均可使用。
有幾種散列算法可以使用,包括本示例代碼提供的SHA1,SHA256,SHA512。
rounds參數用於使計算速度變慢,以便攻擊者必須在每次嘗試中花費大量時間。典型的延遲值在100ms到500ms之間,如果有不可接受的性能,可以使用較短的值。
這個例子需要公共的密碼
這是需要有一個橋接報的項目:
#import <CommonCrypto/CommonCrypto.h>
添加Security.framework
到項目中。
參數:
password password String
salt salt Data
keyByteCount number of key bytes to generate
rounds Iteration rounds
returns Derived key
func pbkdf2SHA1(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA1), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}
func pbkdf2SHA256(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}
func pbkdf2SHA512(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}
func pbkdf2(hash :CCPBKDFAlgorithm, password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
let passwordData = password.data(using:String.Encoding.utf8)!
var derivedKeyData = Data(repeating:0, count:keyByteCount)
let derivationStatus = derivedKeyData.withUnsafeMutableBytes {derivedKeyBytes in
salt.withUnsafeBytes { saltBytes in
CCKeyDerivationPBKDF(
CCPBKDFAlgorithm(kCCPBKDF2),
password, passwordData.count,
saltBytes, salt.count,
hash,
UInt32(rounds),
derivedKeyBytes, derivedKeyData.count)
}
}
if (derivationStatus != 0) {
print("Error: \(derivationStatus)")
return nil;
}
return derivedKeyData
}
用法示例:
let password = "password"
//let salt = "saltData".data(using: String.Encoding.utf8)!
let salt = Data(bytes: [0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
let keyByteCount = 16
let rounds = 100000
let derivedKey = pbkdf2SHA1(password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
print("derivedKey (SHA1): \(derivedKey! as NSData)")
輸出示例:
derivedKey (SHA1): <6b9d4fa3 0385d128 f6d196ee 3f1d6dbf>
SO是不是真的喜歡這個一般性問題。網上有大量的信息,教程和建議。我相信你會弄明白的。如果您稍後有關於您的代碼的詳細問題,請回來;所以人們會很樂意提供幫助。祝你們總決賽好運! –
哦,我沒有意識到我在這裏做錯了事。對於那個很抱歉!我會確保我未來的問題更具體。此外,感謝您選擇正確答案和聲譽的提示 - 正如您所看到的,我沒有花太多時間在SO上,並且仍然在學習如何進行下去。 – Sanders0492