1

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.

4

1 回答 1

2

为什么要为这种混合密码学构建自己的解决方案?已经有现有的标准和方法可以帮助您。

我建议您查看PKCS#7标准,它是 S/MIME 的基础。OpenSSL 有一个直接的接口。你告诉它你想使用非对称密钥加密哪些数据,它会为你处理其余的。

查看pkcs7_encrypt以及如何将数据提取为可传输格式(以及pkcs7_decrypt反向)的功能。请参阅 OpenSSL 的文档:PKCS7_encryptPKCS7_decrypt并且您可能想熟悉 OpenSSL 使用的i2d/d2i 约定(这是 X509,但 d2i 部分也适用于此处。i2d_PKCS7_*d2i_PKCS7_*

编辑:这是一个加密的例子(解密是类似的):

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

我已将完整示例上传到我的存储库

于 2013-04-14T18:40:13.873 回答