头文件清单
#pragma once /* 本模块功能: AES加解密,SHA256生成内容文摘,RSA非对称加解密。 測試環境: [1]VS2008 SP1 [2]WinXP SP3 [3]cryptopp561 測試時間: [1]2012-7 by kagula 更新记录: [1]2012-10 修正AES加解密时key长度没有对齐的问题 备注: [1]cryptopp三要素:XXXSource指的是源,Filter指的是过滤器,XXXSink是容器。 [2]AES加密产生的密文以零结尾? 密文跟明文的长度一样? [3]要二进制编码的话参考testAES函数。 参考资料 [1]Sink的概念 http://www.cryptopp.com/wiki/Sink [2]块为单位编解码 http://topic.csdn.net/u/20070512/19/297431db-3b82-480d-96a7-9101d4abf13c.html [3]GCM模式 http://www.cryptopp.com/wiki/GCM [4]Crypto++库在VS 2005中的使用——RSA加解密 http://www.cnblogs.com/cxun/archive/2008/07/30/743541.html [5]CryptoPP 5.6.1 SHA256 results incorrect with 32 bit MSVC 2005 release build http://sourceforge.net/apps/trac/cryptopp/ticket/7 [6]使用cryptopp实现密钥协商 http://bbs.gameres.com/thread_118476.html [7]AES对称加密算法原理 http://www.2cto.com/Article/201112/113465.html 相关: 高级加密标准(Advanced Encryption Standard,AES),在密码学中又称Rijndael加密法, 是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,传递非机密文件。 */ #include <string> #include <config.h> //byte ////////////////////////////////////////////////////////// /* 功能 二进制数据块,转,16进制字符串 入口 s 二进制数据块 s_len 二进制数据块 长度 出口 16进制ASCII码字符串 */ std::string Bytes2Hex(byte * s,unsigned int s_len); /* 功能 16进制字符串,转,二进制数据块 入口 encoded 16进制ASCII码字符串 出口 d 二进制数据块 d_len 二进制数据块的长度 */ bool Hex2Bytes(std::string encoded,byte *d,unsigned int &d_len); ////////////////////////////////////////////////////////// /* 功能 CFB模式AES算法字符串加密 入口 sKey 钥匙 plainText 明文 出口 密文 */ std::string CFB_AESEncryptStr(std::string sKey,const char *plainText); std::string CFB_AESEncryptStr(const char *plainText); /* 入口 sKey 钥匙 cipherText 密文 出口 明文 */ std::string CFB_AESDecryptStr(std::string sKey,const char *cipherText); std::string CFB_AESDecryptStr(std::string cipherText); /* 功能 CFB模式AES算法字符串加密,返回BASE64编码字符串,明文自动16字节对齐,使用0x30填充。 入口 key 钥匙,长度必须为 "16/24/32" 三者之一 plainText 明文 出口 密文 */ std::string CFB_AESEncryptStr_BASE64(const char *key,const char *plainText); /* 功能 CFB模式AES算法字符串解密,对BASE64编码字符串进行解码 入口 key 钥匙,长度必须为 "16/24/32" 三者之一 cipherText 密文 出口 明文 */ std::string CFB_AESDecryptStr_BASE64(const char *key,const char *cipherText); /* 功能 GCM模式AES算法字符串加密 入口: sKey 钥匙。可以为空字符串。 sAuth Auth(解码时必须), 一般Auth存放明文的签名。可以为空字符串。 sPlain 明文 出口: iv 增量(解码时必须) ,用于防止同样的钥匙和明文出现同样的密文。 原则上同样的IV,不能在同key上重复出现。 sCipher 密文 */ bool GCM_AESEncryptStr(const std::string &sKey,const std::string &sAuth,const std::string &sPlain, byte iv[16],std::string &sCipher); /* 入口: sKey 钥匙 sAuth Auth(解码时必须), 一般Auth存放明文的签名 sCipher 密文 iv 增量(解码时必须) 出口: sPlain 明文 */ bool GCM_AESDecryptStr(const std::string &sKey,const std::string &sAuth,const std::string &sCipher,const byte iv[16], std::string &sPlain); ////////////////////////////////////////////////////////// /* 入口: msg 要产生文摘的内容 出口: digest 文摘 */ void SHA256_Cal(const std::string &msg,std::string &digest); /* 入口: msg 内容 digest 文摘 出口: 校验成功返回 True */ bool SHA256_Verify(const std::string &msg,const std::string &digest); ////////////////////////////////////////////////////////// /* 入口 strSeed 种子,可以取值"seed"。 出口 strPri 私钥 解密用 strPub 公钥 加密用 */ void GenerateRSAKey(const std::string &strSeed,std::string &strPri, std::string &strPub); /* 入口 strSeed 调用GenerateRSAKey时用的种子。 strPub 公钥 plainText 明文 出口 返回密文 */ std::string RSAEncryptStr(const std::string &strPub,const std::string &strSeed, const char *plainText); /* 入口 strSeed 调用GenerateRSAKey时用的种子。 strPri 私钥 cipherText 密文 出口 返回明文 */ std::string RSADecryptStr(const std::string &strPri, const char *cipherText); //////////////////////////////////////////////////////////
源文件清单
#include "stdafx.h" ////////////////////////////////////////////////////////// #include <aes.h> #include <files.h> // FileSource, FileSink #include <osrng.h> // AutoSeededRandomPool #include <modes.h> // CFB_Mode #include <Hex.h> // HexEncoder #include <Base64.h> // Base64Encoder #include <gcm.h> // GCM模式支持 #include <sha.h> #include <rsa.h> // RSAES_OAEP_SHA_Decryptor /* [S1]安装并编译cryptopp561到"E:\SDK\cryptopp561" [S2] "E:\SDK\cryptopp561\Win32\Output\Debug\cryptlib.lib"文件复制并重命名到 "E:\SDK\cryptopp561\Win32\Output\cryptlib_D.lib"。 [S3] "E:\SDK\cryptopp561\Win32\Output\Release\cryptlib.lib"文件复制到 "E:\SDK\cryptopp561\Win32\Output\"目录下。 */ #ifdef _DEBUG #pragma comment(lib,"cryptlib_D") #else #pragma comment(lib,"cryptlib") #endif using namespace CryptoPP; ////////////////////////////////////////////////////////// #include <iostream> //std:cerr #include <sstream> //std::stringstream #include <string> using namespace std; ////////////////////////////////////////////////////////// //引用自http://www.cnblogs.com/jclugia/archive/2011/11/29/2267692.html std::string Bytes2Hex(byte * s,unsigned int s_len) { std::string encoded; StringSource ss(s, s_len, true, new HexEncoder(new StringSink(encoded)) ); //std::cout << encoded << std::endl; return encoded; } //string encoded = "FFEEDDCCBBAA99887766554433221100"; bool Hex2Bytes(std::string encoded,byte *d,unsigned int &d_len) { HexDecoder decoder; decoder.Put( (byte*)encoded.data(), encoded.size() ); decoder.MessageEnd(); size_t size = (size_t) decoder.MaxRetrievable(); if(size && size<=d_len) { decoder.Get(d, size); d_len = size; return true; } return false; } /* std::string Bytes2Base64(byte * s,unsigned int s_len) { std::string encoded; StringSource ss(s, s_len, true, new Base64Encoder(new StringSink(encoded)) ); return encoded; } */ ////////////////////////////////////////////////////////// /* 这个例子好像可以稍微改一下,實現二進制數據塊的加解密,懒得测试了。 */ /* void testAES() { AutoSeededRandomPool rnd; // Generate a random key SecByteBlock key(AES::DEFAULT_KEYLENGTH); rnd.GenerateBlock( key, key.size() ); //iv 是一个增量值,可以随便取一个字符串 //加密使用的iv要和解密的一样 byte iv[AES::BLOCKSIZE]; rnd.GenerateBlock(iv, AES::BLOCKSIZE); char plainText[] = "Hello! How are you."; int messageLen = (int)strlen(plainText) + 1; ////////////////////////////////////////////////////////////////////////// // Encrypt CFB_Mode<AES>::Encryption cfbEncryption(key, key.size(), iv); cfbEncryption.ProcessData((byte*)plainText, (byte*)plainText, messageLen); ////////////////////////////////////////////////////////////////////////// // Decrypt CFB_Mode<AES>::Decryption cfbDecryption(key, key.size(), iv); cfbDecryption.ProcessData((byte*)plainText, (byte*)plainText, messageLen); } */ std::string CFB_AESEncryptStr(std::string sKey,const char *plainText) { std::string outstr; //填key SecByteBlock key(AES::DEFAULT_KEYLENGTH); memset(key,0x30,key.size() ); sKey.size()<=AES::DEFAULT_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::DEFAULT_KEYLENGTH); //填iv byte iv[AES::BLOCKSIZE]; memset(iv,0x30,AES::BLOCKSIZE); AES::Encryption aesEncryption((byte *)key, AES::DEFAULT_KEYLENGTH); CFB_Mode_ExternalCipher::Encryption cfbEncryption(aesEncryption, iv); StreamTransformationFilter cfbEncryptor(cfbEncryption, new HexEncoder(new StringSink(outstr))); cfbEncryptor.Put((byte *)plainText, strlen(plainText)); cfbEncryptor.MessageEnd(); return outstr; } std::string CFB_AESEncryptStr(const char *plainText) { std::string outstr; //填key SecByteBlock key(AES::DEFAULT_KEYLENGTH); memset(key,0x30,key.size() ); //填iv byte iv[AES::BLOCKSIZE]; memset(iv,0x30,AES::BLOCKSIZE); //加密 CFB_Mode<AES>::Encryption cfbEncryption(key, key.size(), iv); cfbEncryption.ProcessData((byte*)plainText, (byte*)plainText, strlen(plainText)+1); int nL = strlen(plainText); outstr = Bytes2Hex((byte *)plainText, nL); return outstr; } std::string CFB_AESDecryptStr(std::string sKey,const char *cipherText) { std::string outstr; //填key SecByteBlock key(AES::DEFAULT_KEYLENGTH); memset(key,0x30,key.size() ); sKey.size()<=AES::DEFAULT_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::DEFAULT_KEYLENGTH); //填iv byte iv[AES::BLOCKSIZE]; memset(iv,0x30,AES::BLOCKSIZE); CFB_Mode<AES >::Decryption cfbDecryption((byte *)key, AES::DEFAULT_KEYLENGTH, iv); HexDecoder decryptor(new StreamTransformationFilter(cfbDecryption, new StringSink(outstr))); decryptor.Put((byte *)cipherText, strlen(cipherText)); decryptor.MessageEnd(); return outstr; } std::string CFB_AESDecryptStr(std::string cipherText) { #define OUT_BUF_SIZE 256 unsigned int nSize = OUT_BUF_SIZE; char plainText[OUT_BUF_SIZE]; Hex2Bytes(cipherText,(byte *)plainText,nSize); //填key SecByteBlock key(AES::DEFAULT_KEYLENGTH); memset(key,0x30,key.size() ); //填iv byte iv[AES::BLOCKSIZE]; memset(iv,0x30,AES::BLOCKSIZE); //解密 CFB_Mode<AES>::Decryption cfbDecryption(key, key.size(), iv); cfbDecryption.ProcessData((byte*)plainText, (byte*)plainText, OUT_BUF_SIZE); //返回 std::string r = plainText; return r; } std::string CFB_AESEncryptStr_BASE64(const char *key,const char *plainText) { std::string outstr; //填iv.begin byte iv[AES::BLOCKSIZE]; memset(iv,0x30,AES::BLOCKSIZE); //填iv.end AES::Encryption aesEncryption((byte *)key, AES::DEFAULT_KEYLENGTH); CFB_Mode_ExternalCipher::Encryption cfbEncryption(aesEncryption, iv); StreamTransformationFilter cfbEncryptor(cfbEncryption, new Base64Encoder(new StringSink(outstr))); cfbEncryptor.Put((byte *)plainText, strlen(plainText)); //对明文进行16字节对齐.begin const int nPadding = strlen(plainText)%16; byte *padding; if(nPadding!=0) { padding = new byte[16-nPadding]; memset(padding,0,16-nPadding); cfbEncryptor.Put(padding, 16-nPadding); } //对明文进行16字节对齐.end cfbEncryptor.MessageEnd(); delete padding; return outstr; } std::string CFB_AESDecryptStr_BASE64(const char *key,const char *cipherText) { std::string outstr; //填iv.begin byte iv[AES::BLOCKSIZE]; memset(iv,0x30,AES::BLOCKSIZE); //填iv.end CFB_Mode<AES >::Decryption cfbDecryption((byte *)key, AES::DEFAULT_KEYLENGTH, iv); Base64Decoder decryptor(new StreamTransformationFilter(cfbDecryption, new StringSink(outstr))); decryptor.Put((byte *)cipherText, strlen(cipherText)); decryptor.MessageEnd(); return outstr; } const int TAG_SIZE = 16; bool GCM_AESEncryptStr(const std::string &sKey,const std::string &sAuth,const std::string &sPlain, byte iv[16],std::string &sCipher) { #ifdef _DEBUG std::cout << "Algorithm name=" << AES::StaticAlgorithmName() << std::endl; std::cout << "AES::DEFAULT_KEYLENGTH=" <<AES::DEFAULT_KEYLENGTH<<std::endl; std::cout << "AES::MIN_KEYLENGTH=" <<AES::MIN_KEYLENGTH<<std::endl; std::cout << "AES::MAX_KEYLENGTH=" <<AES::MAX_KEYLENGTH<<std::endl; #endif /* if(sKey.length()!=AES::DEFAULT_KEYLENGTH) sKey.resize(AES::DEFAULT_KEYLENGTH,' '); */ AutoSeededRandomPool rnd; //iv 是一个增量值,可以随便取一个字符串 //加密使用的iv要和解密的一样 std::cout<<"AES::BLOCKSIZE="<<AES::BLOCKSIZE<<std::endl; assert(AES::BLOCKSIZE==16); rnd.GenerateBlock(iv, AES::BLOCKSIZE); // Encrypted, with Tag try { GCM< AES >::Encryption e; e.SetKeyWithIV( (byte*)sKey.c_str(), AES::DEFAULT_KEYLENGTH, iv, sizeof(iv) ); AuthenticatedEncryptionFilter ef( e, new StringSink( sCipher ), false, TAG_SIZE /* MAC_AT_END */ ); // AuthenticatedEncryptionFilter // AuthenticatedEncryptionFilter::ChannelPut // defines two channels: DEFAULT_CHANNEL and AAD_CHANNEL // DEFAULT_CHANNEL is encrypted and authenticated // AAD_CHANNEL is authenticated ef.ChannelPut( AAD_CHANNEL, (byte *)sAuth.c_str(), sAuth.length() ); ef.ChannelMessageEnd(AAD_CHANNEL); // Authenticated data *must* be pushed before // Confidential/Authenticated data. Otherwise // we must catch the BadState exception ef.ChannelPut( DEFAULT_CHANNEL, (byte *)sPlain.c_str(), sPlain.length() ); ef.ChannelMessageEnd(DEFAULT_CHANNEL); } catch( CryptoPP::Exception& e ) { cerr << "Caught Exception..." << endl; cerr << e.what() << endl; cerr << endl; return false; } return true; } bool GCM_AESDecryptStr(const std::string &sKey,const std::string &sAuth,const std::string &sCipher,const byte iv[16], std::string &sPlain) { try { GCM< AES >::Decryption d; d.SetKeyWithIV( (byte*)sKey.c_str(), AES::DEFAULT_KEYLENGTH, iv, sizeof(iv) ); // Break the cipher text out into it's // components: Encrypted and MAC string enc = sCipher.substr( 0, sCipher.length()-TAG_SIZE ); string mac = sCipher.substr( sCipher.length()-TAG_SIZE );//最后TAG_SIZE个字节是MAC码 // Sanity checks if( sCipher.size() != enc.size() + mac.size() ) return false; if( TAG_SIZE != mac.size() ) return false; // Object *will* throw an exception // during decryption\verification _if_ // verification fails. AuthenticatedDecryptionFilter df( d, NULL, AuthenticatedDecryptionFilter::Flags::MAC_AT_BEGIN | AuthenticatedDecryptionFilter::Flags::THROW_EXCEPTION, TAG_SIZE ); // The order of the following calls are important df.ChannelPut( DEFAULT_CHANNEL, (byte *)mac.data(), mac.size() ); df.ChannelPut( AAD_CHANNEL, (byte *)sAuth.data(), sAuth.size() ); df.ChannelPut( DEFAULT_CHANNEL, (byte *)enc.data(), enc.size() ); // If the object throws, it will most likely occur // during ChannelMessageEnd() df.ChannelMessageEnd( AAD_CHANNEL ); df.ChannelMessageEnd( DEFAULT_CHANNEL ); // If the object does not throw, here's the only // opportunity to check the data's integrity if(! df.GetLastResult() ) return false; // Remove data from channel string retrieved; size_t n = (size_t)-1; // Plain text recovered from enc.data() df.SetRetrievalChannel( DEFAULT_CHANNEL ); n = (size_t)df.MaxRetrievable(); retrieved.resize( n ); if( n > 0 ) { df.Get( (byte*)retrieved.data(), n ); } sPlain = retrieved; } catch( CryptoPP::Exception& e ) { cerr << "Caught Exception..." << endl; cerr << e.what() << endl; cerr << endl; return false; } return true; } void SHA256_Cal(const std::string &msg,std::string &digest) { SHA256 sha256; char byDigest[ 32 + 1 ]; memset(byDigest,0,sizeof(byDigest)); sha256.CalculateDigest((byte*)byDigest, (const byte *)msg.c_str(), msg.size()); digest = byDigest; } bool SHA256_Verify(const std::string &msg,const std::string &digest) { SHA256 sha256; return sha256.VerifyDigest( (byte*)digest.c_str(), (const byte *)msg.c_str(), msg.size() ); } void GenerateRSAKey(const std::string &strSeed,std::string &strPri, std::string &strPub) { RandomPool randPool; randPool.Put((byte *)strSeed.c_str(), strSeed.length()); RSAES_OAEP_SHA_Decryptor priv(randPool, 1024);//keylength设为1024 HexEncoder privString(new StringSink(strPri)); priv.DEREncode(privString); privString.MessageEnd(); RSAES_OAEP_SHA_Encryptor pub(priv); HexEncoder pubString(new StringSink(strPub)); pub.DEREncode(pubString); pubString.MessageEnd(); } std::string RSAEncryptStr(const std::string &strPub,const std::string &strSeed, const char *plainText) { StringSource pubString(strPub, true, new HexDecoder); RSAES_OAEP_SHA_Encryptor pub(pubString); RandomPool randPool; randPool.Put((byte *)strSeed.c_str(), strSeed.length()); string result; StringSource(plainText, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result)))); return result; } RandomPool & GlobalRNG() { static RandomPool randomPool; return randomPool; } std::string RSADecryptStr(const std::string &strPri, const char *cipherText) { StringSource privString(strPri, true, new HexDecoder); RSAES_OAEP_SHA_Decryptor priv(privString); string result; StringSource(cipherText, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result)))); return result; }