Issue using CCCrypt (CommonCrypt) in Swift

cccrypt swift 5
kccoptionpkcs7padding
cryptoswift swift 4 example
aes encryption swift 4
aescrypt swift
aes decryption in swift 4
aes/cbc/pkcs5padding swift
swift encryption

I am porting a working Objective-C Category (NSData+AESCrypt.m) to Swift and I have found an issue working with the pointers. The code for the encrypting part in Swift compiles correctly, but generates a runtime EXEC_BAD_ACCES error.

The code I have so far is (I tried to dissect 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 shows the following info:

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

But the encryptedString shows 0x0000000000 in the debugger, and trying to println() it generates the EXEC_BAD_ACCESS error

Any idea what is missing?

Rgds....

Swift 2.0

Here is an example If this is not exactly what is needed the 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 bridging 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

The iv is prefixed to the encrypted data

aesCBC128Encrypt will create a random IV and prefixed to the encrypted code. aesCBC128Decrypt will use the prefixed IV during decryption.

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

The key should be exactly 128-bits (16-bytes), 192-bits (24-bytes) or 256-bits (32-bytes) in length. If another key size is used an error will be thrown.

PKCS#7 padding is set by default.

This example requires Common Crypto It is necessary to have a bridging header to the project: #import <CommonCrypto/CommonCrypto.h> Add the Security.framework to the project.

This is example, not 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;
}

Example usage:

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

Example Output:

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 CBC mode example code is that it leaves the creation and sharing of the random IV to the user. This example includes generation of the IV, prefixed the encrypted data and uses the prefixed IV during decryption. This frees the casual user from the details that are necessary for CBC mode.

For security the encrypted data also should have authentication, this example code does not provide that in order to be small and allow better interoperability for other platforms.

Also missing is key derivation of the key from a password, it is suggested that PBKDF2 be used is text passwords are used as keying material.

For robust production ready multi-platform encryption code see RNCryptor.

What is replacement of CommonCrypt…, to use AES 128 encryption for a app but Common Cryptor is not avilable in Swift. IMO the best way to resolve this issue is to write a small C (or Objective-C ) + kCCBlockSizeAES128]; err = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, � I'm trying to use this answer here: Issue using CCCrypt (CommonCrypt) in Swift. But am a) unsure if I'm properly converting the string to data and b) how to get the IV (initialization vector) from the string I receive.

Swift 2.0 Encryption and Decryption. Just updated the above answer 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)")
        }
    }

AES 256 in swift 4 with CommonCrypto � GitHub, AES 256 in swift 4 with CommonCrypto #import <CommonCrypto/ CommonCrypto.h>. SHA256.swift status = CCCrypt(operation,. Issue using CCCrypt (CommonCrypt) in Swift. Related. 981. How to change the name of an iOS app? 388. Java 256-bit AES Password-Based Encryption. 1. OpenSSL: bad

zaph adopted to modern swift (yet another deprecation of yet another swift api causes yet another set of warnings noone really cares about even though they should)

extension Data
{
    func aes256CBCEncrypt(keyData: Data) -> Data? {
        let keyLength = keyData.count
        if keyData.count != kCCKeySizeAES256 {
            return nil
        }
        let data = self;
        let ivSize = kCCBlockSizeAES128;
        let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
        var cryptData = Data(count:cryptLength)

        let status: Int32 = cryptData.withUnsafeMutableBytes {
            guard let ivBytes = $0.baseAddress else {
                return 0
            }
            return SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
        }
        if (status != 0) {
// who cares, really?            return nil 
        }

        var numBytesEncrypted :size_t = 0
        let options   = CCOptions(kCCOptionPKCS7Padding)

        let cryptStatus: CCCryptorStatus = cryptData.withUnsafeMutableBytes {
            guard let cryptBytes = $0.baseAddress else {
                return CCCryptorStatus(kCCMemoryFailure) // sadly kCCMoronSwiftLanguageSpecDeveloperDetected does not exist
            }
            let cryptStatus: CCCryptorStatus = data.withUnsafeBytes {
                guard let dataBytes = $0.baseAddress else {
                    return CCCryptorStatus(kCCMemoryFailure)
                }
                return keyData.withUnsafeBytes {
                    guard let keyBytes = $0.baseAddress else {
                        return CCCryptorStatus(kCCMemoryFailure)
                    }
                    return CCCrypt(CCOperation(kCCEncrypt),
                            CCAlgorithm(kCCAlgorithmAES),
                            options,
                            keyBytes, keyLength,
                            cryptBytes,
                            dataBytes, data.count,
                            cryptBytes+kCCBlockSizeAES128, cryptLength,
                            &numBytesEncrypted)
                }
            }
            return cryptStatus
        }

        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData.count = numBytesEncrypted + ivSize
        }
        else {
            return nil
        }
        return cryptData;
    }
}

