OpenSSL AES_CBC-256 在 C++ 中解密没有原始文本长度
OpenSSL AES_CBC-256 decrypting without original text length in C++
我有在 SO 上找到的这段代码,它可以工作。我的问题是加密和解密在同一个文件中。自然地,我想把它们分成两个函数。问题是解码器需要原始输入长度。这不是安全漏洞吗?如何在不知道输入的原始长度的情况下解密?
/* computes the ciphertext from plaintext and key using AES256-CBC algorithm */
string cipher_AES(string key, string message)
{
size_t inputslength = message.length();
unsigned char aes_input[inputslength];
unsigned char aes_key[AES_KEYLENGTH];
memset(aes_input, 0, inputslength/8);
memset(aes_key, 0, AES_KEYLENGTH/8);
strcpy((char*) aes_input, message.c_str());
strcpy((char*) aes_key, key.c_str());
/* init vector */
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
// buffers for encryption and decryption
const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_out[encslength];
unsigned char dec_out[inputslength];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, AES_KEYLENGTH, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv, AES_ENCRYPT);
AES_set_decrypt_key(aes_key, AES_KEYLENGTH, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);
stringstream ss;
for(int i = 0; i < encslength; i++)
{
ss << enc_out[i];
}
return ss.str(););
}
首先,AES 加密以 128 位为单位进行 1 对 1 加密,因此您只需查看密文就可以知道 16 字节精度的消息大小。
然后,对于最后一个块,您只需确定消息的结束位置。标准解决方案是使用填充(例如 PKCS#7)。或者只在开头存储消息长度并与消息一起加密。
您当然可以继续使用 OpenSSL AES API 和 填充或您自己的一些其他机制。但是 OpenSSL 已经有了更高级别的 API (EVP),它会自动执行 AES、CBC 和 PKCS 填充。
有关使用 EVP API 的示例,请参阅 EVP Symmetric Encryption and Decryption 官方 OpenSSL wiki 页面。
不相关的注释:
固定 IV(尤其是零 IV)是不安全的。考虑生成随机 IV 并将其与密文存储在一起(例如使用 RAND_bytes)。
还检查 AES GCM 模式以进行身份验证加密(加密 + 安全校验和),这样加密的消息还可以防篡改。参见 this example。
我有在 SO 上找到的这段代码,它可以工作。我的问题是加密和解密在同一个文件中。自然地,我想把它们分成两个函数。问题是解码器需要原始输入长度。这不是安全漏洞吗?如何在不知道输入的原始长度的情况下解密?
/* computes the ciphertext from plaintext and key using AES256-CBC algorithm */
string cipher_AES(string key, string message)
{
size_t inputslength = message.length();
unsigned char aes_input[inputslength];
unsigned char aes_key[AES_KEYLENGTH];
memset(aes_input, 0, inputslength/8);
memset(aes_key, 0, AES_KEYLENGTH/8);
strcpy((char*) aes_input, message.c_str());
strcpy((char*) aes_key, key.c_str());
/* init vector */
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
// buffers for encryption and decryption
const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_out[encslength];
unsigned char dec_out[inputslength];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, AES_KEYLENGTH, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv, AES_ENCRYPT);
AES_set_decrypt_key(aes_key, AES_KEYLENGTH, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);
stringstream ss;
for(int i = 0; i < encslength; i++)
{
ss << enc_out[i];
}
return ss.str(););
}
首先,AES 加密以 128 位为单位进行 1 对 1 加密,因此您只需查看密文就可以知道 16 字节精度的消息大小。
然后,对于最后一个块,您只需确定消息的结束位置。标准解决方案是使用填充(例如 PKCS#7)。或者只在开头存储消息长度并与消息一起加密。
您当然可以继续使用 OpenSSL AES API 和
有关使用 EVP API 的示例,请参阅 EVP Symmetric Encryption and Decryption 官方 OpenSSL wiki 页面。
不相关的注释:
固定 IV(尤其是零 IV)是不安全的。考虑生成随机 IV 并将其与密文存储在一起(例如使用 RAND_bytes)。
还检查 AES GCM 模式以进行身份验证加密(加密 + 安全校验和),这样加密的消息还可以防篡改。参见 this example。