Search code examples
c++objective-cencryptioncrypto++commoncrypto

Different results when encrypting with Common Crypto and Crypto++ with AES


I get different results when encrypting the same file (binary data) with the same key with Apple's Common Crypto and Crypto++. The algorithm I'm using is AES.

Here's the code in Objective C using Common Crypto:

void FileUtil::writeToFileEncrypt(string fileName, const void *data, int size, string key, int *sizeOut)
{
    int numBytesEncrypted = 0;
    char keyPtr[kCCKeySizeAES256+1];

    if (key.length() > 32)
    {
        key = key.substr(0, 32);
    }

    memcpy(keyPtr, key.c_str(), sizeof(keyPtr));

    if (key.length() < 32)
    {
        for (int i = key.length(); i < 32; i++)
        {
            keyPtr[i] = '0';
        }
    }

    size_t bufferSize = size + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                      keyPtr, kCCKeySizeAES256,
                                      NULL /* initialization vector (optional) */,
                                      data, size, /* input */
                                      buffer, bufferSize, /* output */
                                      &numBytesEncrypted);

    if (cryptStatus == kCCSuccess) {
        cout << "encrypt success" << endl;
    }

    ofstream myfile;
    myfile.open (fileName.c_str(), ios::out | ios::binary);
    myfile.write((const char *)buffer, numBytesEncrypted);
    myfile.close();

    free(buffer);

    *sizeOut = numBytesEncrypted;
}

Here's the code in C++ using Crypto++

void EncryptUtils::encrypt(string fileName, unsigned char *chars, string key, int *length, int dataLength)
{
    unsigned char *iv = (unsigned char *)"0000000000000000";

    char keyPtr[32 + 1];

    if (key.length() > 32)
    {
        key = key.substr(0, 32);
    }

    memcpy(keyPtr, key.c_str(), sizeof(keyPtr));

    if (key.length() < 32)
    {
        for (int i = key.length(); i < 32; i++)
        {
            keyPtr[i] = '0';
        }
    }
    keyPtr[32] = '\0';

    CryptoPP::AES::Encryption aesEncryption((unsigned char *)keyPtr, 32);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);

    int newBufSize = (sizeof(unsigned char *) * dataLength) + 32;
    unsigned char *newBuf = (unsigned char *)malloc(newBufSize);
    CryptoPP::ArraySink *arraySink = new CryptoPP::ArraySink(newBuf, newBufSize);

    CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, arraySink, CryptoPP::StreamTransformationFilter::PKCS_PADDING);
    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(chars), (unsigned int)dataLength);
    stfEncryptor.MessageEnd();

    *length = arraySink->TotalPutLength();

    ofstream myfile;
    myfile.open (fileName.c_str(), ios::out | ios::binary);
    myfile.write((const char *)newBuf, *length);
    myfile.close();
}

I need to get both of them to produce the same results. Is there something I overlooked?


Solution

    1. The "Objective-C" version is not written in Objective-C, it is in C++. the actual encryption used CCCrypt which is plain "C".

    2. The "Objective-C" version has no iv supplied so it defaults to all zeros. The C++ version supplies an iv of ASCII "0" characters, that is not the same as all zero data.This is probably the error.

    3. Provide input and output hex data dumps for each including key, iv, data in and data out immediately prior to and after the encryption calls.