swiftencryptionopensslaescommoncrypto

CommonCrypto in iOS producing different results to openssl command line


I'm using CommonCrypto in my app to decrypt some data encrypted using openssl. In order to test the encryption, I've tried to encrypt some sample data and its quite surprise that the outputs of my encryption (which is aes ecb) are different from what is generated by using openssl command.

I've also given some tries with other framework like CryptoSwift, but the results are the same.

Heres the code I use to encrypt:

class AESEncryptor {

    static func encrypt(text: String, key: String) -> String? {

        guard let encryptingData = text.data(using: .utf8), let keyData = key.data(using: .utf8) else {
            return nil
        }

        var outLength = Int(0)
        var outBytes = [UInt8](repeating: 0, count: encryptingData.count + kCCBlockSizeAES128)
        var status: CCCryptorStatus = CCCryptorStatus(kCCSuccess)
        encryptingData.withUnsafeBytes { (encryptingBytes: UnsafePointer<UInt8>!) -> () in
            keyData.withUnsafeBytes { (keyBytes: UnsafePointer<UInt8>!) -> () in
                status = CCCrypt(CCOperation(kCCEncrypt),
                                 CCAlgorithm(kCCAlgorithmAES),            // algorithm
                    CCOptions(kCCOptionECBMode | kCCOptionPKCS7Padding),           // options
                    keyBytes,                                   // key
                    keyData.count,                                  // keylength
                    nil, //ivBytes,                                    // iv
                    encryptingBytes,                             // dataIn
                    encryptingData.count,                                // dataInLength
                    &outBytes,                                  // dataOut
                    outBytes.count,                             // dataOutAvailable
                    &outLength)                                 // dataOutMoved
            }
        }
        guard status == kCCSuccess else {
            return nil
        }

        let encryptedData =  Data(bytes: UnsafePointer<UInt8>(outBytes), count: outLength)
        return encryptedData.base64EncodedString()

    }
}

Calling the above function:

let key = "4f0fbad47141ef9616ce4d71b459eea9"
let plain = "ThisIsASuperSecurePassword"
let digest = AESEncryptor.encrypt(text: plain, key: key)

the digest is "4ebhUO+Rma34MR4iBTT04AS6rXX+Jy2U97rwC2HGmz0="

Meanwhile, openssl command line, with same input:

echo -n "ThisIsASuperSecurePassword" | openssl enc -e -aes-128-ecb -K "3466306662616434373134316566393631366365346437316234353965656139" -a

("3466306662616434373134316566393631366365346437316234353965656139" is the hex string of "4f0fbad47141ef9616ce4d71b459eea9")

gives me "zPO4jNrMbbZp4WXNPgkX1RuBIpNXZqe0XNqNMFPTt/Q="

So, my question is: why they are not the same? How can I get the same outputs?

AD


Solution

  • First problem is that you didn't encode with AES-128-EBC, you actually encoded with AES-256-EBC. With is because your key length is 256 bits, not 128 bits.

    So if we encode using openssl with the correct key length I get:

    (Note I'm using powershell and for some reason piping text to a command will add a CRLF so I to it via a file)

    "ThisIsASuperSecurePassword" | Set-Content -NoNewLine plaintext.txt
    openssl enc -e -aes-256-ecb -K 3466306662616434373134316566393631366365346437316234353965656139 -a -in plaintext.txt
    

    I get:

    4ebhUO+Rma34MR4iBTT04AS6rXX+Jy2U97rwC2HGmz0=

    Which is the same as what you get.

    And decrypting the output produces the plaintext again:

    "4ebhUO+Rma34MR4iBTT04AS6rXX+Jy2U97rwC2HGmz0=" | openssl enc -d -aes-256-ecb -K 3466306662616434373134316566393631366365346437316234353965656139 -a -p
    

    produces the output:

    ThisIsASuperSecurePassword

    If you actually wanted AES-128 you will need to reduce your key size to 128 bits in length.