OpenSSL库的RSA使用(下)-rsa函数方式

来源:互联网 发布:update sql 所有数据 编辑:程序博客网 时间:2024/06/05 08:51

http://blog.csdn.net/fenghaibo00/article/details/17249493


3      RSA函数方式

3.1 步骤

i.             生成RSA的key,包括三部分:公钥指数、私钥指数和模数(这些需要先了解一下RSA算法的原理)

ii.             将这三个数存下来,其中私钥指数和模数比较大,都是大素数

iii.             构造RSA结构,可以构造公钥和私钥RSA结构

iv.             利用构造的RSA结构的指针进行<公钥加密-私钥解密>或者<私钥加密-公钥解密>(注意加解密用到的密钥类型,不能用同一密钥进行加密和解密)

3.2  代码

3.2.1 头文件代码

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef __OPENSSL_RSA_CODEC_H__    // rsa_op.h  
  2. #define __OPENSSL_RSA_CODEC_H__  
  3.   
  4. // 公钥指数  
  5. const unsigned char PUBLIC_EXPONENT_HEX[] =   
  6. {0x01, 0x00, 0x01};  
  7.   
  8. // 私钥指数  
  9. const unsigned char PRIVATE_EXPONENT_HEX[] =   
  10. {0x68, 0x4D, 0x32, 0xAA, 0xE1, 0x3B, 0x28, 0xEA, 0x96, 0x48, 0x9A, 0x52, 0xCF, 0xD4, 0x11, \  
  11. 0xBE, 0x8E, 0xC1, 0xC2, 0x36, 0xF2, 0x95, 0xB3, 0x66, 0x2E, 0x54, 0x49, 0xFD, 0xAE, 0xDC, \  
  12. 0x1D, 0x8E, 0x86, 0xAA, 0xAD, 0x60, 0x5E, 0x82, 0xCD, 0x99, 0xA9, 0x96, 0x64, 0xB0, 0x70, \  
  13. 0xA0, 0xC5, 0x3A, 0x78, 0x8B, 0x5F, 0x85, 0x7A, 0x31, 0x21, 0x95, 0xDD, 0xDC, 0x99, 0x0E, \  
  14. 0x88, 0x4E, 0xA1, 0x3D, 0x8B, 0xF8, 0x58, 0xA1, 0x7C, 0xE8, 0x8C, 0x37, 0xE1, 0x1D, 0x59, \  
  15. 0x76, 0x81, 0x48, 0xFC, 0xF0, 0x1C, 0x37, 0x5A, 0x39, 0x23, 0x05, 0xAB, 0xC1, 0x75, 0xC8, \  
  16. 0x7F, 0x7A, 0xA6, 0xB9, 0x25, 0x9D, 0x36, 0xE7, 0x9E, 0xC5, 0xCE, 0x32, 0x45, 0x34, 0xE2, \  
  17. 0xEC, 0xDF, 0xB1, 0xD1, 0x4D, 0xC9, 0x31, 0x55, 0xBA, 0x14, 0xB1, 0xD1, 0x09, 0x22, 0x69, \  
  18. 0xCF, 0x09, 0xB9, 0xF6, 0xB6, 0x68, 0xA1, 0x49};  
  19. // 模数  
  20. const unsigned char MODULES_HEX[] =   
  21. {0xD7, 0x42, 0xCC, 0x97, 0x4D, 0x35, 0x1A, 0x8F, 0xB3, 0xAA, 0x42, 0xAA, 0x6D, 0x10, 0xEB, \  
  22. 0x09, 0x58, 0xFA, 0xD2, 0xFB, 0x21, 0x0C, 0xDB, 0xBA, 0xB7, 0x22, 0x45, 0xE0, 0xF8, 0x1F, \  
  23. 0x40, 0x26, 0xFD, 0x00, 0xAF, 0x83, 0x1B, 0x5C, 0xE5, 0x68, 0x7B, 0x3F, 0x81, 0x21, 0x9E, \  
  24. 0xB4, 0x6B, 0x91, 0xCB, 0x5F, 0x2F, 0x6F, 0x18, 0xA6, 0x4B, 0xA0, 0x83, 0x33, 0x41, 0x7A, \  
  25. 0x75, 0xE3, 0x4B, 0xF1, 0x23, 0xCC, 0xA5, 0x76, 0xD0, 0x58, 0x8F, 0x87, 0xE6, 0x4C, 0x66, \  
  26. 0xB7, 0x83, 0x29, 0x16, 0xAE, 0x95, 0xE3, 0x76, 0x40, 0x0D, 0x54, 0xB8, 0x87, 0x0E, 0x8D, \  
  27. 0x66, 0x0E, 0x0E, 0x1D, 0xC4, 0x16, 0xFD, 0x4F, 0xFA, 0xC4, 0xB9, 0x89, 0x5D, 0x01, 0x2D, \  
  28. 0x86, 0x25, 0x44, 0x4B, 0x61, 0x31, 0xE2, 0xBD, 0x9A, 0xCD, 0x58, 0xE6, 0x6A, 0x94, 0xEC, \  
  29. 0x94, 0x77, 0x64, 0x50, 0x8C, 0x04, 0xE8, 0x3F};  
  30.   
  31. #define RSA_KEY_LENGTH 1024  
  32. static const char rnd_seed[] = "string to make the random number generator initialized";  
  33. class rsa_op  
  34. {  
  35. public:  
  36.     rsa_op();  
  37.     ~rsa_op();  
  38.   
  39.     // generate keys, usually no need to call it.  
  40.     int generate_key_str();  
  41.   
  42.     // init params  
  43.     int set_params(const unsigned char *pub_expd = PUBLIC_EXPONENT_HEX, int pub_expd_len = 3,   
  44.         const unsigned char *pri_expd = PRIVATE_EXPONENT_HEX, int pri_expd_len = 128,  
  45.         const unsigned char *module = MODULES_HEX, int module_len = 128);  
  46.   
  47.     // open keys  
  48.     int open_prikey_pubkey();  
  49.     int open_prikey();  
  50.     int open_pubkey();  
  51.   
  52.     // private key to encryption and public key to decryption  
  53.     int prikey_encrypt(const unsigned char *in, int in_len,  
  54.         unsigned char **out, int &out_len);  
  55.     int pubkey_decrypt(const unsigned char *in, int in_len,  
  56.         unsigned char **out, int &out_len);  
  57.     // public key to encryption and private key to decryption  
  58.     int pubkey_encrypt(const unsigned char *in, int in_len,  
  59.         unsigned char **out, int &out_len);  
  60. int prikey_decrypt(const unsigned char *in, int in_len,  
  61.         unsigned char **out, int &out_len);   
  62.   
  63.     int close_key();  
  64. protected:  
  65.     void free_res();  
  66.   
  67. private:  
  68.     RSA *_pub_key;  
  69.     RSA *_pri_key;  
  70.   
  71.     unsigned char *_pub_expd;  
  72.     unsigned char *_pri_expd;  
  73.     unsigned char *_module;  
  74.   
  75.     int _pub_expd_len;  
  76.     int _pri_expd_len;  
  77.     int _module_len;  
  78. };  
  79.   
  80. #endif  

