Problem using CCCrypt (CommonCrypt) in Swift

I am moving the working Objective-C category (NSData + AESCrypt.m) to Swift, and I have encountered a problem with pointers. The code for encryption in Swift compiles correctly, but generates an EXEC_BAD_ACCES error at runtime.

The code that I have so far (I tried to analyze the code as much as possible):

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)") } 

The encryptedData object displays the following information:

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

But encryptedString shows 0x0000000000 in the debugger and tries println() generate EXEC_BAD_ACCESS error

Any idea what is missing?

Rgds ....

+7
ios objective-c cryptography swift commoncrypto
source share
2 answers

Swift 2.0

Here is an example
If this is not quite what you need, methods should be a good example
Note: the key string is converted to data

Add Security.framework to the project
Add #import <CommonCrypto/CommonCryptor.h> to the bridge header.

 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)") } 

Output:

 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

Document iv prefix for encrypted data

aesCBC128Encrypt will create a random IV and prefix for the encrypted code.
aesCBC128Decrypt will use the IV prefix during decryption.

Inputs are data and key are data objects. If encoded form, such as Base64, if required, convert to and / or from the calling method.

The key must consist of 128-bit (16-byte), 192-bit (24 bytes) or 256-bit (32 bytes) in length. If a different key size is used, an error will be generated.

PKCS # 7 padding is installed by default.

This example requires Common Crypto. You must have a title header for the project:
#import <CommonCrypto/CommonCrypto.h>
Add Security.framework to the project.

This is an example, not a production code.

 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; } 

Usage example:

 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)") } 

Result:

 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> 
  

Notes:

One typical problem with sample code in CBC mode is that it leaves the user and sharing a random IV. This example includes creating an IV, prefixing the encrypted data, and using the IV prefix during decryption. This frees the casual user from the details that are necessary for CBC mode .

For security, encrypted data must also be authenticated; this sample code does not provide for being small and providing better compatibility for other platforms.

There is also no key output of the key from the password; it is proposed to use PBKDF2 , since text passwords are used as key material.

For a robust off-the-shelf multi-platform encryption code, see RNCryptor .

+16
source share

Swift 2.0 Encryption and decryption. Just update the answer above to support 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)") } } 
+9
source share

All Articles