下面是示例代碼可用於TrippleDES被容易地修改:
從子集SO文檔部分
對於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。
如果您必須將此功能修改爲3DES。
對於PBKDF2加密**基於密碼的密鑰派生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>
這是有幾個原因非常不安全的。 1. 3DES不應該用於新作品,請使用AES。 2.不要使用ECB模式,這是不安全的,請參閱[ECB模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29),向下滾動到企鵝。 取而代之的是將CBC模式與隨機IV一起使用,只是將加密數據與IV一起用於解密。 3.不要使用MD5從密碼派生密鑰,使用PBKDF2(基於密碼的密鑰派生函數2)的循環值大約需要100ms。 – zaph
@zaph謝謝你的回覆,但我不得不使用tripleDes和MD5,因爲我們發送數據的服務器只接受tripleDes和MD5,而我不能使用其他任何東西。 – ava
好的,但可惜的是服務器的實現並不安全,這是用戶被置於危險之中,而且真的無法接受。 – zaph