首页 文章

RSA加密/解密

提问于
浏览
16

我正在写一个C程序,它加密(基于私钥)和解密(基于公钥)文本 . 我正在尝试使用OpenSSL lib . 有谁知道任何好的教程,快速入门指南或示例代码?我没有在网上找到任何体面的人 .

1 回答

  • 33

    下面是我使用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 ) .

相关问题