RSA_private_encrypt 中的可能错误
Possible bug in RSA_private_encrypt
在下面的例子中,我们使用一个RSA 256-bit
private key
来加密一个32字节的消息而不填充并将结果存储在同一个内存块中。
#include <openssl/ssl.h>
unsigned char err[256],
msg[] = "This is a message of some sort.",
key[] = "-----BEGIN RSA PRIVATE KEY-----\n"\
"MIGrAgEAAiEA6sZFpHqqFkpskc2GNMl6RHdiEuOqlX3LcW1TnYVgQFECAwEAAQIh\n"\
"AKqoe8FHJVJUwTzvMAo5FrU/t6Cc6GwYDELpU3xxs4nBAhEA+TwHM5ArwBgTtB2y\n"\
"AKlEKQIRAPElwlKWyde1KqHRCjOWX+kCEQDqWYZP9rUcp8cHKpDwTDiZAhBPldOd\n"\
"KDCzJRJN10yTm/RJAhANYsX4BteC/W7VRUjV5jSH\n"\
"-----END RSA PRIVATE KEY-----\n";
void main()
{
//msg[0] = 255;
if (RSA_private_encrypt(32, msg, msg,
PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(key, -1), NULL, NULL, NULL),
RSA_NO_PADDING) != 32)
{
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
puts(err);
}
}
当我们通过删除注释更改第 0 个消息字符的值时,加密失败并显示消息:
rsa routines:RSA_EAY_PRIVATE_ENCRYPT:data too large for modulus
请注意,非常短的 RSA
密钥和硬编码消息长度仅用于演示问题。密钥是使用 openssl
二进制生成的,并且 function
也会因不同大小的密钥而失败(对于 4096 位密钥,the msg[0] = 192
会导致失败)。
似乎函数将消息的开头解释为长度描述符,即使明确说明了 RSA_NO_PADDING
。这是一个错误吗?
在 RSA 中,模数数组和数据数组被解释为大整数。数据整数必须小于模数整数。否则无法恢复加密值
我已经解码了你的private key。模数的第一个字节是 0xEA。这意味着您签名的数据不能以大于 0xEA (234) 的字节开头。如果您分配 msg[0] = 235;
它将再次导致错误。
这就是填充的来源。填充数据的第一个字节通常是 0x00(或者甚至是 0x0001,具体取决于填充方案),这使得填充数据在数值上不可能大于模数。
所以,不,您还没有发现错误。您只是错误地使用了加密货币。我建议你使用一些更高级别的 API 来签署消息。
请注意,填充对于 RSA 至关重要。没有它,就有办法恢复明文或伪造签名。请使用 OAEP 进行加密,使用 PSS 进行签名。此外,密钥大小也很重要。如今,应该使用 4096 位密钥。 256 位的密钥是玩具大小,现在的智能手机可能会破解。
在下面的例子中,我们使用一个RSA 256-bit
private key
来加密一个32字节的消息而不填充并将结果存储在同一个内存块中。
#include <openssl/ssl.h>
unsigned char err[256],
msg[] = "This is a message of some sort.",
key[] = "-----BEGIN RSA PRIVATE KEY-----\n"\
"MIGrAgEAAiEA6sZFpHqqFkpskc2GNMl6RHdiEuOqlX3LcW1TnYVgQFECAwEAAQIh\n"\
"AKqoe8FHJVJUwTzvMAo5FrU/t6Cc6GwYDELpU3xxs4nBAhEA+TwHM5ArwBgTtB2y\n"\
"AKlEKQIRAPElwlKWyde1KqHRCjOWX+kCEQDqWYZP9rUcp8cHKpDwTDiZAhBPldOd\n"\
"KDCzJRJN10yTm/RJAhANYsX4BteC/W7VRUjV5jSH\n"\
"-----END RSA PRIVATE KEY-----\n";
void main()
{
//msg[0] = 255;
if (RSA_private_encrypt(32, msg, msg,
PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(key, -1), NULL, NULL, NULL),
RSA_NO_PADDING) != 32)
{
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
puts(err);
}
}
当我们通过删除注释更改第 0 个消息字符的值时,加密失败并显示消息:
rsa routines:RSA_EAY_PRIVATE_ENCRYPT:data too large for modulus
请注意,非常短的 RSA
密钥和硬编码消息长度仅用于演示问题。密钥是使用 openssl
二进制生成的,并且 function
也会因不同大小的密钥而失败(对于 4096 位密钥,the msg[0] = 192
会导致失败)。
似乎函数将消息的开头解释为长度描述符,即使明确说明了 RSA_NO_PADDING
。这是一个错误吗?
在 RSA 中,模数数组和数据数组被解释为大整数。数据整数必须小于模数整数。否则无法恢复加密值
我已经解码了你的private key。模数的第一个字节是 0xEA。这意味着您签名的数据不能以大于 0xEA (234) 的字节开头。如果您分配 msg[0] = 235;
它将再次导致错误。
这就是填充的来源。填充数据的第一个字节通常是 0x00(或者甚至是 0x0001,具体取决于填充方案),这使得填充数据在数值上不可能大于模数。
所以,不,您还没有发现错误。您只是错误地使用了加密货币。我建议你使用一些更高级别的 API 来签署消息。
请注意,填充对于 RSA 至关重要。没有它,就有办法恢复明文或伪造签名。请使用 OAEP 进行加密,使用 PSS 进行签名。此外,密钥大小也很重要。如今,应该使用 4096 位密钥。 256 位的密钥是玩具大小,现在的智能手机可能会破解。