Различные результаты при шифровании с помощью Common Crypto и Crypto ++ с 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;
}

Вот код на C ++ с использованием 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();
}

Мне нужно, чтобы они оба дали одинаковые результаты. Есть что-то, что я упустил?

2

Решение

  1. Версия «Objective-C» написана не на Objective-C, а на C ++. фактическое используемое шифрование CCCrypt который просто «С».

  2. Версия «Objective-C» не имеет iv поставляется по умолчанию со всеми нулями. Версия C ++ предоставляет iv ASCII «0» символов, это не то же самое, что все нулевые данные. Вероятно, это ошибка.

  3. Предоставьте входные и выходные шестнадцатеричные дампы данных для каждого, включая ключ, iv, данные в и данные непосредственно до и после вызовов шифрования.

1

Другие решения

Это не верно:

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, чтобы переварить пароль в подходящий ключ.

——

Обычный код Crypto не имеет IV и может не использовать тот же отступ, что и в примере Crypto ++.

——

Использование AES представляется неправильным. Похоже, что вы работаете с шифром в режиме ECB, поэтому он обеспечивает конфиденциальность если данные меньше размера блока. Он подлежит переупорядочению и манипулированию, поэтому не обеспечивает гарантий подлинности. Вы должны использовать Аутентифицированное шифрование лайк EAX, GCM или же CCM Режим.

Поскольку Common Crypto не работает (он не обеспечивает аутентифицированные режимы шифрования), а Crypto ++ предоставляет все, что вам нужно (и он работает практически везде), вы должны использовать Crypto ++ и аутентифицированный режим шифрования.

0