[英]OpenSSL RSA: Unable to encrypt/decrypt messages longer than 16 bytes
I'm working on a simple program that uses OpenSSL to do basic RSA encryption and decryption. 我正在研究一个使用OpenSSL进行基本RSA加密和解密的简单程序。 It is working fine for small messages (<16 bytes), but fails for anything over that. 它对于小消息(<16字节)工作正常,但对于任何事情都失败了。 I understand that a limitation of public key cryptography is that you cannot encrypt anything longer than the key size. 我知道公钥加密的局限性在于您无法加密任何比密钥大小更长的内容。 In my case, I'm using a 1024bit key, so I should have 128bytes to work with (maybe slightly less due to padding), correct? 在我的情况下,我使用的是1024位密钥,因此我应该使用128字节(由于填充可能会略微减少),对吗? If so, that's not what I'm experiencing. 如果是这样,那不是我正在经历的。
Here's the output from my program with 15 bytes: 这是我的程序的输出,有15个字节:
Generating RSA keypair...done.
Message to encrypt: 0123456789ABCDE
16 bytes encrypted
Decrypted message: 0123456789ABCDE
And with 16 bytes: 并且有16个字节:
Generating RSA keypair...done.
Message to encrypt: 0123456789ABCDEF
16 bytes encrypted
140153837057696:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:467:
Decrypted message: (null)
It seems that no matter what, only a total of 16 bytes are encrypted. 似乎无论如何,只加密了16个字节。
My encryption function (updated with fix): 我的加密功能(通过修复更新):
unsigned char* rsa_seal(EVP_PKEY *pub_key, unsigned char *msg, size_t **enc_msg_len, unsigned char **sym_key, int *sym_key_len, unsigned char **iv) {
size_t msg_len = strlen((char*)msg);
unsigned char *encrypt = malloc(EVP_PKEY_size(pub_key));
EVP_CIPHER_CTX *ctx = malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
*sym_key = malloc(EVP_PKEY_size(pub_key));
*iv = malloc(EVP_MAX_IV_LENGTH);
**enc_msg_len = 0;
if(!EVP_SealInit(ctx, EVP_aes_128_cbc(), sym_key, sym_key_len, *iv, &pub_key, 1)) {
ERR_print_errors_fp(stderr);
encrypt = NULL;
goto return_free;
}
if(!EVP_SealUpdate(ctx, encrypt, (int*)*enc_msg_len, msg, (int)msg_len)) {
ERR_print_errors_fp(stderr);
encrypt = NULL;
goto return_free;
}
if(!EVP_SealFinal(ctx, encrypt, (int*)*enc_msg_len)) {
ERR_print_errors_fp(stderr);
encrypt = NULL;
goto return_free;
}
return_free:
EVP_CIPHER_CTX_cleanup(ctx);
free(ctx);
ctx = NULL;
return encrypt;
}
The corresponding decryption function (updated with fix): 相应的解密功能(用修复更新):
char* rsa_open(EVP_PKEY *pri_key, unsigned char *enc_msg, size_t *enc_msg_len, unsigned char *sym_key, int sym_key_len, unsigned char *iv) {
size_t dec_len = 0;
unsigned char *decrypt = malloc((*enc_msg_len) + EVP_MAX_IV_LENGTH);
if(decrypt == NULL) return NULL;
EVP_CIPHER_CTX *ctx = malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
if(!EVP_OpenInit(ctx, EVP_aes_128_cbc(), sym_key, sym_key_len, iv, pri_key)) {
ERR_print_errors_fp(stderr);
decrypt = NULL;
goto return_free;
}
if(!EVP_OpenUpdate(ctx, decrypt, (int*)&dec_len, enc_msg, (int)*enc_msg_len)) {
ERR_print_errors_fp(stderr);
decrypt = NULL;
goto return_free;
}
if(!EVP_OpenFinal(ctx, decrypt, (int*)&dec_len)) {
ERR_print_errors_fp(stderr);
decrypt = NULL;
goto return_free;
}
decrypt[dec_len] = '\0';
return_free:
EVP_CIPHER_CTX_cleanup(ctx);
free(ctx);
ctx = NULL;
return (char*)decrypt;
}
The key generation function: 密钥生成功能:
int rsa_init(EVP_PKEY **rsa_keypair) {
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if(!EVP_PKEY_keygen_init(ctx)) {
ERR_print_errors_fp(stderr);
return -1;
}
if(!EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KEY_LENGTH)) {
ERR_print_errors_fp(stderr);
return -1;
}
if(!EVP_PKEY_keygen(ctx, rsa_keypair)) {
ERR_print_errors_fp(stderr);
return -1;
}
EVP_PKEY_CTX_free(ctx);
return 0;
}
And finally, my main: 最后,我的主要内容:
int main() {
EVP_PKEY *rsa_keypair = NULL; // RSA keypair
char msg[BUFFER]; // Message to encrypt
unsigned char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
// Generate key pair
printf("Generating RSA keypair...");
if(rsa_init(&rsa_keypair) == -1) {
fprintf(stderr, "\nError generating RSA keypair.\n");
exit(1);
}
printf("done.\n");
// Get the message to encrypt
printf("Message to encrypt: ");
fgets(msg, BUFFER-1, stdin);
msg[strlen(msg)-1] = '\0';
// Load error strings in anticipation of error
ERR_load_crypto_strings();
// Encrypt the message
size_t *encrypt_len = malloc(sizeof(size_t));
unsigned char *sym_key = NULL;
unsigned char *iv = NULL;
int sym_key_len;
encrypt = rsa_seal(rsa_keypair, (unsigned char*)msg, &encrypt_len, &sym_key, &sym_key_len, &iv);
printf("%d bytes encrypted\n", (int)*encrypt_len);
// Decrypt it
decrypt = rsa_open(rsa_keypair, (unsigned char*)encrypt, (size_t*)encrypt_len, sym_key, sym_key_len, iv);
printf("Decrypted message: %s\n", decrypt);
free(encrypt);
free(decrypt);
free(encrypt_len);
free(sym_key);
free(iv);
EVP_PKEY_free(rsa_keypair);
return 0;
}
Any help is greatly appreciated! 任何帮助是极大的赞赏! Thank you. 谢谢。
EDIT: As pointed out by math below, it seems that the answer to my mistake was hiding in the OpenSSL here: https://www.openssl.org/docs/crypto/EVP_EncryptInit.html# 编辑:正如下面的数学指出,似乎我的错误的答案隐藏在这里的OpenSSL: https : //www.openssl.org/docs/crypto/EVP_EncryptInit.html#
This is because you do not properly handle out
and outl
parameters in EVP_SealUpdate()
, EVP_SealFinal()
, EVP_OpenUpdate()
and EVP_OpenFinal()
. 这是因为您没有正确处理EVP_SealUpdate()
, EVP_SealFinal()
, EVP_OpenUpdate()
和EVP_OpenFinal()
out
和outl
参数。
Each EVP_XxxxUpdate()
and EVP_XxxxFinal()
call will contribute to the output buffer. 每个EVP_XxxxUpdate()
和EVP_XxxxFinal()
调用都将对输出缓冲区EVP_XxxxFinal()
。 So, you are required to keep track of the seal/open process by summing each outl
returned and providing the expected buffer each time (start of buffer + already handled bytes). 因此,您需要通过将每个返回的outl
相加并每次提供预期的缓冲区(缓冲区的开始+已处理的字节)来跟踪密封/打开过程。
unsigned char* rsa_seal(...)
{
...
**enc_msg_len = 0;
EVP_SealUpdate(ctx, encrypt + **enc_msg_len, &outl, msg, (int)msg_len);
**enc_msg_len += outl;
EVP_SealFinal(ctx, encrypt + **enc_msg_len, &outl);
**enc_msg_len += outl;
...
}
char* rsa_open(...)
{
...
dec_len = 0;
EVP_OpenUpdate(ctx, decrypt + dec_len, &outl, enc_msg, (int)*enc_msg_len);
dec_len += outl;
EVP_OpenFinal(ctx, decrypt + dec_len, &outl);
dec_len += outl;
...
}
The program was working with 15-bytes buffer because in that case, the EVP_XxxxUpdate()
call is returning 0 in outl
(not enough data to seal/open a block), hiding the problem in your code logic. 该程序使用15字节缓冲区,因为在这种情况下, EVP_XxxxUpdate()
调用在outl
返回0(没有足够的数据来密封/打开块),将问题隐藏在代码逻辑中。
Note: The data is not directly encrypted using the RSA key but using a generated symetric key (AES-128 in your case). 注意:数据不是使用RSA密钥直接加密,而是使用生成的对称密钥(在您的情况下为AES-128)。 This is why the block size is 16 bytes. 这就是块大小为16字节的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.