我正在编写一个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(在上面的代码中有注释)编写。但是,两者都失败了。我不明白为什么会发生这种情况,或者尝试找到在哪里调试这个问题。有人能为此提供一些建议吗?
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);
}
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;
}