• C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)


    openssl里面有很多用于摘要哈希、加密解密的算法,方便集成于工程项目,被广泛应用于网络报文中的安全传输和认证。下面以md5,sha256,des,rsa几个典型的api简单使用作为例子。

    算法介绍

    md5:https://en.wikipedia.org/wiki/MD5

    sha256:https://en.wikipedia.org/wiki/SHA-2

    des: https://en.wikipedia.org/wiki/Data_Encryption_Standard

    rsa: https://en.wikipedia.org/wiki/RSA_(cryptosystem)

    工程配置

    以windows下为例

    1. 编译openssl库,得到头文件include和链接库lib和dll
    2. 配置包含头文件目录和库目录
    3. 工程中设置链接指定的lib:fenbieshlibssl.lib,libcrypto.lib
    4. 将对应的dll拷贝到exe执行目录:libcrypto-1_1.dll, libssl-1_1.dll
    linux下同理

    代码

    [cpp] view plain copy
     
     print?
    1. #include <iostream>    
    2. #include <cassert>  
    3. #include <string>    
    4. #include <vector>    
    5. #include "openssl/md5.h"    
    6. #include "openssl/sha.h"    
    7. #include "openssl/des.h"    
    8. #include "openssl/rsa.h"    
    9. #include "openssl/pem.h"    
    10.   
    11. // ---- md5摘要哈希 ---- //    
    12. void md5(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)  
    13. {  
    14.     // 调用md5哈希    
    15.     unsigned char mdStr[33] = {0};  
    16.     MD5((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);  
    17.   
    18.     // 哈希后的字符串    
    19.     encodedStr = std::string((const char *)mdStr);  
    20.     // 哈希后的十六进制串 32字节    
    21.     char buf[65] = {0};  
    22.     char tmp[3] = {0};  
    23.     for (int i = 0; i < 32; i++)  
    24.     {  
    25.         sprintf(tmp, "%02x", mdStr[i]);  
    26.         strcat(buf, tmp);  
    27.     }  
    28.     buf[32] = ''; // 后面都是0,从32字节截断    
    29.     encodedHexStr = std::string(buf);  
    30. }  
    31.   
    32. // ---- sha256摘要哈希 ---- //    
    33. void sha256(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)  
    34. {  
    35.     // 调用sha256哈希    
    36.     unsigned char mdStr[33] = {0};  
    37.     SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);  
    38.   
    39.     // 哈希后的字符串    
    40.     encodedStr = std::string((const char *)mdStr);  
    41.     // 哈希后的十六进制串 32字节    
    42.     char buf[65] = {0};  
    43.     char tmp[3] = {0};  
    44.     for (int i = 0; i < 32; i++)  
    45.     {  
    46.         sprintf(tmp, "%02x", mdStr[i]);  
    47.         strcat(buf, tmp);  
    48.     }  
    49.     buf[32] = ''; // 后面都是0,从32字节截断    
    50.     encodedHexStr = std::string(buf);  
    51. }  
    52.   
    53. // ---- des对称加解密 ---- //    
    54. // 加密 ecb模式    
    55. std::string des_encrypt(const std::string &clearText, const std::string &key)  
    56. {  
    57.     std::string cipherText; // 密文    
    58.   
    59.     DES_cblock keyEncrypt;  
    60.     memset(keyEncrypt, 0, 8);  
    61.   
    62.     // 构造补齐后的密钥    
    63.     if (key.length() <= 8)  
    64.         memcpy(keyEncrypt, key.c_str(), key.length());  
    65.     else  
    66.         memcpy(keyEncrypt, key.c_str(), 8);  
    67.   
    68.     // 密钥置换    
    69.     DES_key_schedule keySchedule;  
    70.     DES_set_key_unchecked(&keyEncrypt, &keySchedule);  
    71.   
    72.     // 循环加密,每8字节一次    
    73.     const_DES_cblock inputText;  
    74.     DES_cblock outputText;  
    75.     std::vector<unsigned char> vecCiphertext;  
    76.     unsigned char tmp[8];  
    77.   
    78.     for (int i = 0; i < clearText.length() / 8; i++)  
    79.     {  
    80.         memcpy(inputText, clearText.c_str() + i * 8, 8);  
    81.         DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);  
    82.         memcpy(tmp, outputText, 8);  
    83.   
    84.         for (int j = 0; j < 8; j++)  
    85.             vecCiphertext.push_back(tmp[j]);  
    86.     }  
    87.   
    88.     if (clearText.length() % 8 != 0)  
    89.     {  
    90.         int tmp1 = clearText.length() / 8 * 8;  
    91.         int tmp2 = clearText.length() - tmp1;  
    92.         memset(inputText, 0, 8);  
    93.         memcpy(inputText, clearText.c_str() + tmp1, tmp2);  
    94.         // 加密函数    
    95.         DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);  
    96.         memcpy(tmp, outputText, 8);  
    97.   
    98.         for (int j = 0; j < 8; j++)  
    99.             vecCiphertext.push_back(tmp[j]);  
    100.     }  
    101.   
    102.     cipherText.clear();  
    103.     cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());  
    104.   
    105.     return cipherText;  
    106. }  
    107.   
    108. // 解密 ecb模式    
    109. std::string des_decrypt(const std::string &cipherText, const std::string &key)  
    110. {  
    111.     std::string clearText; // 明文    
    112.   
    113.     DES_cblock keyEncrypt;  
    114.     memset(keyEncrypt, 0, 8);  
    115.   
    116.     if (key.length() <= 8)  
    117.         memcpy(keyEncrypt, key.c_str(), key.length());  
    118.     else  
    119.         memcpy(keyEncrypt, key.c_str(), 8);  
    120.   
    121.     DES_key_schedule keySchedule;  
    122.     DES_set_key_unchecked(&keyEncrypt, &keySchedule);  
    123.   
    124.     const_DES_cblock inputText;  
    125.     DES_cblock outputText;  
    126.     std::vector<unsigned char> vecCleartext;  
    127.     unsigned char tmp[8];  
    128.   
    129.     for (int i = 0; i < cipherText.length() / 8; i++)  
    130.     {  
    131.         memcpy(inputText, cipherText.c_str() + i * 8, 8);  
    132.         DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);  
    133.         memcpy(tmp, outputText, 8);  
    134.   
    135.         for (int j = 0; j < 8; j++)  
    136.             vecCleartext.push_back(tmp[j]);  
    137.     }  
    138.   
    139.     if (cipherText.length() % 8 != 0)  
    140.     {  
    141.         int tmp1 = cipherText.length() / 8 * 8;  
    142.         int tmp2 = cipherText.length() - tmp1;  
    143.         memset(inputText, 0, 8);  
    144.         memcpy(inputText, cipherText.c_str() + tmp1, tmp2);  
    145.         // 解密函数    
    146.         DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);  
    147.         memcpy(tmp, outputText, 8);  
    148.   
    149.         for (int j = 0; j < 8; j++)  
    150.             vecCleartext.push_back(tmp[j]);  
    151.     }  
    152.   
    153.     clearText.clear();  
    154.     clearText.assign(vecCleartext.begin(), vecCleartext.end());  
    155.   
    156.     return clearText;  
    157. }  
    158.   
    159.   
    160. // ---- rsa非对称加解密 ---- //    
    161. #define KEY_LENGTH  2048               // 密钥长度  
    162. #define PUB_KEY_FILE "pubkey.pem"    // 公钥路径  
    163. #define PRI_KEY_FILE "prikey.pem"    // 私钥路径  
    164.   
    165. // 函数方法生成密钥对   
    166. void generateRSAKey(std::string strKey[2])  
    167. {  
    168.     // 公私密钥对    
    169.     size_t pri_len;  
    170.     size_t pub_len;  
    171.     char *pri_key = NULL;  
    172.     char *pub_key = NULL;  
    173.   
    174.     // 生成密钥对    
    175.     RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);  
    176.   
    177.     BIO *pri = BIO_new(BIO_s_mem());  
    178.     BIO *pub = BIO_new(BIO_s_mem());  
    179.   
    180.     PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);  
    181.     PEM_write_bio_RSAPublicKey(pub, keypair);  
    182.   
    183.     // 获取长度    
    184.     pri_len = BIO_pending(pri);  
    185.     pub_len = BIO_pending(pub);  
    186.   
    187.     // 密钥对读取到字符串    
    188.     pri_key = (char *)malloc(pri_len + 1);  
    189.     pub_key = (char *)malloc(pub_len + 1);  
    190.   
    191.     BIO_read(pri, pri_key, pri_len);  
    192.     BIO_read(pub, pub_key, pub_len);  
    193.   
    194.     pri_key[pri_len] = '';  
    195.     pub_key[pub_len] = '';  
    196.   
    197.     // 存储密钥对    
    198.     strKey[0] = pub_key;  
    199.     strKey[1] = pri_key;  
    200.   
    201.     // 存储到磁盘(这种方式存储的是begin rsa public key/ begin rsa private key开头的)  
    202.     FILE *pubFile = fopen(PUB_KEY_FILE, "w");  
    203.     if (pubFile == NULL)  
    204.     {  
    205.         assert(false);  
    206.         return;  
    207.     }  
    208.     fputs(pub_key, pubFile);  
    209.     fclose(pubFile);  
    210.   
    211.     FILE *priFile = fopen(PRI_KEY_FILE, "w");  
    212.     if (priFile == NULL)  
    213.     {  
    214.         assert(false);  
    215.         return;  
    216.     }  
    217.     fputs(pri_key, priFile);  
    218.     fclose(priFile);  
    219.   
    220.     // 内存释放  
    221.     RSA_free(keypair);  
    222.     BIO_free_all(pub);  
    223.     BIO_free_all(pri);  
    224.   
    225.     free(pri_key);  
    226.     free(pub_key);  
    227. }  
    228.   
    229. // 命令行方法生成公私钥对(begin public key/ begin private key)  
    230. // 找到openssl命令行工具,运行以下  
    231. // openssl genrsa -out prikey.pem 1024   
    232. // openssl rsa - in privkey.pem - pubout - out pubkey.pem  
    233.   
    234. // 公钥加密    
    235. std::string rsa_pub_encrypt(const std::string &clearText, const std::string &pubKey)  
    236. {  
    237.     std::string strRet;  
    238.     RSA *rsa = NULL;  
    239.     BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);  
    240.     // 此处有三种方法  
    241.     // 1, 读取内存里生成的密钥对,再从内存生成rsa  
    242.     // 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa  
    243.     // 3,直接从读取文件指针生成rsa  
    244.     RSA* pRSAPublicKey = RSA_new();  
    245.     rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);  
    246.   
    247.     int len = RSA_size(rsa);  
    248.     char *encryptedText = (char *)malloc(len + 1);  
    249.     memset(encryptedText, 0, len + 1);  
    250.   
    251.     // 加密函数  
    252.     int ret = RSA_public_encrypt(clearText.length(), (const unsigned char*)clearText.c_str(), (unsigned char*)encryptedText, rsa, RSA_PKCS1_PADDING);  
    253.     if (ret >= 0)  
    254.         strRet = std::string(encryptedText, ret);  
    255.   
    256.     // 释放内存  
    257.     free(encryptedText);  
    258.     BIO_free_all(keybio);  
    259.     RSA_free(rsa);  
    260.   
    261.     return strRet;  
    262. }  
    263.   
    264. // 私钥解密    
    265. std::string rsa_pri_decrypt(const std::string &cipherText, const std::string &priKey)  
    266. {  
    267.     std::string strRet;  
    268.     RSA *rsa = RSA_new();  
    269.     BIO *keybio;  
    270.     keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);  
    271.   
    272.     // 此处有三种方法  
    273.     // 1, 读取内存里生成的密钥对,再从内存生成rsa  
    274.     // 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa  
    275.     // 3,直接从读取文件指针生成rsa  
    276.     rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);  
    277.   
    278.     int len = RSA_size(rsa);  
    279.     char *decryptedText = (char *)malloc(len + 1);  
    280.     memset(decryptedText, 0, len + 1);  
    281.   
    282.     // 解密函数  
    283.     int ret = RSA_private_decrypt(cipherText.length(), (const unsigned char*)cipherText.c_str(), (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);  
    284.     if (ret >= 0)  
    285.         strRet = std::string(decryptedText, ret);  
    286.   
    287.     // 释放内存  
    288.     free(decryptedText);  
    289.     BIO_free_all(keybio);  
    290.     RSA_free(rsa);  
    291.   
    292.     return strRet;  
    293. }  
    294.   
    295. int main(int argc, char **argv)  
    296. {  
    297.     // 原始明文    
    298.     std::string srcText = "this is an example";  
    299.   
    300.     std::string encryptText;  
    301.     std::string encryptHexText;  
    302.     std::string decryptText;  
    303.   
    304.     std::cout << "=== 原始明文 ===" << std::endl;  
    305.     std::cout << srcText << std::endl;  
    306.   
    307.     // md5    
    308.     std::cout << "=== md5哈希 ===" << std::endl;  
    309.     md5(srcText, encryptText, encryptHexText);  
    310.     std::cout << "摘要字符: " << encryptText << std::endl;  
    311.     std::cout << "摘要串: " << encryptHexText << std::endl;  
    312.   
    313.     // sha256    
    314.     std::cout << "=== sha256哈希 ===" << std::endl;  
    315.     sha256(srcText, encryptText, encryptHexText);  
    316.     std::cout << "摘要字符: " << encryptText << std::endl;  
    317.     std::cout << "摘要串: " << encryptHexText << std::endl;  
    318.   
    319.     // des    
    320.     std::cout << "=== des加解密 ===" << std::endl;  
    321.     std::string desKey = "12345";  
    322.     encryptText = des_encrypt(srcText, desKey);  
    323.     std::cout << "加密字符: " << std::endl;  
    324.     std::cout << encryptText << std::endl;  
    325.     decryptText = des_decrypt(encryptText, desKey);  
    326.     std::cout << "解密字符: " << std::endl;  
    327.     std::cout << decryptText << std::endl;  
    328.   
    329.     // rsa    
    330.     std::cout << "=== rsa加解密 ===" << std::endl;  
    331.     std::string key[2];  
    332.     generateRSAKey(key);  
    333.     std::cout << "公钥: " << std::endl;  
    334.     std::cout << key[0] << std::endl;  
    335.     std::cout << "私钥: " << std::endl;  
    336.     std::cout << key[1] << std::endl;  
    337.     encryptText = rsa_pub_encrypt(srcText, key[0]);  
    338.     std::cout << "加密字符: " << std::endl;  
    339.     std::cout << encryptText << std::endl;  
    340.     decryptText = rsa_pri_decrypt(encryptText, key[1]);  
    341.     std::cout << "解密字符: " << std::endl;  
    342.     std::cout << decryptText << std::endl;  
    343.   
    344.     system("pause");  
    345.     return 0;  
    346. }  


    运行结果

    [plain] view plain copy
     
     print?
    1. === 原始明文 ===  
    2. this is an example  
    3.   
    4. === md5哈希 ===  
    5. 摘要字符: 乵�驥!範  
    6. 摘要串: 9202816dabaaf34bb106a10421b9a0d0  
    7. === sha256哈希 ===  
    8. 摘要字符: 訪X5衽鄁媫j/醢?17?P?4膡zD  
    9. 摘要串: d44c035835f1c5e0668b7d186a2ff5b0  
    10. === des加解密 ===  
    11. 加密字符:  
    12. ?/灲�取鮋t8:夽U錺?说  
    13. 解密字符:  
    14. this is an example  
    15.   
    16. === rsa加解密 ===  
    17. 公钥:  
    18. -----BEGIN RSA PUBLIC KEY-----  
    19. MIIBCAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR2zLj  
    20. hMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJYqh4e  
    21. sNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqjuywm  
    22. gVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1zyJA  
    23. WaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsfQc9r  
    24. RQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAw==  
    25. -----END RSA PUBLIC KEY-----  
    26.   
    27. 私钥:  
    28. -----BEGIN RSA PRIVATE KEY-----  
    29. MIIEowIBAAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR  
    30. 2zLjhMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJY  
    31. qh4esNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqj  
    32. uywmgVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1  
    33. zyJAWaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsf  
    34. Qc9rRQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAwKCAQEAmo5YMTlnfytRoQAN  
    35. FwB6+8sY3xKSNIfPlPTaR4V6jtkkrEHhPMyXrd0+PCNrrj0In2BFr6NqbMX7CMuv  
    36. jr0aDqSigzyejeSnQJT7nmFS/T0myXblxr6/IJFZDEvUITCa2yJGu5+QT9psxajb  
    37. 0mso2ri9XQk6SBPk+B5u8eVj5Myt4tqpWL0DEEDzwfhihs+uEGM7g6bPvQBI4JXu  
    38. 8uxfSRUkpyZ5s1koEhqj+RCguksPzSWO/Ut2Sd60iOUMRhya2aEbAyRTtfhsXja3  
    39. 4NMWjXorJ0SRkryM1iLJvVWkhkcr2vShH9rm9qz16BkrkI9/9Yx++GNNr6VU/p/+  
    40. Waa8CwKBgQD4m0ryXi6rCqazdCICGoZJGzaljApOZ1rWOiotM9TekaYE7tZ2NDAT  
    41. eytiCzxvs4/+1Jt5XzdGJ035VJKSai/n2ZzAq1YYtVHy5CG2olmeFtwaIWU18m2s  
    42. RjHQf/FiscVB4XdKrHjh3gLgSB8MWMDg/krisxT86HNyp1UE2jZv+QKBgQDuuoez  
    43. V+H23ktb9oDS9HuLXt+wZuww29uNb0jhVoLiqK6M90Pl2u8yErjsq04cG9pF0MUl  
    44. 8/nIw4RRKQh9GUOBBbxZqA/1yBxmHTz48siYJ3YXf5HB+0WxxOlEk3s05AnTilTi  
    45. 5Y4u9Ptwieoy+TOXatBL9XZgKkpHbcxKZH2gvwKBgQClvNyhlB8cscR3osFWvFmG  
    46. EiRuXVw0ROc5fBweIo3ptm6t9I75eCAM/MeWsihKd7VUjbz7lM+EGjP7jbcMRsqa  
    47. kRMrHOQQeOFMmBZ5wZEUDz1mwO4j9vPILsvgVUuXIS4r66TccvtBPqyVhWoIOytA  
    48. qYdBzLiomvehxONYkXmf+wKBgQCfJwUiOpaklDI9TwCMov0HlJUgRJ115+ezn4Xr  
    49. jwHscHRd+i1D50ohYdCdx4loEpGD4INuoqaF162LcLBTZi0Arn2RGrVOhWhEE337  
    50. TIW6xPlk/7aBUi52g0Ytt6d4mAaNBuNB7l7J+KegW/F3UM0PnIrdTk7qxtwvnogx  
    51. mFPAfwKBgAEuRGqF2Q9bNu/r0OufeFxsYm0zFvWBIxbq3DxPYRtzfhiQMeTOzl1g  
    52. 5rowAtb/w1SusGAZ4/lEUZoBgzV+8fr+rpx3eavVCmcXBVjDi9B5nNLIXWkcoEQG  
    53. G/4ZwXUr5kyTBktL6mIBVNJ8dJUQo8xyxK0GjfWhlsk5t/Zu8tmK  
    54. -----END RSA PRIVATE KEY-----  
    55.   
    56. 加密字符:  
    57. 佷篒?z_�&欗霐嗪K赸;J╄[i9?S絑?て晄p?[hD∞51鱠,k|1裡郿     犓鈪鑒?饞w2?`vlu  
    58. L<萿囂?圖L潥?O0�佲y▃ 飕E堿^桮??�,e鉀煯A�CsJ挈R聡-鳊帔!eQC乥+1(齀  
    59. я盈Xj饮[o6覾羂≯傁澓  
    60. 解密字符:  
    61. this is an example  

    注:

    (1)在读取公钥文件时,PEM_read_RSA_PUBKEY()函数和PEM_read_RSAPublicKEY()的疑惑。有时候为什么读取私钥文件用的PEM_read_RSAPrivateKey(),针对上述openssl命令生成的公钥文件,在读取其内容时用对称的PEM_read_RSAPublicKEY()接口却会报错,必须要用PEM_read_RSA_PUBKEY()才可以。

              RSA PUBLIC KEY和PUBLIC KEY的两种公钥文件其存储方式是不一样的,PEM_read_RSAPublicKEY()只能读取RSA PUBLIC KEY开头形式的公钥文件(用函数生成的);而PEM_read_RSA_PUBKEY()只能读取PUBLIC KEY开头格式的公钥文件(用命令行生成),所以公钥私钥读取函数一定要跟生成的密钥对的格式对应起来。

    (2)公钥加密和私钥解密, 私钥加密公钥解密 这两种都可以使用

    (3)一般加密之后的字符串因为编码跟中文对应不上所以是乱码,在很多场合选择用十六进制串输出

    (4)实际的工程应用中读取密钥对需要加安全验证

    (5)用纯代码不依赖openssl库也是可以自己实现这些加解密算法的,搞清楚原理就行

    http://blog.csdn.net/u012234115/article/details/72762045

  • 相关阅读:
    内核态内存映射
    FS 数据结构
    内存页分配/释放
    用户态内存映射
    WindowsServer 2008 TIME_WAIT
    OutOfMemoryError:修改tomcat启动参数
    windows下Tomcat添加jmx监控
    mysql 5.7.11 安装运行
    mysql 数据库备份与还原
    Win7下虚拟WiFi设置
  • 原文地址:https://www.cnblogs.com/findumars/p/7252839.html
Copyright © 2020-2023  润新知