OpenSSL RSA:无法加密/解密长度超过16个字节的消息

我正在研究一个使用OpenSSL进行基本RSA加密和解密的简单程序。 它对于小消息(<16字节)工作正常,但对于任何事情都失败了。 我知道公钥加密的局限性在于您无法加密任何比密钥大小更长的内容。 在我的情况下,我使用的是1024位密钥,因此我应该使用128字节(由于填充可能会略微减少),对吗? 如果是这样,那不是我正在经历的。

这是我的程序的输出,有15个字节:

Generating RSA keypair...done. Message to encrypt: 0123456789ABCDE 16 bytes encrypted Decrypted message: 0123456789ABCDE 

并且有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) 

似乎无论如何,只加密了16个字节。

我的加密function(通过修复更新):

 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; } 

相应的解密function(用修复更新):

 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; } 

密钥生成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; } 

最后,我的主要内容:

 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; } 

任何帮助是极大的赞赏! 谢谢。

编辑:正如下面的数学指出,似乎我的错误的答案隐藏在这里的OpenSSL: https : //www.openssl.org/docs/crypto/EVP_EncryptInit.html#

这是因为您没有正确处理EVP_SealUpdate()EVP_SealFinal()EVP_OpenUpdate()EVP_OpenFinal() outoutl参数。

每个EVP_XxxxUpdate()EVP_XxxxFinal()调用都将对输出缓冲区EVP_XxxxFinal() 。 因此,您需要通过将每个返回的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; ... } 

该程序使用15字节缓冲区,因为在这种情况下, EVP_XxxxUpdate()调用在outl返回0(没有足够的数据来密封/打开块),将问题隐藏在代码逻辑中。

注意:数据不是使用RSA密钥直接加密,而是使用生成的对称密钥(在您的情况下为AES-128)。 这就是块大小为16字节的原因。