3.2.2 实现文件代码

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>   // rsa_op.cpp  
  2. #include <string.h>  
  3. #include <openssl/evp.h>  
  4. #include <crypto/evp/evp_locl.h>  
  5. #include <openssl/rand.h>  
  6. #include <openssl/rsa.h>  
  7. #include <openssl/pem.h>  
  8. #include <openssl/err.h>  
  9. #include "rsa_op.h"  
  10.   
  11. rsa_op::rsa_op()  
  12. {  
  13.     _pub_key = NULL;  
  14.     _pri_key = NULL;  
  15.   
  16.     _pub_expd = NULL;  
  17.     _pri_expd = NULL;  
  18.     _module = NULL;  
  19. _pub_expd_len = 0;  
  20.     _pri_expd_len = 0;  
  21.     _module_len = 0;  
  22. }  
  23.   
  24. rsa_op::~rsa_op()  
  25. {  
  26.     close_key();  
  27.     free_res();  
  28. }  
  29.   
  30. // 生成密钥函数  
  31. int rsa_op::generate_key_str()  
  32. {  
  33.     RSA *r = NULL;    
  34.     int bits = RSA_KEY_LENGTH;   
  35.     unsigned long e = RSA_F4;  
  36.   
  37.     r = RSA_generate_key(bits, e, NULL, NULL);    
  38.       
  39.     // 用作显示  
  40.     RSA_print_fp(stdout, r, 11);  
  41.     FILE *fp = fopen("f:\\new_keys""w");  
  42.     if(NULL == fp)  
  43.     {  
  44.         return -1;  
  45.     }  
  46.       
  47.     RSA_print_fp(fp, r, 0);  
  48.     fclose(fp);  
  49.   
  50.     return 0;  
  51. }  
  52.   
  53. // 初始化参数  
  54. int rsa_op::set_params(const unsigned char *pub_expd, int pub_expd_len,   
  55.                        const unsigned char *pri_expd, int pri_expd_len,  
  56.                        const unsigned char *module,   int module_len)  
  57. {  
  58.     if(pub_expd)  
  59.     {  
  60.           
  61. _pub_expd_len = pub_expd_len;  
  62.         _pub_expd = new unsigned char[pub_expd_len];  
  63.         if(!_pub_expd)  
  64.         {  
  65.             free_res();  
  66.             return -1;  
  67.         }  
  68.   
  69.         memcpy(_pub_expd, pub_expd, _pub_expd_len);  
  70.     }  
  71.   
  72.     if(pri_expd)  
  73.     {  
  74.         _pri_expd_len = pri_expd_len;  
  75.         _pri_expd = new unsigned char[pri_expd_len];  
  76.         if(!_pri_expd)  
  77.         {  
  78.             free_res();  
  79.             return -1;  
  80.         }  
  81.   
  82.         memcpy(_pri_expd, pri_expd, pri_expd_len);  
  83.     }  
  84.   
  85.     if(module)  
  86.     {  
  87.         _module_len = module_len;  
  88.         _module = new unsigned char[module_len];  
  89.         if(!_module)  
  90.         {  
  91.             free_res();  
  92.             return -1;  
  93.         }  
  94.   
  95.         memcpy(_module, module, module_len);  
  96.     }  
  97.   
  98.     return 0;  
  99. }  
  100.   
  101. // 在一个key中同时打开公钥和私钥,该key既可用作公钥函数,也可用作私钥函数  
  102. int rsa_op::open_prikey_pubkey()  
  103. {  
  104. //构建RSA数据结构  
  105.     _pri_key = RSA_new();  
  106.     _pri_key->e = BN_bin2bn(_pub_expd, _pub_expd_len, _pri_key->e);  
  107.     _pri_key->d = BN_bin2bn(_pri_expd, _pri_expd_len, _pri_key->d);  
  108.     _pri_key->n = BN_bin2bn(_module, _module_len, _pri_key->n);  
  109.   
  110.     RSA_print_fp(stdout, _pri_key, 0);  
  111.   
  112.     return 0;  
  113. }  
  114.   
  115. // 打开私钥  
  116. int rsa_op::open_prikey()  
  117. {  
  118.     //构建RSA数据结构  
  119.     _pri_key = RSA_new();  
  120.     //_pri_key->e = BN_bin2bn(_pub_expd, _pub_expd_len, _pri_key->e);  
  121.     _pri_key->d = BN_bin2bn(_pri_expd, _pri_expd_len, _pri_key->d);  
  122.     _pri_key->n = BN_bin2bn(_module, _module_len, _pri_key->n);  
  123.   
  124.     return 0;  
  125. }  
  126. // 打开公钥  
  127. int rsa_op::open_pubkey()  
  128. {  
  129.     //构建RSA数据结构  
  130.     _pub_key = RSA_new();  
  131.     _pub_key->e = BN_bin2bn(_pub_expd, _pub_expd_len, _pub_key->e);  
  132.     //_pub_key->d = BN_bin2bn(_pri_expd, _pri_expd_len, _pub_key->d);  
  133.     _pub_key->n = BN_bin2bn(_module, _module_len, _pub_key->n);  
  134.   
  135.     RSA_print_fp(stdout, _pub_key, 0);  
  136.   
  137.     return 0;  
  138. }  
  139. // 私钥加密函数  
  140. int rsa_op::prikey_encrypt(const unsigned char *in, int in_len,  
  141.                    unsigned char **out, int &out_len)  
  142. {  
  143.     out_len =  RSA_size(_pri_key);  
  144.     *out =  (unsigned char *)malloc(out_len);  
  145.     if(NULL == *out)  
  146.     {  
  147.           
  148. printf("prikey_encrypt:malloc error!\n");  
  149.         return -1;  
  150.     }  
  151.     memset((void *)*out, 0, out_len);  
  152.   
  153.     printf("prikey_encrypt:Begin RSA_private_encrypt ...\n");  
  154.     int ret =  RSA_private_encrypt(in_len, in, *out, _pri_key, RSA_PKCS1_PADDING);  
  155.     //RSA_public_decrypt(flen, encData, decData, r,  RSA_NO_PADDING);  
  156.   
  157.     return ret;  
  158. }  
  159. // 公钥解密函数,返回解密后的数据长度  
  160. int rsa_op::pubkey_decrypt(const unsigned char *in, int in_len,  
  161.                            unsigned char **out, int &out_len)  
  162. {  
  163.     out_len =  RSA_size(_pub_key);  
  164.     *out =  (unsigned char *)malloc(out_len);  
  165.     if(NULL == *out)  
  166.     {  
  167.         printf("pubkey_decrypt:malloc error!\n");  
  168.         return -1;  
  169.     }  
  170.     memset((void *)*out, 0, out_len);  
  171.   
  172.     printf("pubkey_decrypt:Begin RSA_public_decrypt ...\n");  
  173.     int ret =  RSA_public_decrypt(in_len, in, *out, _pub_key, RSA_PKCS1_PADDING);  
  174.   
  175.     return ret;  
  176. }  
  177. // 公钥加密函数  
  178. int rsa_op::pubkey_encrypt(const unsigned char *in, int in_len,  
  179.                            unsigned char **out, int &out_len)  
  180. {  
  181.     out_len =  RSA_size(_pub_key);  
  182.     *out =  (unsigned char *)malloc(out_len);  
  183.     if(NULL == *out)  
  184. {  
  185.         printf("pubkey_encrypt:malloc error!\n");  
  186.         return -1;  
  187.     }  
  188. memset((void *)*out, 0, out_len);  
  189.   
  190.     printf("pubkey_encrypt:Begin RSA_public_encrypt ...\n");  
  191.     int ret =  RSA_public_encrypt(in_len, in, *out, _pub_key, RSA_PKCS1_PADDING/*RSA_NO_PADDING*/);  
  192.   
  193.   
  194.     return ret;  
  195. }  
  196.   
  197. // 私钥解密函数,返回解密后的长度  
  198. int rsa_op::prikey_decrypt(const unsigned char *in, int in_len,  
  199.                            unsigned char **out, int &out_len)  
  200. {  
  201.     out_len =  RSA_size(_pri_key);  
  202.     *out =  (unsigned char *)malloc(out_len);  
  203.     if(NULL == *out)  
  204.     {  
  205.         printf("prikey_decrypt:malloc error!\n");  
  206.         return -1;  
  207.     }  
  208.     memset((void *)*out, 0, out_len);  
  209.   
  210.     printf("prikey_decrypt:Begin RSA_private_decrypt ...\n");  
  211.     int ret =  RSA_private_decrypt(in_len, in, *out, _pri_key, RSA_PKCS1_PADDING);  
  212.   
  213.     return ret;  
  214. }  
  215.   
  216. // 释放分配的内存资源  
  217. void rsa_op::free_res()  
  218. {  
  219.     if(_pub_expd)  
  220.     {  
  221.         delete []_pub_expd;  
  222.         _pub_expd = NULL;  
  223.     }  
  224.   
  225.     if(_pri_expd)  
  226.     {  
  227.         delete []_pri_expd;  
  228.         _pri_expd = NULL;  
  229.     }  
  230. if(_module)  
  231.     {  
  232.         delete []_module;  
  233.         _module = NULL;  
  234.     }  
  235. }  
  236.   
  237. // 释放公钥和私钥结构资源  
  238. int rsa_op::close_key()  
  239. {  
  240.     if(_pub_key)  
  241.     {  
  242.         RSA_free(_pub_key);  
  243.         _pub_key = NULL;  
  244.     }  
  245.   
  246.     if(_pri_key)  
  247.     {  
  248.         RSA_free(_pri_key);  
  249.         _pri_key = NULL;  
  250.     }  
  251.   
  252.     return 0;  
  253. }  

