今天心血来潮突然想搞搞openssl了,趁着端午小假,刚好有空可以鼓捣孤岛自己喜欢的东西,出去东奔西跑的实在太造孽了,还是宅起来给自己充充电吧。下载openssl最新代码1.0.1g,修复了“心血漏洞”那个版本。编译安装那些小儿科的东西就不再浪费笔墨了,如果出现头文件或者库文件之类的错误,请在本人博客里寻找相关文章,应该主要集中在动态库那几篇博文。反正我在自己虚拟机里安装的时候是妥妥滴。

因为我主要对非对称加密的RSA算法比较感兴趣,网上最多的就是这么用的:
   生成私钥文件(其中已经包含了公钥):

[root@localhost release]#openssl genrsa -out plainPrv.key 1024

然后再从这个私钥文件里将公钥提取出来,保存到文件里:

[root@localhost release]#openssl rsa -in plainPrv.key -pubout -out plainPub.key

RSA一般有两种应用场景:
   1、公钥加密、私钥解密:这是数据安全通信领域最常见情形;
   2、私钥加密、公钥解密:这主要用于数字签名。
   两种方式,一通百通,本文只看第一种场景。
  关于测试代码,网上到处都是,也都基本能用,我就先不摘抄了。大家问的最多的问题就是在读取公钥文件时,PEM_read_RSA_PUBKEY()函数和PEM_read_RSAPublicKEY()的疑惑。为什么读取私钥文件用的PEM_read_RSAPrivateKey(),针对上述openssl命令生成的公钥文件,在读取其内容时用对称的PEM_read_RSAPublicKEY()接口却会报错,必须要用PEM_read_RSA_PUBKEY()才可以。

其实,我们要是看看一两个文件内容就明白了:

[root@localhost release]# cat plainPrv.key
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDlGVxzTDVhnC16SW+D0WG8hvm1wztmr0vBh2VK6CU7k90mdrCx
4by1URcZ6iS6KxomxSqWmK9g2C0iRd8xx7OyykBHKttjIx5Diq3wLXDP2qU4mjSI
vHP3MwgrOR2Jwa4mNr1veM2c1pyXn5xIfZs2IFnicMugj+0sXik1pLWwIwIDAQAB
AoGBAKoB5OomfmJ92/2oKxmdsjKN0xY/13++y6/EgrVQifipJG5bm4mVI01F7Ket
ai3AuHpWy+DPUy3BndSWFyfAsyatULiK3cJnIZumxmWP8G9odfO1pH/KcZB2Vi61
HcbioDuJRCcF3jpbGMun3lCwkdG/qVfsFmOElbzSbNMDbwkJAkEA/K9mOSKrP+lu
6bsIuD6/n2XQkz8XE2lPuPwKhVLX+ljXqRyxJZH0n+2EC8pUi694Q2Zhgn0uPdEl
KCYtlBaLXQJBAOgawH01Xc0r63+XVif6rLZfwJGBAP8921e2dRDFYhYLP3riflY8
xvFQsh4n7kbAXt4xZ3pDA/J1INnE01Rk8X8CQCmzyOslDZ4+qE9qzsWZlYZ5BzNF
9kj92GpvLk1SntJyVyVR1uqcbAL48BICEnH7Q53cB7vBbSBGpBs8Mcl+7wECQQCF
Dbjkze/sys2ggd+44WGa1n8sqhgpOYuA1656I7ybyGzmg+pKg2LEOS8yTE+yrVp0
4ztfggVEO1LOo59F1Ov/AkEApfUtgKHB4YCPy70syFaQoAWjiaxOWq/FLM7FBntP
ikz1X7gNsRkb4I/be15ZN8E/2Z0Q95FOpsgqw76Bi4Yynw==
-----END RSA PRIVATE KEY-----

[root@localhost release]# cat plainPub.key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlGVxzTDVhnC16SW+D0WG8hvm1
wztmr0vBh2VK6CU7k90mdrCx4by1URcZ6iS6KxomxSqWmK9g2C0iRd8xx7OyykBH
KttjIx5Diq3wLXDP2qU4mjSIvHP3MwgrOR2Jwa4mNr1veM2c1pyXn5xIfZs2IFni
cMugj+0sXik1pLWwIwIDAQAB
-----END PUBLIC KEY-----

当我们在用PEM_read_RSAPublicKEY()读取公钥文件plainPub.key时报的错误是酱紫滴:

3077879432:error:0906D06C:lib(9):func(109):reason(108):pem_lib.c:698:Expecting: RSA PUBLIC KEY

