这是我编写的用于生成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 位密钥尝试了上述操作,我得到了相同的结果和相同的大小不匹配
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 主题公钥信息:开始公钥
- PKCS#1 私有:开始 RSA 私钥
- PKCS#8:开始私钥
我意识到我需要使用 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;
}