3.2.3 测试代码

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>                   // main.cpp  
  2. #include <openssl/evp.h>  
  3. #include <crypto/evp/evp_locl.h>  
  4. #include <openssl/rand.h>  
  5. #include <openssl/rsa.h>  
  6. #include <openssl/pem.h>  
  7. #include "rsa_op.h"  
  8.   
  9.   
  10. #ifdef WIN32  
  11. #pragma comment(lib, "libeay32.lib")  
  12. #pragma comment(lib, "ssleay32.lib")  
  13. #endif  
  14. int main(int argc, char **argv)  
  15. {  
  16.     char origin_text[] = "hello world!";  
  17.   
  18.     // 由于采用RSA_PKCS1_PADDING方式,因此最大长度不要超过(即- 11)  
  19.     int origin_len = sizeof(origin_text);  
  20.     int enc_len = 0;  
  21.     int dec_len = 0;  
  22.     unsigned char *enc_data = NULL;  
  23.     unsigned char *dec_data = NULL;  
  24.   
  25.     rsa_op ro;  
  26.     // 下面是重新生成key的代码,一般不需要  
  27.     // ro.generate_key_str();  
  28.   
  29.     ro.set_params();  
  30.     ro.open_prikey_pubkey();  
  31.     ro.open_pubkey();  
  32.   
  33.     // 下面两行是私钥加密,公钥解密  
  34.     ro.prikey_encrypt((const unsigned char *)origin_text, origin_len, (unsigned char **)&enc_data, enc_len);  
  35.     ro.pubkey_decrypt(enc_data, enc_len, (unsigned char **)&dec_data, dec_len);  
  36.   
  37.     // 下面两行是公钥加密,私钥解密  
  38.     //ro.pubkey_encrypt((const unsigned char *)origin_text, origin_len, (unsigned char **)&enc_data, enc_len);  
  39.     //ro.prikey_decrypt(enc_data, enc_len, (unsigned char **)&dec_data, dec_len);  
  40.   
  41.     delete []enc_data;  
  42.     delete []dec_data;  
  43.   
  44.     return 0;  
  45. }  