所以我就天真地将公钥文件头和尾分别改成“-----BEGIN RSA PUBLIC KEY-----”和“-----BEGIN RSA PUBLIC KEY-----”,理想很丰满,显示很骨感。实践证明openssl是不能那么轻易就被忽悠过去的。没办法,查看openssl源码发现,提取公钥文件时除了-pubout参数可以设置外,还有有个参数叫做-RSAPublicKey_out,但是命令行提示和man手册里居然没有任何提及。幸好我还会读C代码,所以提取公钥时我改用下面的命令:

[root@localhost release]#openssl rsa -in plainPrv.key -RSAPublicKey_out -out plainPub.key

这样做完的结果是,首先公钥文件的内容有点变化:

[root@localhost test_openssl]# cat plainPub2.key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOUZXHNMNWGcLXpJb4PRYbyG+bXDO2avS8GHZUroJTuT3SZ2sLHhvLVR
FxnqJLorGibFKpaYr2DYLSJF3zHHs7LKQEcq22MjHkOKrfAtcM/apTiaNIi8c/cz
CCs5HYnBriY2vW94zZzWnJefnEh9mzYgWeJwy6CP7SxeKTWktbAjAgMBAAE=
-----END RSA PUBLIC KEY-----

[root@localhost release]# cat plainPub.key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlGVxzTDVhnC16SW+D0WG8hvm1
wztmr0vBh2VK6CU7k90mdrCx4by1URcZ6iS6KxomxSqWmK9g2C0iRd8xx7OyykBH
KttjIx5Diq3wLXDP2qU4mjSIvHP3MwgrOR2Jwa4mNr1veM2c1pyXn5xIfZs2IFni
cMugj+0sXik1pLWwIwIDAQAB
-----END PUBLIC KEY-----

其次,当我再用PEM_read_RSAPublicKEY()接口来读取公钥文件plainPub2.key时,居然成功了。说明RSA PUBLIC KEY和PUBLIC KEY的两种公钥文件其存储方式是不一样的,PEM_read_RSAPublicKEY()只能读取RSA PUBLIC KEY形式的公钥文件;而PEM_read_RSA_PUBKEY()只能读取PUBLIC KEY格式的公钥文件。由于本人密码学基础较薄弱,现在还不能说出两者的区别,请各位见谅,还望密码方面的大牛们予以点拨。演示代码如下:

点击(此处)折叠或打开

  1. /* filename: tmp.c
  2. */
  3. #includestdio.h>
  4. #includestdlib.h>
  5. #includestring.h>
  6. #includeopenssl/rsa.h>
  7. #includeopenssl/pem.h>
  8. #includeopenssl/err.h>
  9. void hexprint(char *str,int len)
  10. {
  11. int i=0;
  12. for(i=0;ilen;i++){
  13. printf("%s%02x%s",((i%16==0?"|":"")),*((unsigned char*)str+i),(((i+1)%16==0)?"|\n":" "));
  14. }
  15. if(i%16!=0)
  16. printf("|\n");
  17. }
  18. static int do_operation(RSA* rsa_ctx,char *instr,char* path_key,int inlen,char** outstr,int type)
  19. {
  20. if(rsa_ctx == NULL || instr == NULL || path_key == NULL)
  21. {
  22. perror("input elems error,please check them!");
  23. return -1;
  24. }
  25. int rsa_len,num;
  26. rsa_len=RSA_size(rsa_ctx);
  27. *outstr=(unsigned char *)malloc(rsa_len+1);
  28. memset(*outstr,0,rsa_len+1);
  29. switch(type){
  30. case 1: //pub enc
  31. if(inlen == 0){
  32. perror("input str len is zero!");
  33. goto err;
  34. }
  35. num = RSA_public_encrypt(inlen,(unsigned char *)instr,(unsigned char*)*outstr,rsa_ctx,RSA_PKCS1_OAEP_PADDING);
  36. break;
  37. case 2: //prv dec
  38. num = RSA_private_decrypt(inlen,(unsigned char *)instr,(unsigned char*)*outstr,rsa_ctx,RSA_PKCS1_OAEP_PADDING);
  39. default:
  40. break;
  41. }
  42. if(num == -1)
  43. {
  44. printf("Got error on enc/dec!\n");
  45. err:
  46. free(*outstr);
  47. *outstr = NULL;
  48. num = -1;
  49. }
  50. return num;
  51. }
  52. int rsa_pub_encrypt(char *str,char *path_key,char** outstr){
  53. RSA *p_rsa;
  54. FILE *file;
  55. int flen,rsa_len,num;
  56. if((file=fopen(path_key,"r"))==NULL){
  57. perror("open key file error");
  58. return -1;
  59. }
  60. #ifdef RSAPUBKEY
  61. if((p_rsa=PEM_read_RSA_PUBKEY(file,NULL,NULL,NULL))==NULL){
  62. #else
  63. if((p_rsa=PEM_read_RSAPublicKey(file,NULL,NULL,NULL))==NULL){
  64. #endif
  65. ERR_print_errors_fp(stdout);
  66. return -1;
  67. }
  68. num = do_operation(p_rsa,str,path_key,strlen(str),outstr,1);
  69. RSA_free(p_rsa);
  70. fclose(file);
  71. return num;
  72. }
  73. int rsa_prv_decrypt(char *str,char *path_key,int inlen,char** outstr){
  74. RSA *p_rsa;
  75. FILE *file;
  76. int rsa_len,num;
  77. if((file=fopen(path_key,"r"))==NULL){
  78. perror("open key file error");
  79. return -1;
  80. }
  81. if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
  82. ERR_print_errors_fp(stdout);
  83. return -1;
  84. }
  85. num = do_operation(p_rsa,str,path_key,inlen,outstr,2);
  86. RSA_free(p_rsa);
  87. fclose(file);
  88. return num;
  89. }
  90. int main(int argc,char** argv){
  91. char *ptr_en,*ptr_de;
  92. int len;
  93. printf("source is :%s\n",argv[1]);
  94. len=rsa_pub_encrypt(argv[1],argv[2],&ptr_en);
  95. printf("pubkey encrypt:\n");
  96. hexprint(ptr_en,len);
  97. rsa_prv_decrypt(ptr_en,argv[3],len,&ptr_de);
  98. printf("prvkey decrypt:%s\n",ptr_de==NULL?"NULL":ptr_de);
  99. if(ptr_en!=NULL){
  100. free(ptr_en);
  101. }
  102. if(ptr_de!=NULL){
  103. free(ptr_de);
  104. }
  105. return 0;
  106. }

