在Swift中使用CCCrypt(CommonCrypt)问题

我正在将一个工作的Objective-C类别(NSData + AESCrypt.m)移植到Swift中,并且发现了一个指针问题。 Swift中encryption部分的代码编译正确,但生成一个运行时EXEC_BAD_ACCES错误。

我到目前为止的代码是(我试图尽可能解剖代码):

let key = "123456789012345678901234567890120" let keyLength = UInt(kCCKeySizeAES256 + 1) let keyPointer = strdup(key) // Convert key to <UnsafeMutablePointer<Int8> let message = "Don´t try to read this text. Top Secret Stuff" let data = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) let dataBytes = data?.bytes let length = data?.length let dataLength = UInt(length!) let dataPointer = UnsafePointer<UInt8>(dataBytes!) let operation: CCOperation = UInt32(kCCEncrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding) let cryptBufferSize = UInt(dataLength + kCCBlockSizeAES128) var cryptBuffer = [UInt8](count: Int(cryptBufferSize), repeatedValue: 0) var cryptBufferPointer = UnsafeMutablePointer<UInt8>(cryptBuffer) var numBytesEncrypted = UnsafeMutablePointer<UInt>() var cryptStatus = CCCrypt(operation, algoritm, options, keyPointer, keyLength, nil, dataPointer, dataLength, cryptBufferPointer, cryptBufferSize, numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { let size = NSInteger(cryptBufferSize) let encryptedData = NSData(bytes: cryptBufferPointer, length: size) let encryptedString = NSString(data: encryptedData, encoding: NSUTF8StringEncoding) println("Encrypted String = \(encryptedString)") // EXEC_BAD_ACCESS error } else { println("Error: \(cryptStatus)") } 

encryptedData对象显示以下信息:

 <279c2d0f d3ce2200 0dc10cc1 9df46e76 cb26f423 7c9bde76 f9d8d0e2 632acef9 74fb0614 4717422b 684d1889 e3ce882c 00000000 00000000 00000000 0000> 

但是encryptedString在debugging器中显示0x0000000000 ,并试图println()它会生成EXEC_BAD_ACCESS错误

任何想法缺less什么?

RGDS ….

Swift 2.0

这是一个例子
如果这不是所需的方法应该是一个很好的例子
注意:密钥string被转换为数据

将Security.framework添加到项目
#import <CommonCrypto/CommonCryptor.h>添加到桥接头。

 let keyString = "12345678901234567890123456789012" let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! print("keyLength = \(keyData.length), keyData = \(keyData)") let message = "Don´t try to read this text. Top Secret Stuff" let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! print("data length = \(data.length), data = \(data)") let cryptData = NSMutableData(length: Int(data.length) + kCCBlockSizeAES128)! let keyLength = size_t(kCCKeySizeAES256) let operation: CCOperation = UInt32(kCCEncrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding) var numBytesEncrypted :size_t = 0 var cryptStatus = CCCrypt(operation, algoritm, options, keyData.bytes, keyLength, nil, data.bytes, data.length, cryptData.mutableBytes, cryptData.length, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)") // Not all data is a UTF-8 string so Base64 is used let base64cryptString = cryptData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength) print("base64cryptString = \(base64cryptString)") } else { print("Error: \(cryptStatus)") } 

输出:

 keyLength = 32, keyData = <31323334 35363738 39303132 33343536 37383930 31323334 35363738 39303132> dataLength = 46, data = <446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666> cryptLength = 48, cryptData = <118a32dc c23f7caa 883abc3c 1c7f0770 e200016b 2737acfa 17bb96fb a02b02a7 c147603b 06acd863 94bb8ff2 6cb14515> base64cryptString = EYoy3MI/fKqIOrw8HH8HcOIAAWsnN6z6F7uW+6ArAqfBR2A7BqzYY5S7j/JssUUV 
  

Swift 3

iv是encryption数据的前缀

aesCBC128Encrypt将创build一个随机的IV,并以encryption的代码为前缀。
aesCBC128Decrypt将在解密期间使用前缀IV。

input是数据,关键是数据对象。 如果需要,如Base64等编码forms转换为和/或从调用方法。

密钥的长度应该是128位(16字节),192位(24字节)或256位(32字节)。 如果使用其他密钥大小,则会引发错误。

PKCS#7填充是默认设置的。

这个例子需要Common Crypto
有必要有一个桥头到项目:
#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 = "clearData0123456".data(using:String.Encoding.utf8)! let keyData = "keyData890123456".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的创build和共享留给用户。 这个例子包括IV的生成,在encryption的数据前加前缀,并且在解密期间使用前缀IV。 这使得临时用户从CBC模式所需的细节中解放出来。

为了安全,encryption的数据也应该具有authentication,这个示例代码没有规定为了小而且允许其他平台更好的互操作性。

另外还缺less密钥的密钥推导,build议使用PBKDF2是将文本密码用作密钥材料。

要获得稳健的生产就绪多平台encryption代码,请参阅RNCryptor 。

Swift 2.0encryption和解密。 刚刚更新了上面的答案来支持Swift 2.0。

 static func AES128Encryption() { let keyString = "12345678901234567890123456789012" let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes) print("keyLength = \(keyData.length), keyData = \(keyData)") let message = "Don´t try to read this text. Top Secret Stuff" let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let dataLength = size_t(data.length) let dataBytes = UnsafeMutablePointer<Void>(data.bytes) print("dataLength = \(dataLength), data = \(data)") let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128) let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes) let cryptLength = size_t(cryptData!.length) let keyLength = size_t(kCCKeySizeAES256) let operation: CCOperation = UInt32(kCCEncrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode) var numBytesEncrypted :size_t = 0 let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, nil, dataBytes, dataLength, cryptPointer, cryptLength, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { // let x: UInt = numBytesEncrypted cryptData!.length = Int(numBytesEncrypted) print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)") // Not all data is a UTF-8 string so Base64 is used let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength) print("base64cryptString = \(base64cryptString)") } else { print("Error: \(cryptStatus)") } } static func AES128Decryption(data:NSData) //data = cryptData { let keyString = "12345678901234567890123456789012" let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes) print("keyLength = \(keyData.length), keyData = \(keyData)") //let message = "Don´t try to read this text. Top Secret Stuff" // let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let dataLength = size_t(data.length) let dataBytes = UnsafeMutablePointer<Void>(data.bytes) print("dataLength = \(dataLength), data = \(data)") let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128) let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes) let cryptLength = size_t(cryptData!.length) let keyLength = size_t(kCCKeySizeAES256) let operation: CCOperation = UInt32(kCCDecrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode) var numBytesEncrypted :size_t = 0 let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, nil, dataBytes, dataLength, cryptPointer, cryptLength, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { // let x: UInt = numBytesEncrypted cryptData!.length = Int(numBytesEncrypted) print("DecryptcryptLength = \(numBytesEncrypted), Decrypt = \(cryptData)") // Not all data is a UTF-8 string so Base64 is used let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength) print("base64DecryptString = \(base64cryptString)") print( "utf8 actual string = \(NSString(data: cryptData!, encoding: NSUTF8StringEncoding))"); } else { print("Error: \(cryptStatus)") } }