Encrypted string changing every time iOS Swift 4.2 version � Issue , String) -> String{ //help from this thread //http://stackoverflow.com/questions/ 25754147/issue-using-cccrypt-commoncrypt-in-swift let keyString� Issue using CCCrypt (CommonCrypt) in Swift. 1. Compatible AES encryption between Swift on iOS and Python. Related. 1128. Shortcuts in Objective-C to concatenate

Issue decrypting with CommonCrypto in Swift, Issue decrypting with CommonCrypto in Swift. aes decryption in swift 4 cryptoswift swift 4 example cccrypt swift decrypt data in swift rncryptor swift example Common Crypto is still the recommended way to do low-level crypto operations, like AES. Alas, as you’ve noted, it’s not easy to access from Swift. IMO the best way to resolve this issue is to write a small C (or Objective-C) wrapper around the Common Crypto operations you need and then have your Swift code call those.

Issue decrypting with CommonCrypto in Swift, AES 256 in swift 4 with CommonCrypto � GitHub, it appears that IV should be hardcoded or saved Issue using CCCrypt (CommonCrypt) in Swift, Swift 2.0. Issue using CCCrypt (CommonCrypt) in Swift Tags ajax android angular api button c++ class database date dynamic exception file function html http image input java javascript jquery json laravel list mysql object oop ph php phplaravel phpmysql phpphp post python sed select spring sql string text time url view windows wordpress xml

Resurrecting CommonCrypto in Swift for hashing, encrypting and , The inability to simply import CommonCrypto into a Swift file has been .com/ questions/25754147/issue-using-cccrypt-commoncrypt-in-swift I know this is an old question. But I figure out an alternative way to use the library in Swift project, which might be helpful for those who don't want to import framework introduced in these answers. In Swift project, create a Objective-C bridging header, create NSData category (or custom class that to use the library) in Objective-C.

Comments
  • There are a few problems here. 1. The key length is incorrect. 2. The output is not being resized to numBytesEncrypted. 3. A UTF-8 String can not be created fom arbitrary data, that is not all data can form a UTF-8 string.
  • From a security standpoint t, and the assumption security is the desired result, using a String as a key is also a poor idea, if a String is used it should be used to derive a key with PBKFD2. Lastly: Do not use ECB mode, it is insecure, see ECB mode, scroll down to the Penguin. Instead use CBC mode with a random IV, just prefix the encrypted data with the IV for use in decryption, it does not need to not secret.
  • Thx Zaph. This works perfectly. I have one more question with regards the decrypt process. I used your code as reference, but something seems to be missing. I noted that after converting the NSMutableData object (crypData) to String using, cryptData.base64EncodedStringWithOptions, the resulting String, if converted back to NSData using string.dataUsingEncoding(NSDatabase64EncodingOptions) gives something different than cryptData.
  • If is a small thing ask here, it it involves code create a new question.
  • Sorry, I hit the enter key, so I had to go to comment edit mode.... I will elaborate on the issue in a new question
  • This really should be a new question. 1: AES is block based so padding is needed unless the data will always be a multiple of the block size (16-bytes for AES). 2: Note that CBC mode is the default so to remove all modes and padding you would need to pass kCCOptionECBMode which is just base encryption, if you want to add no options which would mean CBC mode and no padding use 0. 3: An iv is used for CBC mode, ECB mode does not require an iv but is nor very secure. Create an iv the same way keyData or data is created and in the CCCrypt call use ivData.bytes.
  • For CBC mode an iv is required, see Cipher Block Chaining. The CCCrypt method will supply an default: "If CBC mode is selected (by the absence of any mode bits in the options flags) and no IV is present, a NULL (all zeroes) IV will be used." But for security a random iv should be provided, the usual convention is to prepend the iv to the encrypted data so it will be available for decryption.eroes.