最近一个项目中需要使用非对称加密算法rsa对通信数据进行加密操作,加密过程中需要用到公钥证书。接口方提供了keytool生成的公钥证书,而我方在linux下使用openssl对公钥证书进行操作并加密。由于之前很少接触这方面的内容,在处理此业务的过程中走了不少弯路,在此将过程记录下来。
一、证书格式
对方提供的公钥证书是用keytool生成的cer格式证书,这是个二进制文件,完全不知道如何使用。因此拿到证书后,先补充了部分基础知识:
二、尝试过程
在了解到cer证书是java特有格式后,于是想将cer格式证书转化为pem格式证书:
openssl x509 -inform DER -in ca.cer -outform PEM -out ca.pem
格式转化完毕之后,得到证书文件,内容如下:
—–BEGIN CERTIFICATE—–
MIIDJjCCAg6gA….
—–END CERTIFICATE—–
于是使用PEM_read_RSA_PUBKEY函数读取证书文件,却报错:
error:0906D06C:PEM routines:PEM_read_bio:no start line
分析问题,发现刚才转换后得到的ca.pem是数字证书文件其文件头是—–BEGIN CERTIFICATE—–,而不是—–BEGIN PUBLIC KEY—–。因此继续从证书角度查找分析问题。最后找到从数字证书文件中提取公钥的方法:
openssl x509 -in p.pem -noout -pubkey > pubkey.pem
于是,得到了以—–BEGIN PUBLIC KEY—–开头的公钥文件,问题解决。
三、部分代码
FILE *fp;
if ((fp = fopen("pubkey.pem", "r")) == NULL)
{
printf("load pem failed!\n");
return -1;
}
rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);//使用SubjectPublicKeyInfo结构标准对RSA公钥进行编码操作,如果公钥类型不是RSA,就出错返回失败信息。
//rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);//使用PKCS#1 RSAPublicKey结构标准对RSA公钥进行编码操作。
if (rsa == NULL)
{
ERR_error_string(ERR_get_error(), errinfo);
printf("读取公钥失败!%s\n", errinfo);
return -1;
}
//加密
int ret = RSA_public_encrypt(strlen(from), (unsigned char *)from, (unsigned char *)to, rsa, RSA_PKCS1_PADDING);
if (ret <= 0)
{
ERR_error_string(ERR_get_error(), errinfo);
printf("RSA_public_encrypt fail!%s\n", errinfo);
return -1;
}
printf("RSA_public_encrypt 成功\n");
RSA_free(rsa);
fclose(fp);
代码片段有部分省略,应注意RSA_public_encrypt函数的第1个和第5个参数的使用。
四、总结
- 基础知识掌握的不好,对证书,rsa算法,openssl,keytool等知识的欠缺,导致问题解决较慢;
- 感谢各位前辈的知识分享,从网上搜索到了大堆有用的信息,但要有删选和甄别的能力;
解决问题要有明确思路。在解决问题过程中数次出现卡壳的情况,其实是没有思路了。一条路走不通,再走另一条路,不要多种方法、思路一起上;
这篇文章仅仅用作处理问题过程的记录,如有错误,请指教!