RSA加密/解密

Posted

技术标签:

【中文标题】RSA加密/解密【英文标题】:RSA encrypt/decrypt 【发布时间】:2012-03-13 11:48:12 【问题描述】:

我正在编写一个 C 程序来加密(基于私钥)和解密(基于公钥)文本。我正在尝试使用 OpenSSL 库来做到这一点。有谁知道任何好的教程、快速入门指南或示例代码?我在网上没有找到任何像样的。

【问题讨论】:

您应该从加密入门开始。您通常使用公钥加密并使用私钥解密。 【参考方案1】:

这是我创建的一个示例,用于使用 RSA 加密文件,不对称算法使用 RSA,对称算法使用 AES-128-CBC,使用 OpenSSL EVP 函数:

#include <stdio.h>
#include <stdlib.h>

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/err.h>

#include <arpa/inet.h> /* For htonl() */

int do_evp_seal(FILE *rsa_pkey_file, FILE *in_file, FILE *out_file)

    int retval = 0;
    RSA *rsa_pkey = NULL;
    EVP_PKEY *pkey = EVP_PKEY_new();
    EVP_CIPHER_CTX ctx;
    unsigned char buffer[4096];
    unsigned char buffer_out[4096 + EVP_MAX_IV_LENGTH];
    size_t len;
    int len_out;
    unsigned char *ek = NULL;
    int eklen;
    uint32_t eklen_n;
    unsigned char iv[EVP_MAX_IV_LENGTH];

    if (!PEM_read_RSA_PUBKEY(rsa_pkey_file, &rsa_pkey, NULL, NULL))
    
        fprintf(stderr, "Error loading RSA Public Key File.\n");
        ERR_print_errors_fp(stderr);
        retval = 2;
        goto out;
    

    if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey))
    
        fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
        retval = 3;
        goto out;
    

    EVP_CIPHER_CTX_init(&ctx);
    ek = malloc(EVP_PKEY_size(pkey));

    if (!EVP_SealInit(&ctx, EVP_aes_128_cbc(), &ek, &eklen, iv, &pkey, 1))
    
        fprintf(stderr, "EVP_SealInit: failed.\n");
        retval = 3;
        goto out_free;
    

    /* First we write out the encrypted key length, then the encrypted key,
     * then the iv (the IV length is fixed by the cipher we have chosen).
     */

    eklen_n = htonl(eklen);
    if (fwrite(&eklen_n, sizeof eklen_n, 1, out_file) != 1)
    
        perror("output file");
        retval = 5;
        goto out_free;
    
    if (fwrite(ek, eklen, 1, out_file) != 1)
    
        perror("output file");
        retval = 5;
        goto out_free;
    
    if (fwrite(iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc()), 1, out_file) != 1)
    
        perror("output file");
        retval = 5;
        goto out_free;
    

    /* Now we process the input file and write the encrypted data to the
     * output file. */

    while ((len = fread(buffer, 1, sizeof buffer, in_file)) > 0)
    
        if (!EVP_SealUpdate(&ctx, buffer_out, &len_out, buffer, len))
        
            fprintf(stderr, "EVP_SealUpdate: failed.\n");
            retval = 3;
            goto out_free;
        

        if (fwrite(buffer_out, len_out, 1, out_file) != 1)
        
            perror("output file");
            retval = 5;
            goto out_free;
        
    

    if (ferror(in_file))
    
        perror("input file");
        retval = 4;
        goto out_free;
    

    if (!EVP_SealFinal(&ctx, buffer_out, &len_out))
    
        fprintf(stderr, "EVP_SealFinal: failed.\n");
        retval = 3;
        goto out_free;
    

    if (fwrite(buffer_out, len_out, 1, out_file) != 1)
    
        perror("output file");
        retval = 5;
        goto out_free;
    

    out_free:
    EVP_PKEY_free(pkey);
    free(ek);

    out:
    return retval;


int main(int argc, char *argv[])

    FILE *rsa_pkey_file;
    int rv;

    if (argc < 2)
    
        fprintf(stderr, "Usage: %s <PEM RSA Public Key File>\n", argv[0]);
        exit(1);
    

    rsa_pkey_file = fopen(argv[1], "rb");
    if (!rsa_pkey_file)
    
        perror(argv[1]);
        fprintf(stderr, "Error loading PEM RSA Public Key File.\n");
        exit(2);
    

    rv = do_evp_seal(rsa_pkey_file, stdin, stdout);

    fclose(rsa_pkey_file);
    return rv;

以及对应的解密例子:

#include <stdio.h>
#include <stdlib.h>

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/err.h>

#include <arpa/inet.h> /* For htonl() */

