使用AES加密Common Crypto和Crypto ++时的结果不同

时间:2015-01-30 09:41:17

标签: c++ objective-c encryption crypto++ commoncrypto

使用Apple的Common Crypto和Crypto ++使用相同的密钥加密相同的文件(二进制数据)时会得到不同的结果。我正在使用的算法是AES。

以下是使用Common Crypto的Objective C中的代码:

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

这是使用Crypto ++的C ++代码

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

我需要让他们两个产生相同的结果。有没有我忽略的东西?

2 个答案:

答案 0 :(得分:1)

  1. &#34; Objective-C&#34; version不是用Objective-C编写的,而是用C ++编写的。使用的实际加密CCCrypt是简单的&#34; C&#34;。

  2. &#34; Objective-C&#34;版本没有提供iv因此默认为全零。 C ++版本提供iv ASCII&#34; 0&#34;字符,与所有零数据不同。这可能是错误。

  3. 在加密呼叫之前和之后,为每个包括密钥,iv,数据输入和数据输出提供输入和输出十六进制数据转储。

答案 1 :(得分:0)

这是错误的:

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

尝试复制33个字节。我认为你需要这样的东西:

size_t ksize = std::min(sizeof(keyPtr), key.size());
assert(ksize == 16 || ksize == 24 || ksize == 32);

-----

一般来说,设计是错误的:

keyPtr[32] = '\0';

键是二进制的,而不是ASCII字符串。如果您使用密码,那么它仍然是错误的,因为您应该使用KDF将密码消化为合适的密钥。

-----

常见的加密代码缺少IV,可能不会使用与Crypto ++示例相同的填充。

-----

使用AES似乎是错误的。您似乎正在ECB模式下操作密码,因此它仅提供机密性 如果 数据小于块大小。它受到重新排序和操纵,因此不提供真实性保证。您应该使用Authenticated EncryptionEAXGCM模式{/ 3}}。

由于Common Crypto很蹩脚(它不提供经过身份验证的加密模式)而且Crypto ++提供了您需要的一切(并且它几乎无处不在),您应该使用Crypto ++和经过身份验证的加密模式。