以 DER 格式写入 private/public 键

Write private/public keys in DER format

我需要编写一个生成 RSA 密钥的 C 程序,并以 DER 格式保存 X.509 public 密钥和 DER 格式的 PKCS#8 私钥。我用过 Google,但并没有真正找到多少。我到目前为止是这样的:

#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>

void main() {
    int ret = 0;
    RSA *r = NULL;
    BIGNUM *bne = NULL;
    BIO *bp_public = NULL, *bp_private = NULL;
    int bits = 2048;
    unsigned long e = RSA_F4;

    // Generate the RSA key
    printf("Generating RSA key...\n");
    bne = BN_new();
    ret = BN_set_word(bne, e);
    if(ret != 1) {
        goto free_all;
    }
    r = RSA_new();
    ret = RSA_generate_key_ex(r, bits, bne, NULL);
    if(ret != 1) {
        goto free_all;
    }

    // Save the public key in PEM format
    printf("Writing key files...\n");
    bp_public = BIO_new_file("public.pem", "w+");
    ret = PEM_write_bio_RSAPublicKey(bp_public, r);
    if(ret != 1) {
        goto free_all;
    }

    // Save the private key in PEM format
    bp_private = BIO_new_file("private.pem", "w+");
    ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);

    // Free everything
    free_all:
    BIO_free_all(bp_public);
    BIO_free_all(bp_private);
    RSA_free(r);
    BN_free(bne);
    printf("Done!\n");
}

这显然是以PEM 格式编写密钥。我还需要能够在代码中将数据实际存储在内存中,而不仅仅是将其直接写入文件,因为我还需要用 public 键做一些其他事情。

感谢您的帮助

我认为您需要使用 EVP_PKEY_assign_RSA 将密钥转换为 EVP_PKEY。然后你可以使用 i2d_PUBKEY_bio 写出一个生物。

对我的代码进行以下修改:

  1. 包含头文件<openssl/evp.h>
  2. 声明 BIO 以写出 public_der
  3. EVP_PKEY_new()
  4. 创建 EVP_PKEY 结构
  5. 使用 EVP_PKEY_assign_RSA
  6. 进行转换
  7. i2d_PUBKEY_bio
  8. 写简历

在上下文中:

#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>

void main() {
    int ret = 0;
    RSA *r = NULL;
    BIGNUM *bne = NULL;
    BIO *bp_public = NULL, *bp_private = NULL, *bp_public_der = NULL;
    int bits = 2048;
    unsigned long e = RSA_F4;

    // Generate the RSA key
    printf("Generating RSA key...\n");
    bne = BN_new();
    ret = BN_set_word(bne, e);
    if(ret != 1) {
        goto free_all;
    }
    r = RSA_new();
    ret = RSA_generate_key_ex(r, bits, bne, NULL);
    if(ret != 1) {
        goto free_all;
    }

    // Save the public key in PEM format
    printf("Writing key files...\n");
    bp_public = BIO_new_file("public.pem", "w+");
    ret = PEM_write_bio_RSAPublicKey(bp_public, r);
    if(ret != 1) {
        goto free_all;
    }

    // Save the private key in PEM format
    bp_private = BIO_new_file("private.pem", "w+");
    ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);

    // Save in DER
    EVP_PKEY *evp = EVP_PKEY_new();
    ret = EVP_PKEY_assign_RSA(evp, r);
    if(ret != 1){
        printf("failure %i\n", ret);
    }
    bp_public_der = BIO_new_file("public.key", "w+");
    ret = i2d_PUBKEY_bio(bp_public_der, evp);



    // Free everything
    free_all:
    BIO_free_all(bp_public);
    BIO_free_all(bp_public_der);
    BIO_free_all(bp_private);
    RSA_free(r);
    BN_free(bne);
    printf("Done!\n");
}

您现在可以在 public.key 中找到 public 键的 DER。你应该能够为私人做同样的事情。

希望对您有所帮助。

您的问题 "saves an X.509 public key in DER format" 的实际含义有点含糊。假设您实际上是指 "save it as a SubjectPublicKeyInfo structure" (这是持有 public 密钥的 X.509 证书的一部分),那么您应该使用 i2d_RSA_PUBKEY (或 i2d_RSA_PUBKEY_fp 或 i2d_RSA_PUBKEY_bio) 将其写出(无需先将其转换为 EVP_PKEY)。

对于 DER 格式的 PKCS#8 私钥,您当前的方法对于 PEM 格式不正确。 PEM_write_bio_RSAPrivateKey() 函数将以传统格式(不是 PKCS#8)写出来。

我假设您不想做任何复杂的事情,比如先加密密钥。对于这个,您需要将其转换为 EVP_PKEY(使用 @JawguyChooser 提到的 EVP_PKEY_assign_RSA())。接下来,您使用(遗憾的是未记录)函数 EVP_PKEY2PKCS8.

获得一个 PKCS8_PRIV_KEY_INFO 结构
PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey);

使用完 PKCS8_PRIV_KEY_INFO_free() 后,您需要释放此结构。接下来使用 i2d_PKCS8_PRIV_KEY_INFO()(或 i2d_PKCS8_PRIV_KEY_INFO_fp() 或 i2d_PKCS8_PRIV_KEY_INFO_bio)写出 PKCS8 DER。

有关这些函数的各种信息,请参阅手册页:

https://www.openssl.org/docs/man1.1.0/crypto/i2d_RSAPublicKey.html