【发布时间】:2016-08-10 22:21:50
【问题描述】:
我对 OpenSSL AES 有疑问(我使用 aes.h):
获取二进制文件(.pdf、.jpg)或一些 .xml、.txt 大约 5000 个字符,然后我加密 base64。
-
当我尝试加密 AES 时,我得到了错误的大小(随机 400、200、50),我的 AESKey 是随机 128 位字符:[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-@#&*oeOE¯_]
我认为这个问题是 '\0' enrypted char 但我不知道我可以敲诈输入 (字符串可以保存带有 \0 元素的 char 数组,但 unsigned char* 和 char* 被中止)
这是我的代码:
std::string PFHelper::ASE_encode(std::string in, wchar_t* KS)
{
//const unsigned char* aes_input = reinterpret_cast<const unsigned char *> (in.c_str());
unsigned char* aes_input = new unsigned char[in.length()];
strcpy((char*)aes_input, in.c_str());
std::string KS_string = PFHelper::ConvertFromUtf8ToString(KS);
unsigned char* aes_key = new unsigned char[16];
strcpy((char*)aes_key, KS_string.c_str());
/* Input data to encrypt */
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
const size_t encslength = ((in.length() + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
/* Buffers for Encryption and Decryption */
unsigned char * enc_out = new unsigned char [encslength];
//unsigned char * dec_out = new unsigned char[in.length()];
memset(enc_out, 0, encslength);
//memset(dec_out, 0, in.length());
AES_KEY enc_key;
AES_set_encrypt_key(aes_key, 128, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, encslength, &enc_key, iv, AES_ENCRYPT);
//AES_KEY decrypt;
//memset(iv, 0x00, AES_BLOCK_SIZE);
//AES_cbc_encrypt((unsigned char*)enc_out, dec_out, encslength, &decrypt, iv, AES_DECRYPT);
//std::string returned = ConvertFromUnsignedCharToString(enc_out);
memset(aes_key, 0x00, 16);
memset(aes_input, 0x00, in.length());
return ConvertFromUnsignedCharToString(enc_out);
}
样本值:
KS (AESKey) : L"F-ZTNW meOJLK1s5"
in(5464chars) : PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVR.....
out(51chars) : "©¦ľ‘Ň·rnoŚ8nžęwřëůl2ěY ßJ2¨ßňO× ohX,Ž~ŚČ"E
我尝试了 EVP 和典型的字符键,问题是一样的
//set back to normal
unsigned char* aes_input = new unsigned char[in.length()];
strcpy((char*)aes_input, in.c_str());
unsigned char* dec_out = new unsigned char[in.length()];
memset(dec_out, 0, in.length());
dec_out[in.length()] = '\0';
/* A 256 bit key */
unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"01234567890123456";
int lenght;
int c_len = in.length() + AES_BLOCK_SIZE;
//Set up encryption
int f_len = 0;
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
{
wcout << L"1";
}
if (EVP_EncryptUpdate(ctx, dec_out, &lenght, aes_input, in.length()) != 1)
{
wcout << L"2";
}
if (EVP_EncryptFinal_ex(ctx, dec_out, &lenght) != 1)
{
wcout << L"3";
}
return ConvertFromUnsignedCharToString(dec_out);
}
【问题讨论】:
-
你应该不使用
AES_encrypt和朋友。这是一个纯软件实现,因此您不会享受硬件支持,如 AES-NI。您应该使用EVP_*函数。请参阅 OpenSSL wiki 上的 EVP Symmetric Encryption and Decryption。事实上,您可能应该使用经过身份验证的加密,因为它提供 机密性和真实性。请参阅 OpenSSL wiki 上的 EVP Authenticated Encryption and Decryption。 -
KS (AESKey) : L"F-ZTNW meOJLK1s5"- Windows 使用 UTF-16,Linux 使用 UTF-32。这意味着你一半的密钥位在 Windows 上是 0(实际上是 64 位密钥),而四分之三的密钥位在 Linux 上是 0(实际上是 32 位密钥)。您需要使用 HKDF 之类的东西来消化您的密钥字符串以提取熵,然后键入密码。否则,就会有不小的威胁,因为坏人可以暴力破解密钥。