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<char *>(strPublicKey.c_str());
if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL)       //從字符串讀取RSA公鑰
{     
        cout<<"BIO_new_mem_buf failed!"<<endl;      
}       
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["<<errBuf<<"]"<<endl;
BIO_free_all(bio);
 }

由於使用RSA_vefify函數未能成功驗證簽名,改爲使用evp相關函數進行簽名驗證。下面貼上使用公鑰進行簽名驗證的代碼:

string strBase64DecodedSig = base64_decode(strSignature);                //strSignature爲簽名
char *chInAppDataSignature = const_cast<char *>(strBase64DecodedSig.c_str());   //簽名先進行base64解碼
int result = 0;
char *chInAppData = const_cast<char *>(strUnsignedData.c_str());         //strUnsignedData爲原始數據,即未加密數據
EVP_PKEY *evpKey = NULL;
EVP_MD_CTX ctx;
evpKey = EVP_PKEY_new();
if(evpKey == NULL)
{
        cout<<"error EVP_PEKY_new"<<endl;
        RSA_free(rsa);
BIO_free_all(bio);return;
 }
 if((result = EVP_PKEY_set1_RSA(evpKey,rsa)) != 1)
{
        cout<<"error EVP_PKEY_set1_RSA"<<endl;
        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"<<endl;
 }
 if(result == 1 && (result = EVP_VerifyUpdate(&ctx, chInAppData,strUnsignedData.size())) != 1)
{
cout<<"error EVP_VerifyUpdate"<<endl;
}
 if(result == 1 && (result = EVP_VerifyFinal(&ctx, (unsigned char *)chInAppDataSignature, strBase64DecodedSig.size(), evpKey)) != 1)
{
cout<<"error EVP_VerifyFinal"<<endl;
}
if(result == 1)
{
cout<<"Verify success"<<endl;
}
else
{
ERR_load_crypto_strings(); 
char errBuf[512]; 
ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf)); 
cout<<"verify failed["<<errBuf<<"]"<<endl;
}
EVP_MD_CTX_cleanup(&ctx);
RSA_free(rsa);
EVP_PKEY_free(evpKey);
BIO_free_all(bio);

發佈了86 篇原創文章 · 獲贊 23 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章