嗨,我正在 Linux 上使用 C 语言。
我有一个与对称 key 解密相关的查询。
我使用以下命令生成了对称 key 。
openssl rand base64 512 > sym.key
使用此 key (sym.key),我已使用以下命令加密了一个文件。
openssl enc -aes-256-cbc -in temp.txt -out temp.enc -kfile sym.key
它生成了一个加密文件temp.enc。
现在,我必须使用与 EVP Decrypt API's 相同的 key (sym.key),并且必须解密此加密文件。
有人可以建议我一种更好的方法吗?
这是代码
unsigned char* decode (unsigned char *key, int len)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(len);
memset (buffer, 0, len);
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new_mem_buf(key, len);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, len);
BIO_free_all(bmem);
return buffer;
}
void decrypt(char *file_name, char *key_file)
{
unsigned char *inbuff = NULL, *outbuff = NULL, *ckey = NULL;
char *buff = NULL;
unsigned int flen = 0, outlen2 = 0, outlen1 = 0, klen = 0;
FILE *fp = NULL, *kfp = NULL;
unsigned char iv[16] = {};
fp = fopen (file_name, "r");
if (NULL == fp)
{
printf ("Cannot open file : %s\n", file_name);
exit(1);
}
fseek (fp, 0, SEEK_END);
flen = ftell (fp);
rewind (fp);
kfp = fopen (key_file, "r");
if (NULL == kfp)
{
printf ("Cannot open file : %s\n", key_file);
exit(1);
}
fseek (kfp, 0, SEEK_END);
klen = ftell (kfp);
rewind (kfp);
inbuff = (unsigned char *)malloc(flen);
outbuff = (unsigned char *)malloc(flen * 2);
ckey = (unsigned char *)malloc(klen);
buff = (char *)malloc(klen);
fread (inbuff, sizeof(char), flen, fp);
fread (buff, sizeof(char), klen, kfp);
ckey = decode(buff, klen);
EVP_CIPHER_CTX ctx;
#if 1
if (! EVP_DecryptInit (&ctx, EVP_aes_256_cbc(), ckey, iv))
{
ERR_print_errors_fp(stderr);
EVP_CIPHER_CTX_cleanup(&ctx);
printf ("Error in Init\n");
exit(1);
}
if (! EVP_DecryptUpdate (&ctx, outbuff, &outlen1, inbuff, flen))
{
ERR_print_errors_fp(stderr);
EVP_CIPHER_CTX_cleanup(&ctx);
printf ("Error in Init\n");
exit(1);
}
if (! EVP_DecryptFinal (&ctx, outbuff + outlen1, &outlen2))
{
ERR_print_errors_fp(stderr);
EVP_CIPHER_CTX_cleanup(&ctx);
printf ("Error in Init\n");
exit(1);
}
EVP_CIPHER_CTX_cleanup(&ctx);
#endif
free (inbuff);
free (outbuff);
free (ckey);
fclose (fp);
fclose (kfp);
printf ("Outbuff:\n %s\n", outbuff);
}
谢谢。
最佳答案
Using this key (sym.key) I have encrypted a file with below command.
openssl enc -aes-256-cbc -in temp.txt -out temp.enc -kfile sym.key
不完全是。 openssl enc -kfile
读取文件的第一行,并且仅读取第一行,并将其用作密码,这与 key 不同。 enc
具有三个输入密码的选项,之后它通过 key 派生过程使用随机盐运行密码,以生成实际 key 和 IV(对于使用 IV 的密码,AES-CBC 就是如此) 。然后,它将包含盐的 header 和密文写入输出文件。这称为基于密码的加密 (PBE),有时也称为基于密码的 key 派生函数 (PBKDF)。
根据您实际想要做什么,有两种方法。
解密您拥有的文件
读取 sym.key
中的第一行(不包括行终止符)作为字符,而不是base64,并用 temp.enc
中的盐来喂养它通过EVP_BytesToKey
像这样的东西:
FILE * pwfile = fopen (key_file, "r");
if(!pwfile) error_handling
char pwline [70];
fgets (pwline, sizeof pwline, pwfile);
int pwlen = strlen (pwline);
if(pwlen==0 || pwline[pwlen-1]!='\n') error_handling
pwline[--pwlen] = '\0';
// Open file_name and read into inbuff for flen as you have now
// Optionally confirm the first 8 bytes are "Salted__"
// If on Windows must fopen with mode "rb" to get all bytes correctly;
// on Unix it is clearer to specify this but not actually needed
// because on Unix binary files and text files are treated the same
unsigned char key [256/8]; // AES-256 key is 32 bytes
unsigned char iv [128/8]; // AES IV is 16 bytes (regardless of key)
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_md5(), inbuff+8, /* the salt! */
(unsigned char*)pwline, pwlen, 1, key, iv);
// Now continue as you have with EVP_Encrypt{Init,Update,Final}
// using key,iv except use buffer inbuff+16 for length flen-16 .
// (And do something with the output, which you don't now!)
创建您显然想要的文件
使用enc
要创建使用直接 key 加密的文件,您必须使用 -K
传递它命令行上的选项(大写 K)以十六进制表示。然而,在 C 程序中处理十六进制很麻烦,所以我会在加密端处理它,例如:
openssl rand 32 >sym.key # AES-256 key must be exactly 32 bytes, not more
openssl enc -aes-256-cbc -in temp.txt -out temp.enc \
-K $(od -An -tx1 sym.key | sed 's/ //g') -iv 00000000000000000000000000000000
然后在你的 C 程序中读取 sym.key
(至少在 Windows 上是二进制)并按原样使用它,IV 为 16 个 0,就像您现在一样。
或者,有rand
编写十六进制并按原样使用
openssl rand -hex 32 >sym.key
openssl enc -aes-256-cbc -in temp.txt -out temp.enc -K $(cat sym.key) -iv (same)
然后在你的 C 程序中读取 sym.key
(作为文本行)并将其从 64 个十六进制字符转换为 unsigned char key [32]
.
其他要点
如果您确实需要解码 Base64 文件,则无需先将其读入内存,然后将 b64BIO 推送到 memBIO;您可以将 b64BIO 推送到读取文件的 fileBIO 上。
您不需要分配 flen*2
对于 outbuff
。解密后的明文永远不会比密文长。 (对于 salted-PBE 形式来说,实际上是 flen-16
,如上所述。)加密可以扩展数据,然后只有一个 block (对于 AES,16 字节)。
检查 malloc
是一个很好的做法没有回来NULL
在使用它之前。这种情况在现代系统上很少发生,但如果从较大的程序调用这样的简单代码,并且该程序的某些其他部分存在耗尽内存的错误,或者可能存在被拒绝服务攻击利用的漏洞,则可能会发生这种情况.
如果您想支持不适合可用内存的大文件,或者可能不支持,请迭代读取 block ,将每个 block 输入 DecryptUpdate
,写出结果(这将滞后大约一个 block ),并在 EOF 处调用 DecryptFinal
并输出任何最后一个部分块。
关于OpenSSL EVP API : How to decrypt the encrypted file using a symmetric key file,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34357543/