来自 OpenSSL 的 AES-256 每次都会产生不同的密文
AES-256 from OpenSSL produces a different ciphertext each time
代码如下:
#include <QCoreApplication>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <iostream>
void en_de_crypt(int should_encrypt, FILE *ifp, FILE *ofp, unsigned char *ckey, unsigned char *ivec) {
const unsigned BUFSIZE=4096;
unsigned char *read_buf = (unsigned char*)malloc(BUFSIZE);
unsigned char *cipher_buf;
unsigned blocksize;
int out_len;
EVP_CIPHER_CTX ctx;
for(int i=0; i<8;i++)
{
printf("%c\n",ckey[i]);
}
printf("\n\n");
for(int i=0; i<8;i++)
{
printf("%c\n",ivec[i]);
}
EVP_CipherInit(&ctx, EVP_aes_256_cbc(), ckey, ivec, should_encrypt);
blocksize = EVP_CIPHER_CTX_block_size(&ctx);
cipher_buf = (unsigned char *)malloc(BUFSIZE + blocksize);
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
int numRead = fread(read_buf, sizeof(unsigned char), BUFSIZE, ifp);
EVP_CipherUpdate(&ctx, cipher_buf, &out_len, read_buf, numRead);
fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
if (numRead < BUFSIZE) { // EOF
break;
}
}
// Now cipher the final block and write it out.
EVP_CipherFinal(&ctx, cipher_buf, &out_len);
fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
// Free memory
free(cipher_buf);
free(read_buf);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::string pathToFiles = "C:/Temp/testEnc/dqdokoleda.7z";
unsigned char ckey[8];
unsigned char ivec[8];
ckey[0] = 'p';
ckey[1] = 'a';
ckey[2] = 's';
ckey[3] = 's';
ckey[4] = 'w';
ckey[5] = 'o';
ckey[6] = 'r';
ckey[7] = 'd';
ivec[0] = 'a';
ivec[1] = 'c';
ivec[2] = 'g';
ivec[3] = 't';
ivec[4] = 'i';
ivec[5] = 'j';
ivec[6] = 'o';
ivec[7] = 'r';
FILE *fIN, *fOUT;
// First encrypt the file
fIN = fopen((pathToFiles).c_str(), "rb"); //File to be encrypted; plain text
fOUT = fopen((pathToFiles+".enc").c_str(), "wb"); //File to be written; cipher text
en_de_crypt(1, fIN, fOUT, ckey, ivec);
fclose(fIN);
fclose(fOUT);
//Decrypt file now
fIN = fopen((pathToFiles+".enc").c_str(), "rb"); //File to be read; cipher text
fOUT = fopen((pathToFiles+".decrypted").c_str(), "wb"); //File to be written; cipher text
en_de_crypt(0, fIN, fOUT, ckey, ivec);
fclose(fIN);
fclose(fOUT);
std::cout << "END" << std::endl;
return a.exec();
}
问题是我注释解密部分的时候,每次.enc文件的内容都不一样。然后,如果我尝试分别解密代码的取消注释解密和注释加密部分,则文件未正确解密(7zip 表示无法打开它)。如果我不注释代码的任何部分,加密和解密就成功完成了。
我正在使用 QT5.5.1,在我正在清理的文件的加密和解密之间,运行 qmake,重建和 运行 在调试模式下使用 MSVC 12.0 编译器(这无关紧要,但如果该程序适合您 - 尝试在一个文件的加密和解密之间清理和构建,看看它是否正常工作。
AES 支持 128 位的块大小和 128、192 和 256 位的密钥大小。在许多模式下,尤其是在 CBC 模式下,IV 必须与块大小相同。问题是您只使用 64 位的 IV 和 64 位的密钥。您需要提供一个 16 字节的 IV(适用于所有 AES 变体)和一个 32 字节的密钥(适用于 AES-256)。
我的猜测是 EVP_CipherInit
将尝试读取完整的 IV 和密钥,因此将读入未初始化的内存,该内存在每次程序执行时可能包含任意数据。
请记住,必须为每次加密随机生成一个 IV,以提供语义安全性。如果 IV 是静态的并且您使用相同的密钥,那么攻击可能会推断您仅通过观察密文来加密相同的消息。因此,随机化密文是一种安全措施 属性。如果你想检查加密是否有效,那么你需要尝试解密它并将结果与原始明文进行比较。您可以将IV存储在密文文件格式的开头。
您似乎想使用密码作为加密密钥。不要混淆密码和密钥。密码的熵很小,而密钥通常看起来像噪音。如果要使用密码,则需要从密码中导出密钥。这通常使用 PBKDF2(PKCS5_PBKDF2_HMAC
with EVP_sha256
,如果你想要 AES-256 密钥)和随机盐和多次迭代(至少 6 万,可以是几百万)。您可以将盐与 IV 一起存储在密文文件格式的开头。
代码如下:
#include <QCoreApplication>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <iostream>
void en_de_crypt(int should_encrypt, FILE *ifp, FILE *ofp, unsigned char *ckey, unsigned char *ivec) {
const unsigned BUFSIZE=4096;
unsigned char *read_buf = (unsigned char*)malloc(BUFSIZE);
unsigned char *cipher_buf;
unsigned blocksize;
int out_len;
EVP_CIPHER_CTX ctx;
for(int i=0; i<8;i++)
{
printf("%c\n",ckey[i]);
}
printf("\n\n");
for(int i=0; i<8;i++)
{
printf("%c\n",ivec[i]);
}
EVP_CipherInit(&ctx, EVP_aes_256_cbc(), ckey, ivec, should_encrypt);
blocksize = EVP_CIPHER_CTX_block_size(&ctx);
cipher_buf = (unsigned char *)malloc(BUFSIZE + blocksize);
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
int numRead = fread(read_buf, sizeof(unsigned char), BUFSIZE, ifp);
EVP_CipherUpdate(&ctx, cipher_buf, &out_len, read_buf, numRead);
fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
if (numRead < BUFSIZE) { // EOF
break;
}
}
// Now cipher the final block and write it out.
EVP_CipherFinal(&ctx, cipher_buf, &out_len);
fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
// Free memory
free(cipher_buf);
free(read_buf);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::string pathToFiles = "C:/Temp/testEnc/dqdokoleda.7z";
unsigned char ckey[8];
unsigned char ivec[8];
ckey[0] = 'p';
ckey[1] = 'a';
ckey[2] = 's';
ckey[3] = 's';
ckey[4] = 'w';
ckey[5] = 'o';
ckey[6] = 'r';
ckey[7] = 'd';
ivec[0] = 'a';
ivec[1] = 'c';
ivec[2] = 'g';
ivec[3] = 't';
ivec[4] = 'i';
ivec[5] = 'j';
ivec[6] = 'o';
ivec[7] = 'r';
FILE *fIN, *fOUT;
// First encrypt the file
fIN = fopen((pathToFiles).c_str(), "rb"); //File to be encrypted; plain text
fOUT = fopen((pathToFiles+".enc").c_str(), "wb"); //File to be written; cipher text
en_de_crypt(1, fIN, fOUT, ckey, ivec);
fclose(fIN);
fclose(fOUT);
//Decrypt file now
fIN = fopen((pathToFiles+".enc").c_str(), "rb"); //File to be read; cipher text
fOUT = fopen((pathToFiles+".decrypted").c_str(), "wb"); //File to be written; cipher text
en_de_crypt(0, fIN, fOUT, ckey, ivec);
fclose(fIN);
fclose(fOUT);
std::cout << "END" << std::endl;
return a.exec();
}
问题是我注释解密部分的时候,每次.enc文件的内容都不一样。然后,如果我尝试分别解密代码的取消注释解密和注释加密部分,则文件未正确解密(7zip 表示无法打开它)。如果我不注释代码的任何部分,加密和解密就成功完成了。
我正在使用 QT5.5.1,在我正在清理的文件的加密和解密之间,运行 qmake,重建和 运行 在调试模式下使用 MSVC 12.0 编译器(这无关紧要,但如果该程序适合您 - 尝试在一个文件的加密和解密之间清理和构建,看看它是否正常工作。
AES 支持 128 位的块大小和 128、192 和 256 位的密钥大小。在许多模式下,尤其是在 CBC 模式下,IV 必须与块大小相同。问题是您只使用 64 位的 IV 和 64 位的密钥。您需要提供一个 16 字节的 IV(适用于所有 AES 变体)和一个 32 字节的密钥(适用于 AES-256)。
我的猜测是 EVP_CipherInit
将尝试读取完整的 IV 和密钥,因此将读入未初始化的内存,该内存在每次程序执行时可能包含任意数据。
请记住,必须为每次加密随机生成一个 IV,以提供语义安全性。如果 IV 是静态的并且您使用相同的密钥,那么攻击可能会推断您仅通过观察密文来加密相同的消息。因此,随机化密文是一种安全措施 属性。如果你想检查加密是否有效,那么你需要尝试解密它并将结果与原始明文进行比较。您可以将IV存储在密文文件格式的开头。
您似乎想使用密码作为加密密钥。不要混淆密码和密钥。密码的熵很小,而密钥通常看起来像噪音。如果要使用密码,则需要从密码中导出密钥。这通常使用 PBKDF2(PKCS5_PBKDF2_HMAC
with EVP_sha256
,如果你想要 AES-256 密钥)和随机盐和多次迭代(至少 6 万,可以是几百万)。您可以将盐与 IV 一起存储在密文文件格式的开头。