RSA_private_encrypt() 和 RSA_public_decrypt() 出现意外的无效填充错误
Unexpected invalid padding error with RSA_private_encrypt() and RSA_public_decrypt()
我正在尝试使用私钥加密并使用 public 密钥解密,并使用 RSA_PKCS1_PADDING
作为填充。加密工作正常,但是当我进行解密时,出现无效填充错误:
processed 9 of 256 bytes, RSA_public_decrypt() error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding
有人知道这里出了什么问题吗?附完整源代码:
void encrypt_stdout(const char *from_file, int to_base64, int padding)
{
unsigned char *input = NULL, *output = NULL, *output2 = NULL;
int output_fd = -1, input_len = 0, output_len = 0, output2_len = 0;
if (readfile(from_file, &input, &input_len) != 0)
{
goto end;
}
output = malloc(RSA_size(rsa));
if (output == NULL)
{
fprintf(stderr, "malloc() on output: %s\n", strerror(errno));
goto end;
}
output_len = RSA_private_encrypt(input_len, input, output, rsa, padding);
if (output_len == -1)
{
fprintf(stderr, "RSA_private_encrypt() %s\n",ERR_error_string(ERR_get_error(), errbuf));
}
else
{
if (to_base64)
{
}
write(1, output, output_len);
}
end:
if (input != NULL)
{
free(input);
}
if (output != NULL)
{
free(output);
}
}
void decrypt_stdout(const char *from_file, int is_base64, int skip_bytes, int padding)
{
unsigned char *input = NULL, *output = NULL, *output2 = NULL;
int output_fd = -1, input_len = 0, output_len = 0, output2_len = 0, total_read = skip_bytes;
if (readfile(from_file, &input, &input_len) != 0)
{
goto end;
}
if (is_base64)
{
if (base64_decode(input, input_len, &output2, &output2_len) != 0)
{
if (output2 != NULL)
free(output2);
goto end;
}
free(input);
input = output2;
input_len = output2_len;
}
output = malloc(RSA_size(rsa));
if (output == NULL)
{
fprintf(stderr, "malloc() on output: %s\n", strerror(errno));
goto end;
}
while (total_read < input_len)
{
memset(output, 0, RSA_size(rsa));
output_len = RSA_public_decrypt(RSA_size(rsa), input + total_read, output, rsa, padding);
if (output_len == -1)
{
fprintf(stderr, "\nprocessed %d of %d bytes, RSA_public_decrypt() %s\n", total_read, input_len, ERR_error_string(ERR_get_error(), errbuf));
break;
}
else
{
write(STDOUT_FILENO, output, output_len);
}
total_read += output_len;
}
end:
if (input != NULL)
{
free(input);
}
if (output != NULL)
{
free(output);
}
}
问题是由 decrypt_stdout()
中的 while
循环引起的。
对我来说,这个循环的意义并不清楚。它应该非常类似于 encrypt_stdout()
:
而不是循环
output_len = RSA_public_decrypt(input_len, input, output, rsa, padding);
if (output_len == -1)
{
fprintf(stderr, "RSA_public_decrypt() %s\n", ERR_error_string(ERR_get_error(), errbuf));
}
else
{
_write(1, output, output_len);
}
有了这个,解密就可以在我的机器上运行了。
但是如果使用循环,第一次解密成功returns明文,而后面解密失败returns-1,导致输出错误信息。
关于代码中使用的逻辑的几点说明:
既然你说的是加解密:RSA_private_encrypt()
and RSA_public_decrypt()
其实不是加解密,而是底层的签名和验证。
通常,当使用 RSA_private_encrypt()
签名时,传递的不是数据本身,而是以摘要 ID 为前缀的数据散列(更准确地说,[=38= 的 DER 编码) ]DigestInfo 值)。在发布的代码中,既没有散列也没有添加摘要 ID。当然,加载的文件可能已经包含摘要 ID 和哈希的串联,但如果没有样本数据就不能这么说。如果不是这种情况,则生成的签名不符合 PKCS#1 v1.5 填充。
如果不进行散列,则必须注意满足长度标准,即要签名的数据必须小于密钥大小减去填充所需的最小值 space(11 字节)对于 PKCS#1 v1.5 填充或 flag_padding
= 1).
为了完整性:PKCS#1 v1.5 填充是确定性的(在签名的上下文中)。填充后的数据如下所示:0x00 || 0x01 || PS || 0x00 || T,其中 PS 由许多 0xff 值组成,大小等于密钥大小。 T 是数据,或者如果符合规范,则为摘要 ID 和散列数据 s 的串联。 RFC8017.
我正在尝试使用私钥加密并使用 public 密钥解密,并使用 RSA_PKCS1_PADDING
作为填充。加密工作正常,但是当我进行解密时,出现无效填充错误:
processed 9 of 256 bytes, RSA_public_decrypt() error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding
有人知道这里出了什么问题吗?附完整源代码:
void encrypt_stdout(const char *from_file, int to_base64, int padding)
{
unsigned char *input = NULL, *output = NULL, *output2 = NULL;
int output_fd = -1, input_len = 0, output_len = 0, output2_len = 0;
if (readfile(from_file, &input, &input_len) != 0)
{
goto end;
}
output = malloc(RSA_size(rsa));
if (output == NULL)
{
fprintf(stderr, "malloc() on output: %s\n", strerror(errno));
goto end;
}
output_len = RSA_private_encrypt(input_len, input, output, rsa, padding);
if (output_len == -1)
{
fprintf(stderr, "RSA_private_encrypt() %s\n",ERR_error_string(ERR_get_error(), errbuf));
}
else
{
if (to_base64)
{
}
write(1, output, output_len);
}
end:
if (input != NULL)
{
free(input);
}
if (output != NULL)
{
free(output);
}
}
void decrypt_stdout(const char *from_file, int is_base64, int skip_bytes, int padding)
{
unsigned char *input = NULL, *output = NULL, *output2 = NULL;
int output_fd = -1, input_len = 0, output_len = 0, output2_len = 0, total_read = skip_bytes;
if (readfile(from_file, &input, &input_len) != 0)
{
goto end;
}
if (is_base64)
{
if (base64_decode(input, input_len, &output2, &output2_len) != 0)
{
if (output2 != NULL)
free(output2);
goto end;
}
free(input);
input = output2;
input_len = output2_len;
}
output = malloc(RSA_size(rsa));
if (output == NULL)
{
fprintf(stderr, "malloc() on output: %s\n", strerror(errno));
goto end;
}
while (total_read < input_len)
{
memset(output, 0, RSA_size(rsa));
output_len = RSA_public_decrypt(RSA_size(rsa), input + total_read, output, rsa, padding);
if (output_len == -1)
{
fprintf(stderr, "\nprocessed %d of %d bytes, RSA_public_decrypt() %s\n", total_read, input_len, ERR_error_string(ERR_get_error(), errbuf));
break;
}
else
{
write(STDOUT_FILENO, output, output_len);
}
total_read += output_len;
}
end:
if (input != NULL)
{
free(input);
}
if (output != NULL)
{
free(output);
}
}
问题是由 decrypt_stdout()
中的 while
循环引起的。
对我来说,这个循环的意义并不清楚。它应该非常类似于 encrypt_stdout()
:
output_len = RSA_public_decrypt(input_len, input, output, rsa, padding);
if (output_len == -1)
{
fprintf(stderr, "RSA_public_decrypt() %s\n", ERR_error_string(ERR_get_error(), errbuf));
}
else
{
_write(1, output, output_len);
}
有了这个,解密就可以在我的机器上运行了。
但是如果使用循环,第一次解密成功returns明文,而后面解密失败returns-1,导致输出错误信息。
关于代码中使用的逻辑的几点说明:
既然你说的是加解密:RSA_private_encrypt()
and RSA_public_decrypt()
其实不是加解密,而是底层的签名和验证。
通常,当使用 RSA_private_encrypt()
签名时,传递的不是数据本身,而是以摘要 ID 为前缀的数据散列(更准确地说,[=38= 的 DER 编码) ]DigestInfo 值)。在发布的代码中,既没有散列也没有添加摘要 ID。当然,加载的文件可能已经包含摘要 ID 和哈希的串联,但如果没有样本数据就不能这么说。如果不是这种情况,则生成的签名不符合 PKCS#1 v1.5 填充。
如果不进行散列,则必须注意满足长度标准,即要签名的数据必须小于密钥大小减去填充所需的最小值 space(11 字节)对于 PKCS#1 v1.5 填充或 flag_padding
= 1).
为了完整性:PKCS#1 v1.5 填充是确定性的(在签名的上下文中)。填充后的数据如下所示:0x00 || 0x01 || PS || 0x00 || T,其中 PS 由许多 0xff 值组成,大小等于密钥大小。 T 是数据,或者如果符合规范,则为摘要 ID 和散列数据 s 的串联。 RFC8017.