openssl从内存中读取RSA公钥
2014-04-12 15:10
260 查看
背景:近期需要在项目中进行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);
在使用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);
相关文章推荐
- openssl——从内存中读取RSA公钥并加密 以及 "PRNG not seeded" error message 的解决办法
- openssl RSA 内存读取密钥
- 使用Qt调用openssl 从内存中读取私钥对RSA密文进行解密
- openssl RSA 内存读取密钥
- MediaPlayer读取手机内存文件夹权限问题
- ARM内存读取与MMU
- (原)解决精伦iDR200 SDK在.NET开发环境中提示"尝试读取或写入受保护的内存"错误
- asp.net报错“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的解决办法
- 内存不能正确读取
- 用内存映射读取大文件
- C#尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
- 内存jpeg文件读取程序
- 通过SharedPreferences 把list数据放在内存,和读取list数据
- 67.文件映射为内存进行操作与多线程 以及 文件映射到内存根据索引进行内存来实现读取多线程操作
- 读取内存数据问题
- java读取excel数据,导致内存泄露的问题
- 读取任意进程内存
- [Win32]一个调试器的实现(四)读取寄存器和内存
- 编写一个业务函数,实现按行读取文件。把内容按照第三种内存模型打包数据传出,把行数通过函数参数传出。