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下为例
- 编译openssl库,得到头文件include和链接库lib和dll
- 配置包含头文件目录和库目录
- 工程中设置链接指定的lib:fenbieshlibssl.lib,libcrypto.lib
- 将对应的dll拷贝到exe执行目录:libcrypto-1_1.dll, libssl-1_1.dll
代码
- #include <iostream>
- #include <cassert>
- #include <string>
- #include <vector>
- #include "openssl/md5.h"
- #include "openssl/sha.h"
- #include "openssl/des.h"
- #include "openssl/rsa.h"
- #include "openssl/pem.h"
- // ---- md5摘要哈希 ---- //
- void md5(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
- {
- // 调用md5哈希
- unsigned char mdStr[33] = {0};
- MD5((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
- // 哈希后的字符串
- encodedStr = std::string((const char *)mdStr);
- // 哈希后的十六进制串 32字节
- char buf[65] = {0};
- char tmp[3] = {0};
- for (int i = 0; i < 32; i++)
- {
- sprintf(tmp, "%02x", mdStr[i]);
- strcat(buf, tmp);
- }
- buf[32] = '\0'; // 后面都是0,从32字节截断
- encodedHexStr = std::string(buf);
- }
- // ---- sha256摘要哈希 ---- //
- void sha256(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
- {
- // 调用sha256哈希
- unsigned char mdStr[33] = {0};
- SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
- // 哈希后的字符串
- encodedStr = std::string((const char *)mdStr);
- // 哈希后的十六进制串 32字节
- char buf[65] = {0};
- char tmp[3] = {0};
- for (int i = 0; i < 32; i++)
- {
- sprintf(tmp, "%02x", mdStr[i]);
- strcat(buf, tmp);
- }
- buf[32] = '\0'; // 后面都是0,从32字节截断
- encodedHexStr = std::string(buf);
- }
- // ---- des对称加解密 ---- //
- // 加密 ecb模式
- std::string des_encrypt(const std::string &clearText, const std::string &key)
- {
- std::string cipherText; // 密文
- DES_cblock keyEncrypt;
- memset(keyEncrypt, 0, 8);
- // 构造补齐后的密钥
- if (key.length() <= 8)
- memcpy(keyEncrypt, key.c_str(), key.length());
- else
- memcpy(keyEncrypt, key.c_str(), 8);
- // 密钥置换
- DES_key_schedule keySchedule;
- DES_set_key_unchecked(&keyEncrypt, &keySchedule);
- // 循环加密,每8字节一次
- const_DES_cblock inputText;
- DES_cblock outputText;
- std::vector<unsigned char> vecCiphertext;
- unsigned char tmp[8];
- for (int i = 0; i < clearText.length() / 8; i++)
- {
- memcpy(inputText, clearText.c_str() + i * 8, 8);
- DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
- memcpy(tmp, outputText, 8);
- for (int j = 0; j < 8; j++)
- vecCiphertext.push_back(tmp[j]);
- }
- if (clearText.length() % 8 != 0)
- {
- int tmp1 = clearText.length() / 8 * 8;
- int tmp2 = clearText.length() - tmp1;
- memset(inputText, 0, 8);
- memcpy(inputText, clearText.c_str() + tmp1, tmp2);
- // 加密函数
- DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
- memcpy(tmp, outputText, 8);
- for (int j = 0; j < 8; j++)
- vecCiphertext.push_back(tmp[j]);
- }
- cipherText.clear();
- cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());
- return cipherText;
- }
- // 解密 ecb模式
- std::string des_decrypt(const std::string &cipherText, const std::string &key)
- {
- std::string clearText; // 明文
- DES_cblock keyEncrypt;
- memset(keyEncrypt, 0, 8);
- if (key.length() <= 8)
- memcpy(keyEncrypt, key.c_str(), key.length());
- else
- memcpy(keyEncrypt, key.c_str(), 8);
- DES_key_schedule keySchedule;
- DES_set_key_unchecked(&keyEncrypt, &keySchedule);
- const_DES_cblock inputText;
- DES_cblock outputText;
- std::vector<unsigned char> vecCleartext;
- unsigned char tmp[8];
- for (int i = 0; i < cipherText.length() / 8; i++)
- {
- memcpy(inputText, cipherText.c_str() + i * 8, 8);
- DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
- memcpy(tmp, outputText, 8);
- for (int j = 0; j < 8; j++)
- vecCleartext.push_back(tmp[j]);
- }
- if (cipherText.length() % 8 != 0)
- {
- int tmp1 = cipherText.length() / 8 * 8;
- int tmp2 = cipherText.length() - tmp1;
- memset(inputText, 0, 8);
- memcpy(inputText, cipherText.c_str() + tmp1, tmp2);
- // 解密函数
- DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
- memcpy(tmp, outputText, 8);
- for (int j = 0; j < 8; j++)
- vecCleartext.push_back(tmp[j]);
- }
- clearText.clear();
- clearText.assign(vecCleartext.begin(), vecCleartext.end());
- return clearText;
- }
- // ---- rsa非对称加解密 ---- //
- #define KEY_LENGTH 2048 // 密钥长度
- #define PUB_KEY_FILE "pubkey.pem" // 公钥路径
- #define PRI_KEY_FILE "prikey.pem" // 私钥路径
- // 函数方法生成密钥对
- void generateRSAKey(std::string strKey[2])
- {
- // 公私密钥对
- size_t pri_len;
- size_t pub_len;
- char *pri_key = NULL;
- char *pub_key = NULL;
- // 生成密钥对
- RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);
- BIO *pri = BIO_new(BIO_s_mem());
- BIO *pub = BIO_new(BIO_s_mem());
- PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
- PEM_write_bio_RSAPublicKey(pub, keypair);
- // 获取长度
- pri_len = BIO_pending(pri);
- pub_len = BIO_pending(pub);
- // 密钥对读取到字符串
- pri_key = (char *)malloc(pri_len + 1);
- pub_key = (char *)malloc(pub_len + 1);
- BIO_read(pri, pri_key, pri_len);
- BIO_read(pub, pub_key, pub_len);
- pri_key[pri_len] = '\0';
- pub_key[pub_len] = '\0';
- // 存储密钥对
- strKey[0] = pub_key;
- strKey[1] = pri_key;
- // 存储到磁盘(这种方式存储的是begin rsa public key/ begin rsa private key开头的)
- FILE *pubFile = fopen(PUB_KEY_FILE, "w");
- if (pubFile == NULL)
- {
- assert(false);
- return;
- }
- fputs(pub_key, pubFile);
- fclose(pubFile);
- FILE *priFile = fopen(PRI_KEY_FILE, "w");
- if (priFile == NULL)
- {
- assert(false);
- return;
- }
- fputs(pri_key, priFile);
- fclose(priFile);
- // 内存释放
- RSA_free(keypair);
- BIO_free_all(pub);
- BIO_free_all(pri);
- free(pri_key);
- free(pub_key);
- }
- // 命令行方法生成公私钥对(begin public key/ begin private key)
- // 找到openssl命令行工具,运行以下
- // openssl genrsa -out prikey.pem 1024
- // openssl rsa - in privkey.pem - pubout - out pubkey.pem
- // 公钥加密
- std::string rsa_pub_encrypt(const std::string &clearText, const std::string &pubKey)
- {
- std::string strRet;
- RSA *rsa = NULL;
- BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
- // 此处有三种方法
- // 1, 读取内存里生成的密钥对,再从内存生成rsa
- // 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa
- // 3,直接从读取文件指针生成rsa
- RSA* pRSAPublicKey = RSA_new();
- rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
- int len = RSA_size(rsa);
- char *encryptedText = (char *)malloc(len + 1);
- memset(encryptedText, 0, len + 1);
- // 加密函数
- int ret = RSA_public_encrypt(clearText.length(), (const unsigned char*)clearText.c_str(), (unsigned char*)encryptedText, rsa, RSA_PKCS1_PADDING);
- if (ret >= 0)
- strRet = std::string(encryptedText, ret);
- // 释放内存
- free(encryptedText);
- BIO_free_all(keybio);
- RSA_free(rsa);
- return strRet;
- }
- // 私钥解密
- std::string rsa_pri_decrypt(const std::string &cipherText, const std::string &priKey)
- {
- std::string strRet;
- RSA *rsa = RSA_new();
- BIO *keybio;
- keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);
- // 此处有三种方法
- // 1, 读取内存里生成的密钥对,再从内存生成rsa
- // 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa
- // 3,直接从读取文件指针生成rsa
- rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
- int len = RSA_size(rsa);
- char *decryptedText = (char *)malloc(len + 1);
- memset(decryptedText, 0, len + 1);
- // 解密函数
- int ret = RSA_private_decrypt(cipherText.length(), (const unsigned char*)cipherText.c_str(), (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
- if (ret >= 0)
- strRet = std::string(decryptedText, ret);
- // 释放内存
- free(decryptedText);
- BIO_free_all(keybio);
- RSA_free(rsa);
- return strRet;
- }
- int main(int argc, char **argv)
- {
- // 原始明文
- std::string srcText = "this is an example";
- std::string encryptText;
- std::string encryptHexText;
- std::string decryptText;
- std::cout << "=== 原始明文 ===" << std::endl;
- std::cout << srcText << std::endl;
- // md5
- std::cout << "=== md5哈希 ===" << std::endl;
- md5(srcText, encryptText, encryptHexText);
- std::cout << "摘要字符: " << encryptText << std::endl;
- std::cout << "摘要串: " << encryptHexText << std::endl;
- // sha256
- std::cout << "=== sha256哈希 ===" << std::endl;
- sha256(srcText, encryptText, encryptHexText);
- std::cout << "摘要字符: " << encryptText << std::endl;
- std::cout << "摘要串: " << encryptHexText << std::endl;
- // des
- std::cout << "=== des加解密 ===" << std::endl;
- std::string desKey = "12345";
- encryptText = des_encrypt(srcText, desKey);
- std::cout << "加密字符: " << std::endl;
- std::cout << encryptText << std::endl;
- decryptText = des_decrypt(encryptText, desKey);
- std::cout << "解密字符: " << std::endl;
- std::cout << decryptText << std::endl;
- // rsa
- std::cout << "=== rsa加解密 ===" << std::endl;
- std::string key[2];
- generateRSAKey(key);
- std::cout << "公钥: " << std::endl;
- std::cout << key[0] << std::endl;
- std::cout << "私钥: " << std::endl;
- std::cout << key[1] << std::endl;
- encryptText = rsa_pub_encrypt(srcText, key[0]);
- std::cout << "加密字符: " << std::endl;
- std::cout << encryptText << std::endl;
- decryptText = rsa_pri_decrypt(encryptText, key[1]);
- std::cout << "解密字符: " << std::endl;
- std::cout << decryptText << std::endl;
- system("pause");
- return 0;
- }
运行结果
- === 原始明文 ===
- this is an example
- === md5哈希 ===
- 摘要字符: 乵驥!範
- 摘要串: 9202816dabaaf34bb106a10421b9a0d0
- === sha256哈希 ===
- 摘要字符: 訪X5衽鄁媫j/醢?17?P?4膡zD
- 摘要串: d44c035835f1c5e0668b7d186a2ff5b0
- === des加解密 ===
- 加密字符:
- ?/灲取鮋t8:夽U錺?说
- 解密字符:
- this is an example
- === rsa加解密 ===
- 公钥:
- -----BEGIN RSA PUBLIC KEY-----
- MIIBCAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR2zLj
- hMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJYqh4e
- sNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqjuywm
- gVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1zyJA
- WaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsfQc9r
- RQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAw==
- -----END RSA PUBLIC KEY-----
- 私钥:
- -----BEGIN RSA PRIVATE KEY-----
- MIIEowIBAAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR
- 2zLjhMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJY
- qh4esNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqj
- uywmgVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1
- zyJAWaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsf
- Qc9rRQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAwKCAQEAmo5YMTlnfytRoQAN
- FwB6+8sY3xKSNIfPlPTaR4V6jtkkrEHhPMyXrd0+PCNrrj0In2BFr6NqbMX7CMuv
- jr0aDqSigzyejeSnQJT7nmFS/T0myXblxr6/IJFZDEvUITCa2yJGu5+QT9psxajb
- 0mso2ri9XQk6SBPk+B5u8eVj5Myt4tqpWL0DEEDzwfhihs+uEGM7g6bPvQBI4JXu
- 8uxfSRUkpyZ5s1koEhqj+RCguksPzSWO/Ut2Sd60iOUMRhya2aEbAyRTtfhsXja3
- 4NMWjXorJ0SRkryM1iLJvVWkhkcr2vShH9rm9qz16BkrkI9/9Yx++GNNr6VU/p/+
- Waa8CwKBgQD4m0ryXi6rCqazdCICGoZJGzaljApOZ1rWOiotM9TekaYE7tZ2NDAT
- eytiCzxvs4/+1Jt5XzdGJ035VJKSai/n2ZzAq1YYtVHy5CG2olmeFtwaIWU18m2s
- RjHQf/FiscVB4XdKrHjh3gLgSB8MWMDg/krisxT86HNyp1UE2jZv+QKBgQDuuoez
- V+H23ktb9oDS9HuLXt+wZuww29uNb0jhVoLiqK6M90Pl2u8yErjsq04cG9pF0MUl
- 8/nIw4RRKQh9GUOBBbxZqA/1yBxmHTz48siYJ3YXf5HB+0WxxOlEk3s05AnTilTi
- 5Y4u9Ptwieoy+TOXatBL9XZgKkpHbcxKZH2gvwKBgQClvNyhlB8cscR3osFWvFmG
- EiRuXVw0ROc5fBweIo3ptm6t9I75eCAM/MeWsihKd7VUjbz7lM+EGjP7jbcMRsqa
- kRMrHOQQeOFMmBZ5wZEUDz1mwO4j9vPILsvgVUuXIS4r66TccvtBPqyVhWoIOytA
- qYdBzLiomvehxONYkXmf+wKBgQCfJwUiOpaklDI9TwCMov0HlJUgRJ115+ezn4Xr
- jwHscHRd+i1D50ohYdCdx4loEpGD4INuoqaF162LcLBTZi0Arn2RGrVOhWhEE337
- TIW6xPlk/7aBUi52g0Ytt6d4mAaNBuNB7l7J+KegW/F3UM0PnIrdTk7qxtwvnogx
- mFPAfwKBgAEuRGqF2Q9bNu/r0OufeFxsYm0zFvWBIxbq3DxPYRtzfhiQMeTOzl1g
- 5rowAtb/w1SusGAZ4/lEUZoBgzV+8fr+rpx3eavVCmcXBVjDi9B5nNLIXWkcoEQG
- G/4ZwXUr5kyTBktL6mIBVNJ8dJUQo8xyxK0GjfWhlsk5t/Zu8tmK
- -----END RSA PRIVATE KEY-----
- 加密字符:
- 佷篒?z_&欗霐嗪K赸;J╄[i9?S絑?て晄p?[hD∞51鱠,k|1裡郿 犓鈪鑒?饞w2?`vlu
- L<萿囂?圖L潥?O0佲y▃飕E堿^桮??,e鉀煯ACsJ挈R聡-鳊帔!eQC乥+1\(齀
- я盈Xj饮[o6覾羂≯傁澓
- 解密字符:
- 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
C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)的更多相关文章
- php中des加密解密 匹配C#des加密解密 对称加密
原文:php中des加密解密 匹配C#des加密解密 对称加密 网上找来的 php des加密解密 完全匹配上一篇C# 字符串加密解密函数 可以用于C#和php通信 对数据进行加密,其中$key 是 ...
- ruby的加密方法整理(des rsa加密 加签)
# coding:utf-8require 'openssl'require 'base64'#des加密并且base64编码def des_encrypt des_key, des_text des ...
- 支付接口中常用的加密解密以及验签rsa,md5,sha
一.常用加密类型分类 1.对称加密:采用单钥对信息进行加密和解密,即同一个秘钥既可以对信息进行加密,也可以进行解密.此类型称之为对称加密.特点速度快,常用于对大量数据信息或文件加密时使用.常用例子:D ...
- DES加密解密 MD5加密解密
#region MD5 加密 /// <summary> /// MD5加密静态方法 /// </summary> /// <param name="Encry ...
- VB使用API进行RC4加密解密(MD5密钥)
根据网络资料整改,来源未知,已调试通过. Option Explicit Private Declare Function CryptAcquireContext Lib "advapi32 ...
- 工作中拓展的加密解密传输方式. DES对称加密传输.
系统间通过xml传输, 不能采用明文, 就加密传输. 秘钥(真正有效的是前8位)存储于配置中. public static string EncryptStr(this string content, ...
- C# 加密解密以及sha256不可逆加密案例
class Program { static void Main(string[] args) { string aa = "身份证"; string bb = "key ...
- [C#]加密解密 MD5、AES
/// <summary> /// MD5函数 /// </summary> /// <param name="str">原始字符串</p ...
- openssl evp RSA 加密解密
openssl evp RSA 加密解密 可以直接使用RSA.h 提供的接口 如下测试使用EVP提供的RSA接口 1. EVP提供的RSA 加密解密 主要接口: int EVP_PKEY_encryp ...
随机推荐
- 使用oschina的gitserver
1.概要 事实上oschina的gitserver与github的几乎相同.只是既然是中国的gitserver,那么速度应该更快一些吧 2.注冊 链接https://git.oschina.net/, ...
- php课程 5-18 数组排序和合并拆分函数有哪些
php课程 5-18 数组排序和合并拆分函数有哪些 一.总结 一句话总结:分类来记.这些函数自己都可以写,费点时间而已. 1.array_combine()和array_merge()的区别是什 ...
- 小强的HTML5移动开发之路(48)——(小练习)新闻订阅系统【1】
一.总体设计 二.数据库设计 --新闻类别表 create table news_cate( news_cateid int primary key auto_increment, news_icon ...
- Codeforces 491B. New York Hotel 最远曼哈顿距离
最远曼哈顿距离有两个性质: 1: 对每一个点(x,y) 分别计算 +x+y , -x+y , x-y , -x-y 然后统计每种组合的最大值就能够了, 不会对结果产生影响 2: 去掉绝对值 , 设 ...
- 一步步学习Linux多任务编程
系统调用 01.什么是系统调用? 02.Linux系统调用之I/O操作(文件操作) 03.文件描述符的复制:dup(), dup2() 多进程实现多任务 04.进程的介绍 05.Linux可执行文件结 ...
- 【u022】车的放置
[问题描述] [题解] 先考虑一个最简单的情况.如一个n*n的棋盘.然后要放k个车. 我们可以先选出k行即C(n,k); 然后在列上对这k个棋子进行一次全排列即A(n,k); 比如k = 4;N=5 ...
- Redis内存管理的基石zmallc.c源代码解读(一)
当我第一次阅读了这个文件的源代码的时候.我笑了,忽然想起前几周阿里电话二面的时候,问到了自己定义内存管理函数并处理8字节对齐问题. 当时无言以对,在面试官无数次的提示下才答了出来,结果显而易见,挂掉了 ...
- 《Erlang程序设计》学习笔记-第1章 编译并运行程序
http://blog.csdn.net/karl_max/article/details/3976372 1. erlang:halt()可以即刻停止系统运行. 2. q()命令可以完成文件和数据库 ...
- matplotlib tricks(一)—— 多类别数据的 scatter(cmap)
cmap 的选择: binary seismic Reds 多类别数据的 scatter(逐点散列),在 matplotlib 中的实现关键在于,color关键字的定义: def plot_scatt ...
- sparksql hive作为数据源
根据官方文档的说法,要把hive-site.xml,core-site.xml,hdfs-site.xml拷贝到spark的conf目录下,保证mysql已经启动 java public class ...