3.2.4 生成新密钥

在网上的Demo程序中,基本上都是固定的私钥指数和模数,没有写如何生成新的私钥指数和模数。在实际的使用中,不可能使用别人的私钥指数和模数,否则加密就成了空摆设。在该源代码中,使用rsa_op类generate_key_str函数可生成新的密钥参数,可打印到文件中,也可打印到标准输出stdout中。如下图:


将图中modules的值替换到MODULES_HEX变量的定义,privateExponent的值替换到PRIVATE_EXPONENT_HEX的定义,公钥指数不需要替换。

注意:有时候RSA_print_fp会在一个值前多打印一个00,在替换的时候不要这个00。

3.2.5 注意事项

Win32下注意添加链接时的lib文件,运行时需要相应的dll文件,需添加的lib文件:“libeay32.lib”和“ssleay32.lib”,运行需使用的dll文件:“libeay32.dll”和“ssleay32.dll”。

4. 问题整理

1.      RSA_print_fp在VS2005下导致程序退出

原因:在VS2005中,如果链接的运行库是MDD库(Multi-threaded Debug DLL),该问题就会出现,VS2005默认Debug版本链接MDD库。

解决方法:将程序属性设置中链接运行库改为MD(Multi-threaded DLL),如下图:


2.      使用RSA_NO_PADDING方式公钥加密时,源数据的第一个字节值不能大于等于0xC9,第二个字节值不能大于等于0x90,否则会失败。具体原因未找到,以下是测试的源数据:

unsigned char test[] = {0xD2, 0x90, 0x02};

在RSA的man页上也有说明,新的程序不应该使用RSA_NO_PADDING方式加密。

解决方法:使用RSA_PKCS1_PADDING方式加密解密。



0 0
原创粉丝点击