c - 无法使用 openssl CLI 解密消息,该消息是使用 openssl API 加密的
问题描述
我正在使用来自 Linux libcrypto AES-128 CBC 加密/解密的上述代码在 Ubuntu 上工作,但在 Raspberry Pi 上不工作
这里稍微修改了代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/crypto.h>
unsigned char aes_key[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len);
int main( )
{
/* Input data to encrypt */
unsigned char aes_input[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
fprintf(stderr,"%s\n",SSLeay_version(SSLEAY_VERSION));
/* Init vector */
//unsigned char iv[AES_BLOCK_SIZE];
unsigned char iv[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
//memset(iv, 0x00, AES_BLOCK_SIZE);
/* Buffers for Encryption and Decryption */
unsigned char enc_out[sizeof(aes_input)];
unsigned char dec_out[sizeof(aes_input)];
/* AES-128 bit CBC Encryption */
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, sizeof(aes_input), &enc_key, iv, AES_ENCRYPT);
FILE *fp = fopen("id_encrypted","w");
fwrite(enc_out, sizeof(enc_out), 1, fp); // write all the new buffer
fclose(fp);
/* AES-128 bit CBC Decryption */
//memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
//unsigned char iv[AES_BLOCK_SIZE];
unsigned char iv2[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
AES_cbc_encrypt(enc_out, dec_out, sizeof(aes_input), &dec_key, iv2, AES_DECRYPT);
/* Printing and Verifying */
print_data("\n Original ",aes_input, sizeof(aes_input)); // you can not print data as a string, because after Encryption its not ASCII
print_data("\n Encrypted",enc_out, sizeof(enc_out));
print_data("\n Decrypted",dec_out, sizeof(dec_out));
return 0;
}
void print_data(const char *tittle, const void* data, int len)
{
printf("%s : ",tittle);
const unsigned char * p = (const unsigned char*)data;
int i = 0;
for (; i<len; ++i)
printf("%02X ", *p++);
printf("\n");
}
如果你运行代码,你可以看到下面的输出。
OpenSSL 1.1.1 2018 年 9 月 11 日
原文:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
加密:C6 A1 3B 37 87 8F 5B 82 6F 4F 81 62 A1 C8 D8 79
解密:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
我的目标是使用 openssl CLI解密加密的输出文件 [在代码中命名为id_encrypted ]。
我使用的命令是
openssl enc -d -v -aes-128-cbc -in id_encrypted -out id_decrypted -K "0123456789abcdef" -iv "0123456789abcdef"
但得到以下错误消息并且输出文件为空。
bufsize=8192
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
bad decrypt
139861660053952:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:537:
任何人都可以帮助它为什么不起作用?我想,问题出在我正在使用的 openssl 命令上,因为我们可以看到该代码适用于加密和解密。
解决方案
不要这样写你的加密代码。您正在使用低级 AES API,该 API 适用于非常了解自己在做什么的高级用户。特别是它们不会:
- 执行填充 - 大多数情况下都需要(并且在 OpenSSL CLI 解密期间预期)
- 默认使用优化和恒定时间(即最安全)的实现
它们也很容易被误用并在脚上开枪。由于这个和上述原因,OpenSSL 项目团队长期以来一直不鼓励低级 AES API,并将在下一版本的 OpenSSL 中弃用:
https://github.com/openssl/openssl/blob/9ce921f2dacc9f56b8ae932ae9c299670700a297/CHANGES#L394-L413
相反,您应该使用 EVP API。请参阅此页面以获取示例代码:
https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
除此之外,在 OpenSSL CLI 上指定密钥和 iv 的方式还有一些其他问题。“-K”参数需要十六进制的密钥。每个十六进制数字代表 4 位(不是 8 位)。所以你给出的密钥相当于:
01 23 45 67 89 ab cd ef
但你想要的是:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
IV也有类似的问题。所以你真正想要的是:
$ openssl enc -d -v -aes-128-cbc -in id_encrypted -out id_decrypted -K "000102030405060708090a0b0c0d0e0f" -iv "000102030405060708090a0b0c0d0e0f"
但是,在您修复加密代码以进行适当的填充之前,这仍然不起作用。
编辑添加:
您还可以使用该-nopad
选项在不填充的情况下进行解密。然而,这仍然是最好的重写你的代码不需要这个。
推荐阅读
- clojure - 使用交换!在嵌套地图上
- google-apps-script - Correct setup for accessing a GSheet published as a webapp via a service account
- android - Android Crashlytics - 无法上传符号
- json - 如何将动态命名的记录与 Dhall 中的静态记录合并?
- docker - 如何使用自己的 Dockerfile 搭建 Ray 集群?
- python - Matplotlib 中的文本位置具有绝对 x 坐标,但不是 y
- python - 关于字典的Python问题(调试)
- html - 如何在不被计算的情况下观看 youtube 视频?
- ruby - 无法为 docker ruby alpine 安装 openssl-dev
- c - 使用 fgets() 随机出现分段错误,仅发生在 linux 服务器上,而不是我自己的发行版