关于openssl加解密文件的几个API

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

因为我主要对非对称加密的RSA算法比较感兴趣,网上最多的就是这么用的:

生成私钥文件(其中已经包含了公钥):

[[email protected] release]#openssl genrsa -out plainPrv.key 1024

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

[[email protected] 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()才可以。

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

[[email protected] 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-----

[[email protected] 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代码,所以提取公钥时我改用下面的命令:

[[email protected] release]#openssl rsa -in plainPrv.key
-RSAPublicKey_out -out plainPub.key

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

[[email protected] test_openssl]# cat plainPub2.key

-----BEGIN RSA PUBLIC KEY-----

MIGJAoGBAOUZXHNMNWGcLXpJb4PRYbyG+bXDO2avS8GHZUroJTuT3SZ2sLHhvLVR

FxnqJLorGibFKpaYr2DYLSJF3zHHs7LKQEcq22MjHkOKrfAtcM/apTiaNIi8c/cz

CCs5HYnBriY2vW94zZzWnJefnEh9mzYgWeJwy6CP7SxeKTWktbAjAgMBAAE=

-----END RSA PUBLIC KEY-----

[[email protected]
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. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<openssl/rsa.h>
  7. #include<openssl/pem.h>
  8. #include<openssl/err.h>
  9. void hexprint(char
    *str,int
    len)
  10. {
  11. int i=0;
  12. for(i=0;i<len;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()读取:

[[email protected] release]#gcc -o pub rsatest.c -lcrypto -g -DRSAPUBKEY

[[email protected] release]#gcc -o nopub rsatest.c -lcrypto -g 

测试结果如下:

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

[[email protected] release]#openssl genrsa -des3 -out cipherPrv.key 1024

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

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

[[email protected] release]# openssl rsa -in cipherPrv.key -pubout -out cipherPub.key

[[email protected] 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有很多值得学习的地方,空了再慢慢研究。

时间: 2024-10-25 19:24:14

关于openssl加解密文件的几个API的相关文章

openssl加解密原理及私有CA的建立

一.openssl加解密原理 数据加密解密过程数据加密需要实现的功能:数据私密性,数据完整性,身份认证和秘钥交换. 美国NIST,为了计算机的安全,提出了几个要求: 1.数据保密性   数据保密性   隐私性 2.完整性    数据完整性   系统完整性 3.可用性 4.真实性 && 可追溯性 OSI:x.800  安全攻击:   被动攻击:窃听   主动攻击:伪装.重播.消息修改.拒绝服务  安全机制:   加密.数字签名.访问控制.数据完整性.认证交换.流量填充.路由控制.公证  安全

(8) openssl rsautl(签名/验证签名/加解密文件)和openssl pkeyutl(文件的非对称加密)

rsautl是rsa的工具,相当于rsa.dgst的部分功能集合,可用于生成数字签名.验证数字签名.加密和解密文件. pkeyutl是非对称加密的通用工具,大体上和rsautl的用法差不多,所以此处只解释rsautl. openssl rsautl [-in file] [-out file] [-inkey file] [-pubin] [-certin] [-passin arg] [-sign] [-verify] [-encrypt] [-decrypt] [-hexdump] open

openssl 加解密学习笔记

首先最近接到一个项目,这个项目中需要用到RSA的加密解密,因为之前没有接触过,在网上找了些资料,然后自己测试后发现其实使用openssl来进行加解密挺简单的,但是网上百度出来的很多又是一样的,有时候帮助不是很大,所以才想要写下来自己在搞整个加密过程遇到的一些问题,方便自己以后回头查看,也可能会帮到遇到同样的童鞋. 废话不多说,我接到的这个项目呢,有几个地方是需要用到RSA的加解密.1.使用.pfx格式的私钥签名.2.使用.cer的公钥文件进行加密操作.3.使用给定的指数与模进行公钥加密.下面有些

curses-键盘编码-openssl加解密【转】

本文转载自;https://zhuanlan.zhihu.com/p/26164115 1.1 键盘编码 按键过程:当用户按下某个键时, 1.键盘会检测到这个动作,并通过键盘控制器把扫描码(scan code)传送到计算机:键盘扫描码跟具体的硬件有关的,不同厂商对同一个键的扫描码有可能不同.2.计算机接收到扫描码后,将其交给键盘驱动程序:3.键盘驱动程序把这个扫描码转换为键盘虚拟码:虚拟码与具体硬件无关,不同厂商的键盘,同一个键的虚拟码总是相同的.然后,键盘驱动程序把该键盘操作的扫描码和虚拟码以

vim 命令加解密文件

加密文件 vim file :X  (大写X,是加密 ,小写x是保存) 输入密码: 确认密码: 解除密码: vim file :set key= :wq 命令模式下,输入 /word 后回车,即查找word,按 n 查找下一个匹配单词,按 N 查找上一个匹配单词.

PHP 基础篇 - PHP 中 DES 加解密详解

一.简介 DES 是对称性加密里面常见一种,全称为 Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法.密钥长度是64位(bit),超过位数密钥被忽略.所谓对称性加密即加密和解密密钥相同,对称性加密一般会按照固定长度,把待加密字符串分成块,不足一整块或者刚好最后有特殊填充字符. 跨语言做 DES 加密解密经常会出现问题,往往是填充方式不对.编码不一致或者加密解密模式没有对应上造成.常见的填充模式有: pkcs5.pkcs7.iso10126.ansix9

openssl - rsa加解密例程

原文链接: http://www.cnblogs.com/cswuyg/p/3187462.html openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加密:公钥加密,私钥解密.openssl提供了对RSA的支持,但RSA存在计算效率低的问题,所以一般的做法是使用对称密钥加密数据,然后再把这个只在当前有效的临时生成的对称密钥用非对称密钥的公钥加密之后传递给目标方,目标方使用约定好的非对称密钥中的私钥解开,得到数据加密的密钥,再进行数据解密,得到数据,

Android jni aes加解密,实现文件的加解密,具体实现可以自行修改,上面的代码为简单介绍,下面的是JNI端实现文件加解密,可以修改为字符串加解密

#include "aes.h" #include "modes.h" #include "e_os2.h" #include "aes_locl.h" #include "opensslconf.h" AES_KEY aes; //aes cbc模式加解密用到的向量 unsigned char iv[AES_BLOCK_SIZE]; for (i = 0; i < AES_BLOCK_SIZE; i

Openssl aes加解密例程 更进一步

原文链接: http://blog.csdn.net/itmes/article/details/7718427 前面我们用openssl的aes256对称加密算法对16个字节的内存块进行了的加解密运算测试,现在更进一步,对指定大小的内存块进行加解密运算. 首先明确一下aes是分组加密算法,且每次加密的内存块是16个字节,所以,我们需要加密的内存块必须是16个字节的整数倍,若不是,则需要进行补齐. 常见的对称加解密算法中rc2,rc4都是流加密,也就是以字节为单位进行加解密,而aes,des,3