openssl从内存中读取RSA公钥

背景:近期需要在项目中进行RSA签名验证,厂商会给出pem格式的RSA公钥。在以往项目中使用openssl读取RSA公钥时基本都是从pem文件中读取,基本没什么问题,可最近由于项目需要需要从数据库中读取RSA公钥,经查资料发现openssl提供了bio接口以支持各种形式的秘钥读取。

在使用bio接口从内存中读取pem格式的公钥时,总是读取公钥失败,经不断查找资料,发现在我们得到base64编码的RSA公钥后,从内存中读取这个公钥时要注意以下几点:

(1)公钥字符串开头要加上“-----BEGIN PUBLIC KEY-----\n”,结尾加上“\n-----END PUBLIC KEY-----\n”。否则会出现error:0906D06C:PEM routines:PEM_read_bio:no start line

(2)公钥字符串每隔64个字符要加一个换行,否则会报秘钥格式错误。

c++代码实现举例:

int nPublicKeyLen = strPublicKey.size();      //strPublicKey为base64编码的公钥字符串
for(int i = 64; i < nPublicKeyLen; i+=64)
{
if(strPublicKey[i] != '\n')
{
strPublicKey.insert(i, "\n");
}
i++;
}
strPublicKey.insert(0, "-----BEGIN PUBLIC KEY-----\n");
strPublicKey.append("\n-----END PUBLIC KEY-----\n");

BIO *bio = NULL; 
RSA *rsa = NULL; 
char *chPublicKey = const_cast(strPublicKey.c_str());
if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL)       //从字符串读取RSA公钥
{     
        cout<<"BIO_new_mem_buf failed!"< }       
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);   //从bio结构中得到rsa结构
if (!rsa)
 {
        ERR_load_crypto_strings();
        char errBuf[512];
        ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf));
        cout<< "load public key failed["<BIO_free_all(bio);
 }

由于使用RSA_vefify函数未能成功验证签名,改为使用evp相关函数进行签名验证。下面贴上使用公钥进行签名验证的代码:

string strBase64DecodedSig = base64_decode(strSignature);                //strSignature为签名
char *chInAppDataSignature = const_cast(strBase64DecodedSig.c_str());   //签名先进行base64解码
int result = 0;
char *chInAppData = const_cast(strUnsignedData.c_str());         //strUnsignedData为原始数据,即未加密数据
EVP_PKEY *evpKey = NULL;
EVP_MD_CTX ctx;
evpKey = EVP_PKEY_new();
if(evpKey == NULL)
{
        cout<<"error EVP_PEKY_new"<         RSA_free(rsa);
BIO_free_all(bio);return;
 }
 if((result = EVP_PKEY_set1_RSA(evpKey,rsa)) != 1)
{
        cout<<"error EVP_PKEY_set1_RSA"<         RSA_free(rsa);
        EVP_PKEY_free(evpKey);
BIO_free_all(bio);return;
 }
 EVP_MD_CTX_init(&ctx);
 if(result == 1 && (result = EVP_VerifyInit_ex(&ctx, EVP_sha1(), NULL)) != 1)
{       
        cout<<"error EVP_VerfyInit_ex"<  }
 if(result == 1 && (result = EVP_VerifyUpdate(&ctx, chInAppData,strUnsignedData.size())) != 1)
{
cout<<"error EVP_VerifyUpdate"< }
 if(result == 1 && (result = EVP_VerifyFinal(&ctx, (unsigned char *)chInAppDataSignature, strBase64DecodedSig.size(), evpKey)) != 1)
{
cout<<"error EVP_VerifyFinal"< }
if(result == 1)
{
cout<<"Verify success"< }
else
{
ERR_load_crypto_strings(); 
char errBuf[512]; 
ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf)); 
cout<<"verify failed["< }
EVP_MD_CTX_cleanup(&ctx);
RSA_free(rsa);
EVP_PKEY_free(evpKey);
BIO_free_all(bio);

你可能感兴趣的:(openssl,系统开发,C++)