以DER格式编写私钥/公钥

时间:2018-01-18 15:19:34

标签: c openssl rsa x509 pkcs#8

我需要编写一个生成RSA密钥的C程序,并以DER格式保存X.509公钥,以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格式写入密钥。我还需要能够在代码中实际拥有内存中的数据,而不是直接将其写入文件,因为我需要对公钥执行其他一些操作。

感谢您的帮助

2 个答案:

答案 0 :(得分:2)

我认为您需要使用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. 写给bio

    在上下文中:

    #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中找到公钥的DER。你应该能够为私人做同样的事情。

    希望这有帮助。

答案 1 :(得分:1)

你的问题对于你真正的意思是“以DER格式保存X.509公钥”有点含糊不清。假设您实际上是指“将其保存为SubjectPublicKeyInfo结构”(这是保存公钥的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