Cryptopp使用

41 篇文章 0 订阅

头文件清单

#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;
}


 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kagula086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值