在 C 中读取和写入 rsa 密钥到 pem 文件
Posted
技术标签:
【中文标题】在 C 中读取和写入 rsa 密钥到 pem 文件【英文标题】:Reading and writing rsa keys to a pem file in C 【发布时间】:2012-09-20 18:20:30 【问题描述】:我正在编写一个 C 程序来为 RSA 生成密钥并将它们写入文件,然后从中读取。作业要求我生成 openssl 格式的文件。所以,我选择了PEM。现在,我有以下创建文件的功能
rsa = RSA_new();
// These 3 keys are generated beforehand
rsa->e = e;
rsa->n = n;
rsa->d = d;
fp = fopen(pubkey_file, "w");
if(!PEM_write_RSAPublicKey(fp, rsa))
printf("\n%s\n", "Error writing public key");
fflush(fp);
fclose(fp);
fp = fopen(privkey_file, "w");
// pRsaKey = EVP_PKEY_new();
// EVP_PKEY_assign_RSA(pRsaKey, rsa);
if(!PEM_write_RSAPrivateKey(fp, rsa, NULL, 0, 0, NULL, NULL))
// if (!PEM_write_PrivateKey(fp, pRsaKey, NULL, NULL, 0, 0, NULL))
printf("\n%s\n", "Error writing private key");
fflush(fp);
fclose(fp);
这是读取文件的功能
rsa = RSA_new();
fp = fopen(pubkey_file, "r");
if(PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL) == NULL)
printf("\n%s\n", "Error Reading public key");
return;
fclose(fp);
BN_bn2bin(rsa->n, (unsigned char *)modulus);
BN_bn2bin(rsa->e, (unsigned char *)exp);
printf("\n%s\n%s\n", exp, modulus);
RSA_free(rsa);
// pRsaKey = EVP_PKEY_new();
fp = fopen(privkey_file, "r");
if(fp)
// if((PEM_read_PrivateKey(fp, &pRsaKey, NULL, NULL)) == NULL)
if((PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL)) == NULL)
printf("\n%s\n", "Error Reading private key");
return;
// rsa = RSA_new();
// rsa = EVP_PKEY_get1_RSA(pRsaKey);
fclose(fp);
根据需要写入和读取公钥,但 provate 密钥失败。我尝试过同时使用 rsa 和 evp 进行编写(在上面的代码中对此进行了注释)。但是,两者都失败了。我无法理解为什么会发生这种情况,也无法尝试找到调试此问题的位置。任何人都可以为此提供一些指示吗?
【问题讨论】:
我会调查是否有功能可以提取错误,以便您了解这里发生的情况。调用 fopen 后还要检查 fp 并在那里打印任何错误。照原样,无法调试。 我不熟悉您正在使用的工具包,但 PKCS#1 需要的不仅仅是 en 和 d(我最后还是检查了)。 PEM 真正在做的就是采用 PKCS#1 DER 编码、b64 编码并标记一些页眉和页脚。是否有可能在保存之前关键数据没有完全充实? @LucasHolt 我检查了文件指针。他们没有任何错误。但是,只有读取私钥的函数调用会导致错误。 @WhozCraig 我会调查的。但是,据我所知,RSA 对象只需要 n、e、d。休息可以为空。 openssl.org/docs/crypto/rsa.html#DESCRIPTION 因此,我假设它应该将对象写入文件(它确实如此)。它读回来,这是一个问题 【参考方案1】:RSA 密钥是对称的,您可以将它们中的任何一个用作私钥或公钥,这只是您的选择(但 DSA 密钥非对称)。下面的程序生成两个 2048 位长的 RSA 密钥,然后将它们保存到文件中并将它们读回内存。这应该让你知道如何去做。
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
const char* pcszPassphrase = "open sezamee";
static void gen_callback(int iWhat, int inPrime, void* pParam);
static void init_openssl(void);
static void cleanup_openssl(void);
static int passwd_callback(char *pcszBuff,int size,int rwflag, void *pPass);
static EVP_PKEY* create_rsa_key(void);
static void handle_openssl_error(void);
int main(int argc, char **argv)
int iRet = EXIT_SUCCESS;
EVP_PKEY* pPrivKey = NULL;
EVP_PKEY* pPubKey = NULL;
FILE* pFile = NULL;
const EVP_CIPHER* pCipher = NULL;
init_openssl();
pPrivKey = create_rsa_key();
pPubKey = create_rsa_key();
if(pPrivKey && pPubKey)
/* Save the keys */
if((pFile = fopen("privkey.pem","wt")) && (pCipher = EVP_aes_256_cbc()))
if(!PEM_write_PrivateKey(pFile,pPrivKey,pCipher,
(unsigned char*)pcszPassphrase,
(int)strlen(pcszPassphrase),NULL,NULL))
fprintf(stderr,"PEM_write_PrivateKey failed.\n");
handle_openssl_error();
iRet = EXIT_FAILURE;
fclose(pFile);
pFile = NULL;
if(iRet == EXIT_SUCCESS)
if((pFile = fopen("pubkey.pem","wt")) && PEM_write_PUBKEY(pFile,pPubKey))
fprintf(stderr,"Both keys saved.\n");
else
handle_openssl_error();
iRet = EXIT_FAILURE;
if(pFile)
fclose(pFile);
pFile = NULL;
else
fprintf(stderr,"Cannot create \"privkey.pem\".\n");
handle_openssl_error();
iRet = EXIT_FAILURE;
if(pFile)
fclose(pFile);
pFile = NULL;
if(iRet == EXIT_SUCCESS)
/* Read the keys */
EVP_PKEY_free(pPrivKey);
pPrivKey = NULL;
EVP_PKEY_free(pPubKey);
pPubKey = NULL;
if((pFile = fopen("privkey.pem","rt")) &&
(pPrivKey = PEM_read_PrivateKey(pFile,NULL,passwd_callback,(void*)pcszPassphrase)))
fprintf(stderr,"Private key read.\n");
else
fprintf(stderr,"Cannot read \"privkey.pem\".\n");
handle_openssl_error();
iRet = EXIT_FAILURE;
if(pFile)
fclose(pFile);
pFile = NULL;
if((pFile = fopen("pubkey.pem","rt")) &&
(pPubKey = PEM_read_PUBKEY(pFile,NULL,NULL,NULL)))
fprintf(stderr,"Public key read.\n");
else
fprintf(stderr,"Cannot read \"pubkey.pem\".\n");
handle_openssl_error();
iRet = EXIT_FAILURE;
if(pPrivKey)
EVP_PKEY_free(pPrivKey);
pPrivKey = NULL;
if(pPubKey)
EVP_PKEY_free(pPubKey);
pPubKey = NULL;
cleanup_openssl();
return iRet;
EVP_PKEY* create_rsa_key(void)
RSA *pRSA = NULL;
EVP_PKEY* pKey = NULL;
pRSA = RSA_generate_key(2048,RSA_3,gen_callback,NULL);
pKey = EVP_PKEY_new();
if(pRSA && pKey && EVP_PKEY_assign_RSA(pKey,pRSA))
/* pKey owns pRSA from now */
if(RSA_check_key(pRSA) <= 0)
fprintf(stderr,"RSA_check_key failed.\n");
handle_openssl_error();
EVP_PKEY_free(pKey);
pKey = NULL;
else
handle_openssl_error();
if(pRSA)
RSA_free(pRSA);
pRSA = NULL;
if(pKey)
EVP_PKEY_free(pKey);
pKey = NULL;
return pKey;
void gen_callback(int iWhat, int inPrime, void* pParam)
char c='*';
switch(iWhat)
case 0: c = '.'; break;
case 1: c = '+'; break;
case 2: c = '*'; break;
case 3: c = '\n'; break;
fprintf(stderr,"%c",c);
int passwd_callback(char *pcszBuff,int size,int rwflag, void *pPass)
size_t unPass = strlen((char*)pPass);
if(unPass > (size_t)size)
unPass = (size_t)size;
memcpy(pcszBuff, pPass, unPass);
return (int)unPass;
void init_openssl(void)
if(SSL_library_init())
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
RAND_load_file("/dev/urandom", 1024);
else
exit(EXIT_FAILURE);
void cleanup_openssl(void)
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_thread_state(0);
EVP_cleanup();
void handle_openssl_error(void)
ERR_print_errors_fp(stderr);
【讨论】:
HI @Sirgeorge 我已在我的应用程序中添加了此代码,但出现错误:“#includeRSA_generate_key
不应被调用两次。【参考方案2】:
sirgeorge 给出的答案在 Code 中有错误。
create_rsa_key
不应被调用两次。如果它被调用两次,那么私钥没有匹配的公钥。这会导致解密期间出现问题。
main
方法中需要修改
RSA *pRSA = NULL;
pRSA = RSA_generate_key(2048,RSA_3,gen_callback,NULL);
pPrivKey = create_rsa_key(pRSA);
pPubKey = create_rsa_key(pRSA);
create_rsa_key
中需要修改
EVP_PKEY* create_rsa_key(RSA *pRSA)
EVP_PKEY* pKey = NULL;
pKey = EVP_PKEY_new();
if(pRSA && pKey && EVP_PKEY_assign_RSA(pKey,pRSA))
/* pKey owns pRSA from now */
if(RSA_check_key(pRSA) <= 0)
fprintf(stderr,"RSA_check_key failed.\n");
handle_openssl_error();
EVP_PKEY_free(pKey);
pKey = NULL;
else
handle_openssl_error();
if(pRSA)
RSA_free(pRSA);
pRSA = NULL;
if(pKey)
EVP_PKEY_free(pKey);
pKey = NULL;
return pKey;
【讨论】:
好收获。我很惊讶一直没有人对此发表评论。 谢谢 jww .. 其实我在使用这段代码时偶然发现了这个问题 请编辑并删除“eEVP_PKEY* pKey = NULL;”中多余的'e' @Rndp13:已修复以上是关于在 C 中读取和写入 rsa 密钥到 pem 文件的主要内容,如果未能解决你的问题,请参考以下文章
OpenSSL笔记-生成RSA公私密钥以PEM格式到char*中(非保存为文件)
为啥我无法使用 PEM_read_RSAPublicKey 读取 openssl 生成的 RSA pub 密钥?
C# 将私有/公共 RSA 密钥从 RSACryptoServiceProvider 导出到 PEM 字符串
将 PEM RSA 密钥转换为 C# RSACryptoServiceProvider.FromXmlString 的 xml