如果开启RSAPUBKEY宏,则用PEM_read_RSA_PUBKEY()来读取公钥文件;否则用PEM_read_RSAPublicKey()读取:

[root@localhost release]#gcc -o pub rsatest.c -lcrypto -g -DRSAPUBKEY
[root@localhost release]#gcc -o nopub rsatest.c -lcrypto -g 

测试结果如下:

实际应用中,出于安全考虑我们一般会对私钥文件加密。我们可以用如下的方式来重新生成经3DES加密后私钥文件:

[root@localhost release]#openssl genrsa -des3 -out cipherPrv.key 1024

这样生成的私钥文件使用3DES加过密的,看看内容就晓得和之前的有什么不同了。头部多了一些信息:Proc-Type和DEK-Info,猜想这肯定是某种加密信息(这TM不废话么),但是我看不懂,现阶段“会用”是首要问题:

上述加密私钥文件的口令是123456,分别提取RSA PUBLIC KEY和PUBLIC KEY格式的公钥文件:

[root@localhost release]# openssl rsa -in cipherPrv.key -pubout -out cipherPub.key
[root@localhost release]# openssl rsa -in cipherPrv.key -RSAPublicKey_out -out cipherPub2.key

在代码中我们需要通过下面的方式来读取经3DES加密处理后的私钥文件:

点击(此处)折叠或打开

  1. RSA* getPRV(char *path_key_fullname,char* pwd)
  2. {
  3. RSA *rsaK=RSA_new();
  4. OpenSSL_add_all_algorithms();
  5. BIO *BP = BIO_new_file(path_key_fullname,"rb");
  6. if(NULL == BP)
  7. return NULL;
  8. rsaK=PEM_read_bio_RSAPrivateKey(BP,NULL,NULL,pwd);
  9. return rsaK;
  10. }

