【问题标题】:Function is not generating proper openssl rsa keys函数未生成正确的 openssl rsa 密钥
【发布时间】:2017-02-06 16:09:35
【问题描述】:

这是我编写的用于生成 openssl rsa 4096 位密钥的 c 函数。

    bool rsa_gen_keys()
    {    
    int             ret = 0;
    RSA             *rsa = NULL;
    BIGNUM          *bignum = NULL;
    BIO             *bio_private = NULL;
    BIO             *bio_public = NULL;
    int              bits = 4096;

    unsigned long k = RSA_F4;

    bignum = BN_new();
    ret = BN_set_word(bignum,k);
    if(ret != 1){
        goto cleanup;
    }

    rsa = RSA_new();
    ret = RSA_generate_key_ex(rsa, bits, bignum, NULL);
    if(ret != 1){
        goto cleanup;
    }
    // write rsa private key to file
    bio_private = BIO_new_file("private_new.pem", "w+");
    ret = PEM_write_bio_RSAPrivateKey(bio_private, rsa, NULL, NULL, 0, NULL, NULL);
    BIO_flush(bio_private);
    // write rsa public key to file
    bio_public = BIO_new_file("public_new.pem", "w+");
    ret = PEM_write_bio_RSAPublicKey(bio_public, rsa);
    if(ret != 1){
        goto cleanup;
    }    
    BIO_flush(bio_public);
cleanup:
    BIO_free_all(bio_private);
    BIO_free_all(bio_public);
    RSA_free(rsa);
    BN_free(bignum);
    return ret;
}

上述函数生成的键似乎缺少了什么。当我尝试在另一个程序中使用 public_new.pem 文件时,我收到以下错误:

140286309791384:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: PUBLIC KEY

但是,如果我使用 openssl 命令生成密钥文件,这些文件可以正常工作。

$openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:4096

我注意到从函数和命令行生成的密钥大小不匹配。这是一条线索,但我需要在我的函数中更改什么来解决这个问题?

-rw-rw-r-- 1 3272 Feb  6 09:19 private_key.pem
-rw-rw-r-- 1  800 Feb  6 09:20 public_key.pem
-rw-rw-r-- 1 3243 Feb  6 10:43 private_new.pem
-rw-rw-r-- 1  775 Feb  6 10:43 public_new.pem

顺便说一句,我用 2048 位密钥尝试了上述方法,得到了相同的结果和相同的大小不匹配

【问题讨论】:

标签: c linux openssl rsa key-generator


【解决方案1】:

openssl genpkey 正在使用 PEM_write_bio_PrivateKey (PKCS#8) 而不是 PEM_write_bio_RSAPrivateKey (PKCS#1):https://github.com/openssl/openssl/blob/master/apps/genpkey.c#L161-L164

您没有展示如何生成 public_key.pem,但它可能是使用 PEM_write_bio_PUBKEY (X.509 SubjectPublicKeyInfo) 与 PEM_write_bio_RSAPublicKey (PKCS#1) 编写的。

从 PEM 装甲的角度来看:

  • PKCS#1 公开:开始 RSA 公钥
  • X.509 SubjectPublicKeyInfo: BEGIN PUBLIC KEY
  • PKCS#1 私有:BEGIN RSA PRIVATE KEY
  • PKCS#8:开始私钥

【讨论】:

  • 这就解释了差异。我可能需要切换到使用 EVP 调用来生成正确的格式,而不是直接 RSA 调用 .. 比如 EVP_PKEY_keygen()?.
  • 是的。 EVP_*(envelope(d)) 结构,以及相关的文件格式是关于“这是什么钥匙”和“哦,这是钥匙”。使用 RSA 直接 API 意味着您应该已经知道它是什么密钥类型,所以它忽略了它。
【解决方案2】:

我意识到我需要使用 PKCS#8 和 X.509 的密钥格式。所以我切换到 EVP 函数来生成它们。这是我最终使用的代码的一个非常简化的版本(没有错误检查):

bool rsa_gen_keys() {
    int ret = 0;
    BIO *bio_private = NULL;
    BIO *bio_public = NULL;
    int bits = 4096;

    EVP_PKEY_CTX *ctx;
    EVP_PKEY *pkey = NULL;

    // Get the context
    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    if (!ctx)
        goto cleanup;

    // init keygen
    if (EVP_PKEY_keygen_init(ctx) <= 0)
        goto cleanup;

    // set the bit size 
    if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0)
    goto cleanup;

    /* Generate key */
    if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
        goto cleanup;


    // write rsa private key to file
    bio_private = BIO_new_file("private_new.pem", "w+");
    ret = PEM_write_bio_PrivateKey(bio_private, pkey, NULL, NULL, 0, NULL, NULL);
    if (ret != 1) {
        goto cleanup;
    }
    BIO_flush(bio_private);

    // write rsa public key to file
    bio_public = BIO_new_file("public_new.pem", "w+");

    //ret = PEM_write_bio_RSAPublicKey(bio_public, rsa);
    ret = PEM_write_bio_PUBKEY(bio_public, pkey);
    if (ret != 1) {
        goto cleanup;
    }
    BIO_flush(bio_public);


cleanup:
    if(bio_private) BIO_free_all(bio_private);
    if(bio_public) BIO_free_all(bio_public);
    if(pkey) EVP_PKEY_free(pkey);

    return ret;
}

【讨论】:

    最近更新 更多