2012-02-23 73 views
15

Tôi đang viết một chương trình C mã hóa (dựa trên khóa riêng) và giải mã (dựa trên khóa công khai) văn bản. Tôi đang cố gắng làm điều này với lib OpenSSL. Có ai biết bất kỳ hướng dẫn tốt, hướng dẫn bắt đầu nhanh hoặc mã mẫu? Tôi đã không tìm thấy bất kỳ một phong nha trên web.Mã hóa/giải mã RSA

+4

Bạn nên bắt đầu với bộ khởi động mã hóa. Bạn thường mã hóa bằng khóa công cộng và giải mã bằng khóa riêng. –

Trả lời

30

Dưới đây là một ví dụ tôi tạo ra để mã hóa một tập tin sử dụng RSA cho các thuật toán bất đối xứng và AES-128-CBC cho các thuật toán đối xứng, với các chức năng EVP OpenSSL:

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

Và ví dụ giải mã tương ứng:

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

Tôi nghĩ điều đó khá dễ làm theo.

+0

Tôi không thể hiểu tại sao bạn mang thuật toán mã hóa đối xứng vào ae vào hệ thống mật mã khóa công khai không đối xứng RSA? Điều này có đúng không? – scarface

+4

@scarface: Vì nhiều lý do, hệ thống khóa không đối xứng không được sử dụng để mã hóa dữ liệu hàng loạt - chúng được sử dụng để mã hóa khóa cho hệ thống khóa đối xứng, được sử dụng để mã hóa dữ liệu hàng loạt. Đó chính là cách hoạt động của chức năng mã hóa phong bì EVP *. – caf

+0

Tuyệt vời, cảm ơn bạn rất nhiều. – scarface

Các vấn đề liên quan