OpenSSL RSA解密报错:RSA_padding_check_PKCS1_type_2填充解码错误
解决OpenSSL RSA解密文件数据时的PKCS解码错误问题
我之前也碰到过一模一样的问题——内存里加解密好好的,一存文件再读出来就报PKCS解码错误,折腾了好一阵才搞明白,核心问题基本都是二进制数据在文件读写过程中被损坏了,给你列几个最可能的原因和解决办法:
1. 必须用二进制模式读写文件
这是最常见的坑!如果你的代码里用了fopen("xxx", "w")或者fopen("xxx", "r")这种文本模式,在Windows系统下会自动转换换行符(把0x0A变成0x0D0A),还会把0x1A当作EOF截断数据,直接把加密后的二进制数据搞乱。
一定要改成二进制模式:
// 写入加密数据 FILE *fp_write = fopen("encrypted_aes_key.bin", "wb"); // 读取加密数据 FILE *fp_read = fopen("encrypted_aes_key.bin", "rb");
2. 确保读写的字节数完全一致
RSA加密后的输出长度是固定的(等于你的RSA密钥模数长度,比如2048位密钥就是256字节),写入时要把完整的加密数据都写进去,读取时也要读够全部长度,别用fgets这种文本读取函数(它会在遇到\0时停止)。
举个正确的读写示例:
// 加密后写入文件 int enc_len = RSA_public_encrypt( aes_key_len, aes_key, enc_data, rsa_pub, RSA_PKCS1_PADDING ); if (enc_len == -1) { /* 处理加密错误 */ } FILE *fp = fopen("enc_data.bin", "wb"); if (!fp) { /* 处理文件打开错误 */ } // 确保写入全部字节 if (fwrite(enc_data, 1, enc_len, fp) != enc_len) { fprintf(stderr, "写入文件时截断了数据!\n"); } fclose(fp); // 从文件读取后解密 fp = fopen("enc_data.bin", "rb"); if (!fp) { /* 处理错误 */ } // 先获取文件大小 fseek(fp, 0, SEEK_END); long file_size = ftell(fp); fseek(fp, 0, SEEK_SET); unsigned char *read_enc_data = malloc(file_size); if (!read_enc_data) { /* 处理内存分配错误 */ } // 读取全部字节 if (fread(read_enc_data, 1, file_size, fp) != file_size) { fprintf(stderr, "读取文件时没读全数据!\n"); } fclose(fp); // 解密时用读取到的实际长度作为输入长度 int dec_len = RSA_private_decrypt( file_size, read_enc_data, dec_aes_key, rsa_priv, RSA_PKCS1_PADDING ); if (dec_len == -1) { /* 处理解密错误 */ }
3. 别对二进制加密数据做多余的字符串处理
如果你为了存储把加密数据直接当作ASCII字符串处理(比如用strcpy或者printf输出),遇到不可打印字符(比如0x00到0x1F)就会截断或者乱码,导致数据损坏。如果需要把加密数据转成可安全存储的字符串,应该用Base64编码,写入前编码,读取后解码,再解密。
4. 验证读写前后的数据一致性
如果上面的步骤都做了还是报错,建议把加密后的内存数据和读取后的文件数据都打印成十六进制,对比两者是否完全相同:
// 打印十六进制的函数示例 void print_hex(const unsigned char *data, int len) { for (int i=0; i<len; i++) { printf("%02X ", data[i]); if ((i+1)%16 == 0) printf("\n"); } printf("\n"); }
如果打印出来的内容不一样,说明读写过程有问题;如果完全一样,那就要检查解密时用的密钥是不是和加密时匹配,或者填充模式有没有写错(比如加密用了RSA_PKCS1_PADDING,解密用了别的模式)。
内容的提问来源于stack exchange,提问作者santobedi
相关产品推荐
相关产品推荐

