从EVP_CIPHER_CTX获取AES密钥

时间:2013-04-14 09:16:42

标签: openssl aes rsa libssl

我正在使用openssl尝试使用RSA公钥,加密AES密钥,并使用该AES通过HTTP将大型数据发送到第三方站点。我知道这是很多加密,第二层是在网络关闭时出现的,数据必须缓存在磁盘上,直到它被POST编辑。

我一直在使用this blog中的示例代码,其中一大块内容如下:

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

我想坚持使用aes_init()函数,但是一旦初始化了EVP_CIPHER_CTX,我找不到将密钥从apropos中取出的方法。

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

EVP_CIPHER_CTX看起来很有希望,但是有一些神奇的偏移我必须阅读key吗?否则,我将不得不修改他的函数以返回iv(以及EVP_CIPHER_CTX),或者丢弃函数并内联代码。

这里的最终目标是使用AES加密大部分数据,并使用我们的RSA公钥加密AES密钥,base64编码,并将它们广播到服务器。 (我认为这是正确的做事方式)

唯一的问题是从{{1}}中提取密钥。

1 个答案:

答案 0 :(得分:2)

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

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

查看pkcs7_encryptpkcs7_decrypt以及i2d_PKCS7_*函数,了解如何将数据提取为可传输格式(以及d2i_PKCS7_*进行反向)。请参阅OpenSSL的文档:PKCS7_encryptPKCS7_decrypt,您可能希望熟悉OpenSSL使用的i2d/d2i convention(这是X509,但d2i部分也适用于此处。

编辑:以下是加密示例(解密类似):

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

我已将完整示例上传到my repository