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
linux下同理
代碼
[cpp]view plaincopy
print?
#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摘要哈希----//
voidmd5(conststd::string&srcStr,std::string&encodedStr,std::string&encodedHexStr)
{
//調用md5哈希
unsignedcharmdStr[33]={0};
MD5((constunsignedchar*)srcStr.c_str(),srcStr.length(),mdStr);
//哈希后的字符串
encodedStr=std::string((constchar*)mdStr);
//哈希后的十六進制串32字節
charbuf[65]={0};
chartmp[3]={0};
for(inti=0;i<32;i++)
{
sprintf(tmp,"%02x",mdStr[i]);
strcat(buf,tmp);
}
buf[32]='';//后面都是0,從32字節截斷
encodedHexStr=std::string(buf);
}
//----sha256摘要哈希----//
voidsha256(conststd::string&srcStr,std::string&encodedStr,std::string&encodedHexStr)
{
//調用sha256哈希
unsignedcharmdStr[33]={0};
SHA256((constunsignedchar*)srcStr.c_str(),srcStr.length(),mdStr);
//哈希后的字符串
encodedStr=std::string((constchar*)mdStr);
//哈希后的十六進制串32字節
charbuf[65]={0};
chartmp[3]={0};
for(inti=0;i<32;i++)
{
sprintf(tmp,"%02x",mdStr[i]);
strcat(buf,tmp);
}
buf[32]='';//后面都是0,從32字節截斷
encodedHexStr=std::string(buf);
}
//----des對稱加解密----//
//加密ecb模式
std::stringdes_encrypt(conststd::string&clearText,conststd::string&key)
{
std::stringcipherText;//密文
DES_cblockkeyEncrypt;
memset(keyEncrypt,0,8);
//構造補齊后的密鑰
if(key.length()<=8)
memcpy(keyEncrypt,key.c_str(),key.length());
else
memcpy(keyEncrypt,key.c_str(),8);
//密鑰置換
DES_key_schedulekeySchedule;
DES_set_key_unchecked(&keyEncrypt,&keySchedule);
//循環加密,每8字節一次
const_DES_cblockinputText;
DES_cblockoutputText;
std::vector<unsignedchar>vecCiphertext;
unsignedchartmp[8];
for(inti=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(intj=0;j<8;j++)
vecCiphertext.push_back(tmp[j]);
}
if(clearText.length()%8!=0)
{
inttmp1=clearText.length()/8*8;
inttmp2=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(intj=0;j<8;j++)
vecCiphertext.push_back(tmp[j]);
}
cipherText.clear();
cipherText.assign(vecCiphertext.begin(),vecCiphertext.end());
returncipherText;
}
//解密ecb模式
std::stringdes_decrypt(conststd::string&cipherText,conststd::string&key)
{
std::stringclearText;//明文
DES_cblockkeyEncrypt;
memset(keyEncrypt,0,8);
if(key.length()<=8)
memcpy(keyEncrypt,key.c_str(),key.length());
else
memcpy(keyEncrypt,key.c_str(),8);
DES_key_schedulekeySchedule;
DES_set_key_unchecked(&keyEncrypt,&keySchedule);
const_DES_cblockinputText;
DES_cblockoutputText;
std::vector<unsignedchar>vecCleartext;
unsignedchartmp[8];
for(inti=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(intj=0;j<8;j++)
vecCleartext.push_back(tmp[j]);
}
if(cipherText.length()%8!=0)
{
inttmp1=cipherText.length()/8*8;
inttmp2=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(intj=0;j<8;j++)
vecCleartext.push_back(tmp[j]);
}
clearText.clear();
clearText.assign(vecCleartext.begin(),vecCleartext.end());
returnclearText;
}
//----rsa非對稱加解密----//
#defineKEY_LENGTH2048//密鑰長度
#definePUB_KEY_FILE"pubkey.pem"http://公鑰路徑
#definePRI_KEY_FILE"prikey.pem"http://私鑰路徑
//函數方法生成密鑰對
voidgenerateRSAKey(std::stringstrKey[2])
{
//公私密鑰對
size_tpri_len;
size_tpub_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]='';
pub_key[pub_len]='';
//存儲密鑰對
strKey[0]=pub_key;
strKey[1]=pri_key;
//存儲到磁盤(這種方式存儲的是beginrsapublickey/beginrsaprivatekey開頭的)
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);
}
//命令行方法生成公私鑰對(beginpublickey/beginprivatekey)
//找到openssl命令行工具,運行以下
//opensslgenrsa-outprikey.pem1024
//opensslrsa-inprivkey.pem-pubout-outpubkey.pem
//公鑰加密
std::stringrsa_pub_encrypt(conststd::string&clearText,conststd::string&pubKey)
{
std::stringstrRet;
RSA*rsa=NULL;
BIO*keybio=BIO_new_mem_buf((unsignedchar*)pubKey.c_str(),-1);
//此處有三種方法
//1,讀取內存里生成的密鑰對,再從內存生成rsa
//2,讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
//3,直接從讀取文件指針生成rsa
RSA*pRSAPublicKey=RSA_new();
rsa=PEM_read_bio_RSAPublicKey(keybio,&rsa,NULL,NULL);
intlen=RSA_size(rsa);
char*encryptedText=(char*)malloc(len+1);
memset(encryptedText,0,len+1);
//加密函數
intret=RSA_public_encrypt(clearText.length(),(constunsignedchar*)clearText.c_str(),(unsignedchar*)encryptedText,rsa,RSA_PKCS1_PADDING);
if(ret>=0)
strRet=std::string(encryptedText,ret);
//釋放內存
free(encryptedText);
BIO_free_all(keybio);
RSA_free(rsa);
returnstrRet;
}
//私鑰解密
std::stringrsa_pri_decrypt(conststd::string&cipherText,conststd::string&priKey)
{
std::stringstrRet;
RSA*rsa=RSA_new();
BIO*keybio;
keybio=BIO_new_mem_buf((unsignedchar*)priKey.c_str(),-1);
//此處有三種方法
//1,讀取內存里生成的密鑰對,再從內存生成rsa
//2,讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
//3,直接從讀取文件指針生成rsa
rsa=PEM_read_bio_RSAPrivateKey(keybio,&rsa,NULL,NULL);
intlen=RSA_size(rsa);
char*decryptedText=(char*)malloc(len+1);
memset(decryptedText,0,len+1);
//解密函數
intret=RSA_private_decrypt(cipherText.length(),(constunsignedchar*)cipherText.c_str(),(unsignedchar*)decryptedText,rsa,RSA_PKCS1_PADDING);
if(ret>=0)
strRet=std::string(decryptedText,ret);
//釋放內存
free(decryptedText);
BIO_free_all(keybio);
RSA_free(rsa);
returnstrRet;
}
intmain(intargc,char**argv)
{
//原始明文
std::stringsrcText="thisisanexample";
std::stringencryptText;
std::stringencryptHexText;
std::stringdecryptText;
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::stringdesKey="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::stringkey[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");
return0;
}
運行結果
[plain]view plaincopy
print?
===原始明文===
thisisanexample
===md5哈希===
摘要字符:乵?驥!範
摘要串:9202816dabaaf34bb106a10421b9a0d0
===sha256哈希===
摘要字符:訪X5衽鄁媫j/醢?17?P?4膡zD
摘要串:d44c035835f1c5e0668b7d186a2ff5b0
===des加解密===
加密字符:
?/灲?取鮋t8:夽U錺?說
解密字符:
thisisanexample
===rsa加解密===
公鑰:
-----BEGINRSAPUBLICKEY-----
MIIBCAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR2zLj
hMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJYqh4e
sNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqjuywm
gVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1zyJA
WaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsfQc9r
RQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAw==
-----ENDRSAPUBLICKEY-----
私鑰:
-----BEGINRSAPRIVATEKEY-----
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
-----ENDRSAPRIVATEKEY-----
加密字符:
佷篒?z_?&欗霐嗪K赸;J╄[i9?S絑?て晄p?[hD∞51鱠,k|1裡郿犓鈪鑒?饞w2?`vlu
L<萿囂?圖L潥?O0?佲y▃颼E堿^桮???,e鉀煯A?CsJ挈R聡-鳊帔!eQC乥+1(齀
я盈Xj飲[o6覾羂≯傁澓
解密字符:
thisisanexample
注:
(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)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 捕捉Entity framework 6
 - 下一篇: Google Mesa概览