我正在使用AES CBC和openssl进行一些工作,现在,我遇到了一个问题,我无法猜出是什么问题(一如既往)。
如果消息长度小于16个字节,则加密和解密过程正常,但当消息大于16个字节时,解密只能在第16个第一个字节上起作用。
当我呼叫aes.exe stackoverflow stackoverflow
时,输出为:
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Encrypted = |6c65219594c0dae778f9b5e84f018db6|
Encrypting : stackoverflow
With Key : stackoverflow
Becomes : ??????¤le!òö++þx¨ÁÞO?ìÂ.
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Decrypted = |737461636b6f766572666c6f77|
Decrypting : ??????¤le!òö++þx¨ÁÞO?ìÂ
With Key : stackoverflow
Becomes : stackoverflow
当我呼叫aes.exe stackoverflowstackoverflow stackoverflow
时,输出为:
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Encrypted = |46172e3f7fabdcfc6c8b3e65aef175cddf8164236faf706112c15f5e765e49a5|
Encrypting : stackoverflowstackoverflow
With Key : stackoverflow
Becomes : ??????¤F?.?¦½_³lï>e«±u-¯üd#o»pa?-_^v^IÑ.
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Decrypted = |737461636b6f766572666c6f77737461257d434a1edcbc970bf5346ea2fc7bc2|
Decrypting : ??????¤F?.?¦½_³lï>e«±u-¯üd#o»pa?-_^v^IÑ
With Key : stackoverflow
Becomes : stackoverflowsta%}CJ?_+ù?§4nó³{-.
我为每个加密/解密调用提供一个随机IV,并在两种情况下将密码标准化为32字节;我错过了什么?有谁知道?
源代码:
#include <vector>
#include <string>
#include <iostream>
// Make a Key of exactly 32 bytes, truncates or adds values if it's necessary
std::string AES_NormalizeKey(const void *const apBuffer, size_t aSize)
{
static const unsigned char key32[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
const char *const Buffer = reinterpret_cast<const char *>(apBuffer);
std::string Result(reinterpret_cast<const char *>(key32), 32);
std::copy(Buffer, Buffer + ((aSize < 32)? aSize: 32), Result.begin());
return Result;
}
// Encrypt using AES cbc
std::string AESEncrypt(const void *const apBuffer, size_t aBufferSize, const void *const apKey, size_t aKeySize, std::string &aIVector)
{
// Create IVector.
unsigned char AES_IVector[16] = {0};
std::srand(static_cast<int>(time(NULL)));
std::generate(std::begin(AES_IVector), std::end(AES_IVector), std::rand);
std::copy(std::begin(AES_IVector), std::end(AES_IVector), aIVector.begin());
// Create key.
const std::string Key(AES_NormalizeKey(apKey, aKeySize));
AES_KEY EncryptKey;
AES_set_encrypt_key(reinterpret_cast<const unsigned char *>(Key.c_str()), 256, &EncryptKey);
// Encrypt.
unsigned char AES_Encrypted[1024] = {0};
AES_cbc_encrypt(static_cast<const unsigned char *>(apBuffer), AES_Encrypted, aBufferSize, &EncryptKey, AES_IVector, AES_ENCRYPT);
const std::string Encrypted(reinterpret_cast<const char *>(AES_Encrypted), ((aBufferSize / 16) + 1) * 16);
// Finish.
return Encrypted;
};
// Decrypt using AES cbc
std::string AESDecrypt(const void *const apBuffer, size_t aBufferSize, const void *const apKey, size_t aKeySize, std::string &aIVector)
{
// Read IVector.
unsigned char AES_IVector[16] = {0};
std::copy(aIVector.begin(), aIVector.end(), std::begin(AES_IVector));
// Create Key.
const std::string Key(AES_NormalizeKey(apKey, aKeySize));
AES_KEY DecryptKey;
AES_set_decrypt_key(reinterpret_cast<const unsigned char *>(Key.c_str()), 256, &DecryptKey);
// Decrypt.
unsigned char AES_Decrypted[1024] = {0};
AES_cbc_encrypt(static_cast<const unsigned char *>(apBuffer), AES_Decrypted, aBufferSize, &DecryptKey, AES_IVector, AES_DECRYPT);
const std::string Decrypted(reinterpret_cast<const char *>(AES_Decrypted));
// Finish.
return Decrypted;
};
// Entry point
int main(unsigned int argc, char **argv)
{
typedef std::vector<const std::string> vs;
vs a;
for (vs::size_type Index = 0; Index < argc; ++Index)
{
a.push_back(argv[Index]);
}
if (a.size() == 3)
{
std::string IV("");
std::string e(AESEncrypt(a.at(1).c_str(), a.at(1).size(), a.at(2).c_str(), a.at(2).size()), IV);
std::cout << "Encrypting : " << a.at(1) << "\n"
<< "With Key : " << a.at(2) << "\n"
<< "Becomes : " << e << ".\n";
std::string d(AESDecrypt(e.c_str(), e.size(), a.at(2).c_str(), a.at(2).size()), IV);
std::cout << "Decrypting : " << e << "\n"
<< "With Key : " << a.at(2) << "\n"
<< "Becomes : " << d << ".\n";
}
return 0;
}
答案 0 :(得分:5)
你的代码几乎是正确的,除了由于内存损坏而覆盖了初始化向量,密文的长度被错误地舍入,并且应该使用std :: string :: data()而不是std :: string当使用std :: string作为字节数组时,:: c_str()。初始化向量被复制到覆盖堆栈的空字符串中。然后覆盖初始化向量,因此AESDecrypt使用不同的值。我已经包含了包含个人建议的源代码并修复了这些问题。当使用
aes "Hello World!" stackoverflow运行时,它会产生以下输出:
(Normalized key: 737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f) Encrypting : Hello World! With Key : stackoverflow Init Vec : d8b1657d9e2317c93430994f59bb54eb Becomes : ��Йw�H���}�;E (Normalized key: 737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f) Decrypting : ��Йw�H���}�;E With Key : stackoverflow Init Vec : d8b1657d9e2317c93430994f59bb54eb Becomes : Hello World!
#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <initializer_list>
#include <openssl/aes.h>
typedef unsigned char byte;
template <size_t multiple> size_t round_up(const size_t len)
{
if (len % multiple == 0) return len;
else return ((len / multiple) + 1) * multiple;
}
std::ostream &print_buffer_as_hex(std::ostream &o, const unsigned char *buf, size_t size)
{
o << std::hex << std::setfill('0');
for( size_t i = 0; i < size; ++i )
{
o << std::setw(2) << static_cast<unsigned int>(buf[i]);
}
return o << std::dec;
}
inline std::ostream &operator<<(std::ostream &o, const std::vector<byte> &buf)
{
return print_buffer_as_hex(o, reinterpret_cast<const unsigned char*>(&buf[0]), buf.size());
}
// Make a Key of exactly 32 bytes, truncates or adds values if it's necessary
std::string AES_NormalizeKey(const void *const apBuffer, size_t aSize)
{
static const unsigned char key32[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
const char *const Buffer = reinterpret_cast<const char *>(apBuffer);
std::string Result(reinterpret_cast<const char *>(key32), 32);
std::copy(Buffer, Buffer + ((aSize < 32)? aSize: 32), Result.begin());
return Result;
}
// Encrypt using AES cbc
std::string AESEncrypt(const void *const apBuffer, size_t aBufferSize, const void *const apKey, size_t aKeySize, std::vector<byte> &aIVector)
{
// Create IVector.
unsigned char AES_IVector[AES_BLOCK_SIZE] = {0};
std::srand(static_cast<int>(time(NULL)));
std::generate(std::begin(AES_IVector), std::end(AES_IVector), std::rand);
aIVector.resize(sizeof(AES_IVector));
std::copy(std::begin(AES_IVector), std::end(AES_IVector), aIVector.begin());
// Create key.
const std::string Key(AES_NormalizeKey(apKey, aKeySize));
std::cout << "(Normalized key: ";
print_buffer_as_hex(std::cout, (const unsigned char*)Key.data(), Key.size()) << ")\n";
AES_KEY EncryptKey;
AES_set_encrypt_key(reinterpret_cast<const unsigned char *>(Key.data()), 256, &EncryptKey);
// Encrypt.
unsigned char AES_Encrypted[1024] = {0};
AES_cbc_encrypt(static_cast<const unsigned char *>(apBuffer), AES_Encrypted, aBufferSize, &EncryptKey, AES_IVector, AES_ENCRYPT);
const std::string Encrypted(reinterpret_cast<const char *>(AES_Encrypted), round_up<AES_BLOCK_SIZE>(aBufferSize));
// Finish.
return Encrypted;
};
// Decrypt using AES cbc
std::string AESDecrypt(const void *const apBuffer, size_t aBufferSize, const void *const apKey, size_t aKeySize, std::vector<byte> &aIVector)
{
// Read IVector.
unsigned char AES_IVector[AES_BLOCK_SIZE] = {0};
std::copy(aIVector.begin(), aIVector.end(), std::begin(AES_IVector));
// Create Key.
const std::string Key(AES_NormalizeKey(apKey, aKeySize));
std::cout << "(Normalized key: ";
print_buffer_as_hex(std::cout, (const unsigned char*)Key.data(), Key.size()) << ")\n";
AES_KEY DecryptKey;
AES_set_decrypt_key(reinterpret_cast<const unsigned char *>(Key.data()), 256, &DecryptKey);
// Decrypt.
unsigned char AES_Decrypted[1024] = {0};
AES_cbc_encrypt(static_cast<const unsigned char *>(apBuffer), AES_Decrypted, aBufferSize, &DecryptKey, AES_IVector, AES_DECRYPT);
const std::string Decrypted(reinterpret_cast<const char *>(AES_Decrypted));
// Finish.
return Decrypted;
};
// Entry point
int main(int argc, char **argv)
{
typedef std::vector<std::string> vs;
vs a;
for (vs::size_type Index = 0; Index < static_cast<unsigned>(argc); ++Index)
{
a.push_back(argv[Index]);
}
if (a.size() == 3)
{
std::vector<byte> IV;
std::string e(AESEncrypt(a.at(1).data(), a.at(1).size(), a.at(2).data(), a.at(2).size(), IV));
std::cout << "Encrypting : " << a.at(1) << "\n"
<< "With Key : " << a.at(2) << "\n"
<< "Init Vec : " << IV << "\n"
<< "Becomes : " << e << "\n";
std::string d(AESDecrypt(e.data(), e.size(), a.at(2).data(), a.at(2).size(), IV));
std::cout << "Decrypting : " << e << "\n"
<< "With Key : " << a.at(2) << "\n"
<< "Init Vec : " << IV << "\n"
<< "Becomes : " << d << "\n";
}
std::cout.flush();
return 0;
}
答案 1 :(得分:0)
我没有具体的答案,但这里有一个不适合评论的提示。加密和解密需要相同的密钥和IV才能工作。加密函数的输出必须进入解密函数的输入。
因此,要调试您的问题,您需要打印输入加密功能并打印其输出。然后,您需要将输入数据打印到decrypt函数并打印其输出。纯文本是一种不好的方法,因为你无法看到字节到底是什么。因此,将键,IV和数据打印为十六进制值。
#include <iostream>
#include <iomanip>
...
std::ostream &print_buffer_as_hex(std::ostream &o, const unsigned char *buf, size_t size)
{
for( int i = 0; i < size; ++i )
{
o << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(buf[i]) << std::dec;
}
o << "\n";
return o;
}
这样称呼:
print_buffer_as_hex(std::cout, reinterpret_cast<const char *>(AES_Encrypted), ((aBufferSize / 16) + 1) * 16);
我使用std::vector<unsigned char>
代替std::string
来保存任意字节。使用构造函数或resize()
方法设置所需的空间量(resize(),而不是reserve()!)。如果您调用想要unsigned char *
的API函数,只需传递&vec[0]
,其中vec是您的矢量对象。你的代码看起来会更清晰。
如,
std::vector<unsigned char> iv(16);
std::srand(static_cast<int>(time(NULL)));
std::generate(iv.begin(), iv.end(), std::rand);
print_buffer_as_hex(std::cout, &iv[0], iv.size());