使用 AES 使用 Common Crypto 和 Crypto++ 加密时的不同结果
Different results when encrypting with Common Crypto and Crypto++ with AES
使用 Apple 的 Common Crypto 和 Crypto++ 使用相同的密钥加密相同的文件(二进制数据)时,我得到了不同的结果。我使用的算法是 AES。
这是 Objective C 中使用 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;
}
这是使用 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] = '[=11=]';
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();
}
我需要让它们都产生相同的结果。有什么我忽略的吗?
"Objective-C"版本不是用Objective-C写的,是用C++写的。实际使用的加密 CCCrypt
是普通的 "C".
"Objective-C" 版本未提供 iv
,因此默认为全零。 C++ 版本提供 iv
个 ASCII“0”字符,这与全零不同 data.This 可能是错误。
在加密调用之前和之后立即为每个包括密钥、iv、数据输入和数据输出提供输入和输出十六进制数据转储。
这是错误的:
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] = '[=12=]';
密钥是二进制的,而不是 ASCII 字符串。如果您使用密码,那么它仍然是错误的,因为您应该使用 KDF 将密码消化成合适的密钥。
-----
常见的 Crypto 代码缺少 IV,可能不会使用与 Crypto++ 示例相同的填充。
-----
AES 的使用似乎有误。看来您是在 ECB 模式下运行密码,因此它仅提供机密性 如果 数据小于块大小。它可能会被重新排序和操纵,因此不提供真实性保证。您应该使用 Authenticated Encryption like EAX, GCM or CCM 模式。
由于 Common Crypto 很差劲(它不提供经过身份验证的加密模式)而 Crypto++ 提供了您需要的一切(并且它几乎无处不在),您应该使用 Crypto++ 和经过身份验证的加密模式。
使用 Apple 的 Common Crypto 和 Crypto++ 使用相同的密钥加密相同的文件(二进制数据)时,我得到了不同的结果。我使用的算法是 AES。
这是 Objective C 中使用 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;
}
这是使用 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] = '[=11=]';
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();
}
我需要让它们都产生相同的结果。有什么我忽略的吗?
"Objective-C"版本不是用Objective-C写的,是用C++写的。实际使用的加密
CCCrypt
是普通的 "C"."Objective-C" 版本未提供
iv
,因此默认为全零。 C++ 版本提供iv
个 ASCII“0”字符,这与全零不同 data.This 可能是错误。在加密调用之前和之后立即为每个包括密钥、iv、数据输入和数据输出提供输入和输出十六进制数据转储。
这是错误的:
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] = '[=12=]';
密钥是二进制的,而不是 ASCII 字符串。如果您使用密码,那么它仍然是错误的,因为您应该使用 KDF 将密码消化成合适的密钥。
-----
常见的 Crypto 代码缺少 IV,可能不会使用与 Crypto++ 示例相同的填充。
-----
AES 的使用似乎有误。看来您是在 ECB 模式下运行密码,因此它仅提供机密性 如果 数据小于块大小。它可能会被重新排序和操纵,因此不提供真实性保证。您应该使用 Authenticated Encryption like EAX, GCM or CCM 模式。
由于 Common Crypto 很差劲(它不提供经过身份验证的加密模式)而 Crypto++ 提供了您需要的一切(并且它几乎无处不在),您应该使用 Crypto++ 和经过身份验证的加密模式。