int do_evp_unseal(FILE *rsa_pkey_file, FILE *in_file, FILE *out_file)

    int retval = 0;
    RSA *rsa_pkey = NULL;
    EVP_PKEY *pkey = EVP_PKEY_new();
    EVP_CIPHER_CTX ctx;
    unsigned char buffer[4096];
    unsigned char buffer_out[4096 + EVP_MAX_IV_LENGTH];
    size_t len;
    int len_out;
    unsigned char *ek;
    unsigned int eklen;
    uint32_t eklen_n;
    unsigned char iv[EVP_MAX_IV_LENGTH];

    if (!PEM_read_RSAPrivateKey(rsa_pkey_file, &rsa_pkey, NULL, NULL))
    
        fprintf(stderr, "Error loading RSA Private Key File.\n");
        ERR_print_errors_fp(stderr);
        retval = 2;
        goto out;
    

    if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey))
    
        fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
        retval = 3;
        goto out;
    

    EVP_CIPHER_CTX_init(&ctx);
    ek = malloc(EVP_PKEY_size(pkey));

    /* First need to fetch the encrypted key length, encrypted key and IV */

    if (fread(&eklen_n, sizeof eklen_n, 1, in_file) != 1)
    
        perror("input file");
        retval = 4;
        goto out_free;
    
    eklen = ntohl(eklen_n);
    if (eklen > EVP_PKEY_size(pkey))
    
        fprintf(stderr, "Bad encrypted key length (%u > %d)\n", eklen,
            EVP_PKEY_size(pkey));
        retval = 4;
        goto out_free;
    
    if (fread(ek, eklen, 1, in_file) != 1)
    
        perror("input file");
        retval = 4;
        goto out_free;
    
    if (fread(iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc()), 1, in_file) != 1)
    
        perror("input file");
        retval = 4;
        goto out_free;
    

    if (!EVP_OpenInit(&ctx, EVP_aes_128_cbc(), ek, eklen, iv, pkey))
    
        fprintf(stderr, "EVP_OpenInit: failed.\n");
        retval = 3;
        goto out_free;
    

    while ((len = fread(buffer, 1, sizeof buffer, in_file)) > 0)
    
        if (!EVP_OpenUpdate(&ctx, buffer_out, &len_out, buffer, len))
        
            fprintf(stderr, "EVP_OpenUpdate: failed.\n");
            retval = 3;
            goto out_free;
        

        if (fwrite(buffer_out, len_out, 1, out_file) != 1)
        
            perror("output file");
            retval = 5;
            goto out_free;
        
    

    if (ferror(in_file))
    
        perror("input file");
        retval = 4;
        goto out_free;
    

    if (!EVP_OpenFinal(&ctx, buffer_out, &len_out))
    
        fprintf(stderr, "EVP_SealFinal: failed.\n");
        retval = 3;
        goto out_free;
    

    if (fwrite(buffer_out, len_out, 1, out_file) != 1)
    
        perror("output file");
        retval = 5;
        goto out_free;
    

    out_free:
    EVP_PKEY_free(pkey);
    free(ek);

    out:
    return retval;


int main(int argc, char *argv[])

    FILE *rsa_pkey_file;
    int rv;

    if (argc < 2)
    
        fprintf(stderr, "Usage: %s <PEM RSA Private Key File>\n", argv[0]);
        exit(1);
    

    rsa_pkey_file = fopen(argv[1], "rb");
    if (!rsa_pkey_file)
    
        perror(argv[1]);
        fprintf(stderr, "Error loading PEM RSA Private Key File.\n");
        exit(2);
    

    rv = do_evp_unseal(rsa_pkey_file, stdin, stdout);

    fclose(rsa_pkey_file);
    return rv;

我认为这很容易理解。正如所写的那样,这两个命令都可以用作管道的一部分(它们在stdin 上接受输入并将输出写入stdout)。

【讨论】:

我不明白你们为什么将对称加密算法 aes 带入非对称公钥加密系统 RSA?这是否正确? @scarface:由于各种原因,非对称密钥系统不用于加密批量数据 - 它们用于加密对称密钥系统的密钥,对称密钥系统本身用于加密批量数据。这正是 EVP*“信封加密”功能的工作原理。 是你的代码吗?你能放任何关于openssl的链接来下载吗?谢谢

以上是关于RSA加密/解密的主要内容,如果未能解决你的问题,请参考以下文章

java rsa私钥加密

java编写非对称加密,解密,公钥加密,私钥解密,RSA,rsa

iOS常用加密之RSA加密解密

python_rsa加密解密

C#中RSA加密解密

rsa解密乱码,重启应用后正常