문제

I'm using openssl trying to use an RSA public key, to encrypt an AES key, and use that AES to send large-ish data over HTTP(s) to a 3rd party site. I know that's a lot of encryption, the second layer comes when the network is down, and the data has to be cached on disk until it can be POSTed.

I've been using the example code from this blog, a chunk of which is inlined below:

int aes_init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx)
{
  int i, nrounds = 5;
  unsigned char key[32], iv[32];
  /*
   * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
   * nrounds is the number of times the we hash the material. More rounds are more secure but
   * slower.
   */
  i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv);
  if (i != 32) {
    printf("Key size is %d bits - should be 256 bits\n", i);
    return -1;
  }
  for(int x = 0; x<32; ++x)
    printf("Key: %x iv: %x \n", key[x], iv[x]);
  for(int x = 0; x<8; ++x)
    printf("salt: %x\n", salt[x]);
  EVP_CIPHER_CTX_init(e_ctx);
  EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
  return 0;
}

I'd like to stick with his aes_init() function, but I can't find a way to get the key out of the EVP_CIPHER_CTX once it has been initialised.

apropos lists a few functions relating to EVP_CIPHER_CTX:

$ apropos EVP_CIPHER_CTX
EVP_CIPHER_CTX_block_size (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_cipher (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_cleanup (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_ctrl (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_flags (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_get_app_data (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_init (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_iv_length (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_key_length (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_mode (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_nid (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_set_app_data (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_set_key_length (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_set_padding (3ssl) - EVP cipher routines
EVP_CIPHER_CTX_type (3ssl) - EVP cipher routines

EVP_CIPHER_CTX_set_key_length looks promising, but is there then some magical offset from which I have to read the EVP_CIPHER_CTX? Otherwise, I'll have to modify his function to return the key (and the iv), or throw away the function and inline the code.

The end goal here is to encrypt a large portion of data using AES, and encrypt the AES key using our RSA public key, base64 encode both, and broadcast them to the server. (Which I believe is the correct way of doing things)

The only issue then, is extracting the key from the EVP_CIPHER_CTX.

도움이 되었습니까?

해결책

Why would you want to build your own solution to this kind of hybrid cryptography? There are already existing standards and methods that can help you.

I recommend you look into the PKCS#7 standard, which is the basis for S/MIME. OpenSSL has a direct interface to it. You tell it which data you want to encrypt using an asymmetric key and it handles the rest for you.

Look at pkcs7_encrypt and pkcs7_decrypt as well as the i2d_PKCS7_* functions for how to extract that data into a transmittable format (and d2i_PKCS7_* for reverse). See OpenSSL's documentation: PKCS7_encrypt, PKCS7_decrypt and you might want to familiarize yourself with the i2d/d2i convention used by OpenSSL (this is X509 but the d2i part applies here as well.

Edit: Here is an example for encryption (decryption is analogous):

#include <stdio.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>
#include <openssl/err.h>


int main()
{
    STACK_OF(X509) *certs;
    FILE *fp;
    BIO *bio;
    PKCS7 *p7;

    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();

    certs = sk_X509_new_null();
    fp = fopen("cert.pem", "r");
    sk_X509_push(certs, PEM_read_X509(fp, NULL, NULL, NULL));
    fclose(fp);

    bio = BIO_new_file("data.txt", "r");
    p7 = PKCS7_encrypt(certs, bio, EVP_des_ede3_cbc(), 0);
    BIO_free(bio);

    bio = BIO_new_file("data.txt.enc", "w");
    i2d_PKCS7_bio(bio, p7);
    BIO_flush(bio);
    BIO_free(bio);

    ERR_print_errors_fp(stdout);
    return 0;
}

I have uploaded the full example to my repository.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top