然后将tmp.c中第85行从:
   if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
   替换成:
   if((p_rsa=getPRV(path_key,"123456"))==NULL){
   重新编译,运行后结果如下:

关于openssl有很多值得学习的地方,空了再慢慢研究。

关于openssl几个API的一点小收获的更多相关文章

  1. 刚接触SkyLine的一点小收获与感触

    因为刚接触Skyline不到一个星期,也怕把学习到的忘记掉,所以写一点学习到的一些皮毛的东西,赶紧记录一下,怕回头忘记 1.网上关于web端的开发非常多,也有很多牛人分享自己的经验,所以学习起来也相对 ...

  2. 利用WordPress REST API 开发微信小程序从入门到放弃

    自从我发布并开源WordPress版微信小程序以来,很多WordPress网站的站长问有关程序开发的问题,其实在文章:<用微信小程序连接WordPress网站>讲述过一些基本的要点,不过仍 ...

  3. BUI Webapp用于项目中的一点小心得

    接触BUI也有一段时间,也用在了移动端的项目开发中,总的来说,该框架用起来也挺灵活的,控件可以自由定制,前提是自己能认真地学习该框架的api,因为api里面说的东西比较详细,如果没有仔细看的,可能有些 ...

  4. 快速掌握iOS API的一个小技巧

    快速掌握iOS API的一个小技巧 周银辉 iOS SDK和Developer Library中提供了各个类以及函数的帮助文档,这很棒,但要想了解整个库的大体结构(比如UIKit下有哪些类,他们的继承 ...

  5. 关于win8开发的一点小总结

    我今天做画面的时候,发现了一点小问题. 我在xmal文件里面加了一个CheckBox控件,设置IsChecked属性为True,并添加了Checked事件.Checked事件里面有对另外一个TextB ...

  6. 关于PHP魔术方法__call的一点小发现

    好久没有上博客园写文章了,今晚终于有点空了,就来写一下昨天的一点小发现. 我自己所知,C++,Java的面向对象都有多态的特点,而PHP没有,但PHP可以通过继承链方法的重写来实现多态的属性.而魔术方 ...

  7. 近日使用Taro框架的一点小心得

    1.yarn npm安装的包,跟权限问题有关,与网络也有关 2.Vue框架首先,是解决了view-model的问题,解放开发的双手,使得显示和数据和控制分开 3.当你觉得最近没有技术文章看时,就看收藏 ...

  8. net core体系-web应用程序-4net core2.0大白话带你入门-8asp.net core 内置DI容器(DependencyInjection,控制翻转)的一点小理解

    asp.net core 内置DI容器的一点小理解   DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IO ...

  9. C与C++在形參的一点小差别

    先看一下以下的代码: int fun(a,b) int a; int b; { return 10; } void main(int argc, char ** argv) { fun(10); re ...

随机推荐

  1. 修改APK包并push到system/app路径下安装

    在工作中,经常遇到需要修改apk包里的资源文件,达到检验不同配置下程序运行情况的目的. 过程如下: 1.首先连接手机,进入命令行,输入:adb root,使得adb获取root权限. 2.输入:adb ...

  2. 手持机(Android)开发应用总结

    对于首次接触android的我,刚接到android开发的命令时,自己完全不懂任何android技术,可是由于项目的开发时间周期很短,必须强迫自己即学即用,到了最后才发现,技术其实只是工具,重要的是一 ...

  3. NRF51822之IIC(MEMS_LIS2DH12)

    在上篇介绍了OLED的II以写操作为主,没有进行读取操作.所以在现再补充读取的操作. 我在此以LIS2DH为例子 uint8_t temp; lis2dh_read_registers(LIS2DH_ ...

  4. jQuery实现瀑布流

    瀑布流布局多用于加载图片,或者图片配上文字.视觉表现为参差不齐的多栏布局.随着页面滚动条向下滚动,还会不断加载数据块并附加至当前尾部.本文就来利用jQuery实现一个图片瀑布流的效果. 1.布局. 首 ...

  5. RHEL7/CentOS7中更改网卡默认名称

    1.重命名并修改网卡配置文件,将"NAME"参数更为我们熟悉的“eth*”,这里我将其改为"eth0" [root@localhost ~]# cd /etc/ ...

  6. python反射原理

    1.反射原理 通过字符串的形式导入模块: __import__(),可以以字符串的形式导入模块. 通过字符串的形式导入函数: 反射: 根据字符串去某个对象里面取东西,可以是字符串,函数,数字. 根据字 ...

  7. 在eclipse中启动tomcat加载不了项目的解决方法

    一.在server视图右键选择Add and Remove时,如果想要部署的项目不在左侧的待选列表中,或是弹出警告There are no resources that can be added or ...

  8. http://www.cnblogs.com/zhaoguihua/tag/%E9%AB%98%E6%80%A7%E8%83%BD%E7%BD%91%E7%AB%99/

    http://www.cnblogs.com/zhaoguihua/tag/%E9%AB%98%E6%80%A7%E8%83%BD%E7%BD%91%E7%AB%99/

  9. python求范数

    import numpy as npa=np.array([[complex(1,-1),3],[2,complex(1,1)]])  print(a)print("矩阵2的范数" ...

  10. springbootboot-HttpServletRequest.getInputStream() 获取post内容

    问题描述: 在php端用curl post一段json到java springboot.在java端用request.getInputStream()获取到的数据为空. 问题确认: 询问度娘后, 她告 ...