Win32 API提供了完整的加密解密解决方案,包含各种加密算法,可用于网络数据传输、数字签名。我编写的这两个类是用于网络数据传输的。CSender代表一个发送端程序,CReceiver代表一个接受端程序。这两个类是演示加密解密及传输数据过程的模型,实际使用时可根据具体情况加以修改。这段程序是在VC7/Win2000下编译调试的。我使用DES和RSA两种加密算法:DES是常规加密算法,价密解密使用相同的密钥,用于加密解密数据;RSA是公开密钥算法,用公钥加密DES密钥,用私钥解密DES密钥,保证DES密钥的安全性。由于公开密钥算法一般计算方法复杂,速度较慢,所以不用于加密大量数据。关于加密算法、公开密钥体制等概念原理兄弟我就不介绍了,太麻烦了。加密解密及传输数据过程如下:
1.发送端和接受端分别启动CSP(Windows加密服务)。
2.接受端随机生成一个RSA密钥对,并把公钥传给发送端。
3.发送端随机生成一个DES密钥,用收到的公钥加密,再发送给接受端。
4.接受端用私钥解密DES密钥。
(之后发送端和接受端就可以反复使用DES密钥传输数据了)
5.发送端用DES密钥加密数据,发送给接受端。
6.接受端用DES密钥恢复数据。
兄弟我抛砖引玉,错误不足之处请多指教。[注]
本文是根据《程序员》杂志2001年第8期文章《互联网数据传输的加密方法》写成的。
1.发送端和接受端分别启动CSP(Windows加密服务)。
2.接受端随机生成一个RSA密钥对,并把公钥传给发送端。
3.发送端随机生成一个DES密钥,用收到的公钥加密,再发送给接受端。
4.接受端用私钥解密DES密钥。
(之后发送端和接受端就可以反复使用DES密钥传输数据了)
5.发送端用DES密钥加密数据,发送给接受端。
6.接受端用DES密钥恢复数据。
兄弟我抛砖引玉,错误不足之处请多指教。[注]
本文是根据《程序员》杂志2001年第8期文章《互联网数据传输的加密方法》写成的。
解决方案 »
- 怪事,oracle性能好像没有access高.ado _CommandPtr Execute插入数据,oracle每秒130条,access每秒700.搞不明.
- 新手求助:如何在新窗口中显示一幅位图
- 用c++在visual studio.net的tools菜单下添加的button
- 怎样取得一张位图的颜色值,用来做为对话框的背景
- 关于MFC中CString.Format()的问题
- 求<<Visual C++6.0 宝典>>的光盘源码
- 怎样定义unicode标识符?
- manifest, ntstatus 0xc000000d 应用程序初始化失败?
- MFC中Slider控件垂直放置时使它的大端在上小端在下?
- 如何往注册表里写二进制串值
- 既然倒分帖需要严惩!那么倒信誉分该怎么处理???
- 用CTreeCtrl时遇到麻烦
#include "WinCrypt.h"//接收数据端
class CReceiver
{
public:
CReceiver();
virtual ~CReceiver(); //初始化CSP服务
BOOL Init(); //随机生成一个密钥对,并把公钥导出到m_pPublicKey中
BOOL CreatePublicKey(); //用私钥解密DES密钥
BOOL DecryptSessionKey(const BYTE* pSessionKey, DWORD iSessionKeySize); //用DES密钥解密数据
BOOL Decrypt(const BYTE* pCipherText, DWORD iCipherTextSize); //获得公钥的指针
const BYTE* GetPublicKey() const; //获得公钥数据的字节数
DWORD GetPublicKeySize() const; //获得解密后的明文数据指针
const BYTE* GetPlainText() const; //获得解密后的明文数据的字节数
DWORD GetPlainTextSize() const;private:
//CSP服务句柄
HCRYPTPROV m_hProv; //RSA密钥对句柄
HCRYPTKEY m_hExchangeKey; //DES密钥句柄
HCRYPTKEY m_hSessionKey; //公钥数据
BYTE* m_pPublicKey; //公钥数据的字节数
DWORD m_iPublicKeySize; //明文数据
BYTE* m_pPlainText; //明文数据的字节数
DWORD m_iPlainTextSize;
};//发送数据端
class CSender
{
public:
CSender();
virtual ~CSender(); //初始化CSP服务
BOOL Init(); //随机生成DES密钥,用公钥加密,并导出到m_pSessionKey
BOOL CreateSessionKey(const BYTE* pPublicKey, DWORD iPublicKeySize); //加密数据,pData是任意二进制数据,iDataSize是待加密数据的字节数
BOOL Encrypt(const BYTE* pData, DWORD iDataSize); //获得“块”的字节数。加密算法分为“流”加密和“块”加密,DES属于“块”加密
//本程序并未用到此函数。加密上百兆的数据一般就需要用。见MSDN关于CryptEncrypt()倒数第二个参数的说明
DWORD GetBlockSize(); //获得CSP服务版本号,Win2000/XP的CSP是2.0版本,Win98是1.0版
//1.0版好像不能使用DES加密,但可以使用RC等加密算法,我也没试过
WORD GetCSPVersion(); //获得DES密钥的指针
const BYTE* GetSessionKey() const; //获得DES密钥的字节数
DWORD GetSessionKeySize() const; //获得密文数据的指针
const BYTE* GetCipherText() const; //获得密文数据的字节数
DWORD GetCipherTextSize() const;private:
//CSP服务句柄
HCRYPTPROV m_hProv; //DES密钥句柄
HCRYPTKEY m_hSessionKey; //DES密钥数据
BYTE* m_pSessionKey; //DES密钥数据的字节数
DWORD m_iSessionKeySize; //密文数据
BYTE* m_pCipherText; //密文数据的字节数
DWORD m_iCipherTextSize;
};
#include ".\sender.h"
CReceiver::CReceiver()
{
m_hProv = NULL;
m_hExchangeKey = NULL;
m_hSessionKey = NULL;
m_pPublicKey = NULL;
m_iPublicKeySize = 0;
m_pPlainText = NULL;
m_iPlainTextSize = 0;
}CReceiver::~CReceiver()
{
if (m_pPublicKey)
delete m_pPublicKey;
if (m_pPlainText)
delete m_pPlainText; // release CSP服务
if (m_hProv)
CryptReleaseContext(m_hProv, 0);
}const BYTE* CReceiver::GetPublicKey() const
{
return m_pPublicKey;
}DWORD CReceiver::GetPublicKeySize() const
{
return m_iPublicKeySize;
}const BYTE* CReceiver::GetPlainText() const
{
return m_pPlainText;
}DWORD CReceiver::GetPlainTextSize() const
{
return m_iPlainTextSize;
}BOOL CReceiver::Init()
{
LPCTSTR sContainer = _T("ReceiverContainer"); //启动新的CSP服务
BOOL bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET); if (!bCSPOK)
{
//此CSP服务已存在,最后一个参数改为0,获得其句柄
if (GetLastError() == NTE_EXISTS)
bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, 0);
} if (!bCSPOK)
m_hProv = NULL;
return bCSPOK;
}BOOL CReceiver::CreatePublicKey()
{
ASSERT(m_hProv); //随机生成RSA密钥对
BOOL bReturn = CryptGenKey(m_hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &m_hExchangeKey); //导出公钥,第一次调用CryptExportKey()是为了计算公钥字节数,后面有很多类似的用法
bReturn = CryptExportKey(m_hExchangeKey, 0, PUBLICKEYBLOB, 0, NULL, &m_iPublicKeySize);
if (m_pPublicKey)
delete m_pPublicKey;
m_pPublicKey = new BYTE[m_iPublicKeySize];
bReturn = CryptExportKey(m_hExchangeKey, 0, PUBLICKEYBLOB, 0, m_pPublicKey, &m_iPublicKeySize); return bReturn;
}BOOL CReceiver::DecryptSessionKey(const BYTE* pSessionKey, DWORD iSessionKeySize)
{
ASSERT(m_hProv);
ASSERT(pSessionKey); //解密DES密钥
return CryptImportKey(m_hProv, pSessionKey, iSessionKeySize, m_hExchangeKey, 0, &m_hSessionKey);
}BOOL CReceiver::Decrypt(const BYTE* pCipherText, DWORD iCipherTextSize)
{
ASSERT(m_hProv);
ASSERT(m_hSessionKey);
ASSERT(pCipherText); if (m_pPlainText)
delete m_pPlainText;
m_pPlainText = new BYTE[iCipherTextSize];
CopyMemory(m_pPlainText, pCipherText, iCipherTextSize);
m_iPlainTextSize = iCipherTextSize; //解密数据保存在m_pPlainText中
return CryptDecrypt(m_hSessionKey, 0, TRUE, 0, m_pPlainText, &m_iPlainTextSize);
}
CSender::CSender()
{
m_hProv = NULL;
m_pSessionKey = NULL;
m_iSessionKeySize = 0;
m_pCipherText = NULL;
m_iCipherTextSize = 0;
}CSender::~CSender()
{
if (m_pSessionKey)
delete m_pSessionKey;
if (m_pCipherText)
delete m_pCipherText;
if (m_hProv)
CryptReleaseContext(m_hProv, 0);
}const BYTE* CSender::GetSessionKey() const
{
return m_pSessionKey;
}DWORD CSender::GetSessionKeySize() const
{
return m_iSessionKeySize;
}const BYTE* CSender::GetCipherText() const
{
return m_pCipherText;
}DWORD CSender::GetCipherTextSize() const
{
return m_iCipherTextSize;
}DWORD CSender::GetBlockSize()
{
ASSERT(m_hSessionKey); DWORD iBlockSize;
DWORD iDataSize( sizeof(DWORD) );
CryptGetKeyParam(m_hSessionKey, KP_BLOCKLEN, (BYTE*)&iBlockSize, &iDataSize, 0);
return iBlockSize;
}WORD CSender::GetCSPVersion()
{
ASSERT(m_hProv); DWORD iDataSize;
CryptGetProvParam(m_hProv, PP_VERSION, NULL, &iDataSize, 0);
BYTE* pData = new BYTE[iDataSize]; //按MSND,pData[0]是小版本号,pData[1]是主版本号
CryptGetProvParam(m_hProv, PP_VERSION, pData, &iDataSize, 0);
WORD iCSPVersion;
CopyMemory(&iCSPVersion, pData, 2);
delete pData;
return iCSPVersion;
}BOOL CSender::Init()
{
LPCTSTR sContainer = _T("SenderContainer");
BOOL bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET);
if (!bCSPOK)
{
if (GetLastError() == NTE_EXISTS)
bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, 0);
}
if (!bCSPOK)
m_hProv = NULL;
return bCSPOK;
}BOOL CSender::CreateSessionKey(const BYTE* pPublicKey, DWORD iPublicKeySize)
{
ASSERT(m_hProv);
ASSERT(pPublicKey); HCRYPTKEY hPublicKey;
BOOL bReturn = CryptImportKey(m_hProv, pPublicKey, iPublicKeySize, 0, 0, &hPublicKey); //随机生成DES密钥
bReturn = CryptGenKey(m_hProv, CALG_DES, CRYPT_EXPORTABLE, &m_hSessionKey); //用公钥加密DES密钥并导出到m_pSessionKey
bReturn = CryptExportKey(m_hSessionKey, hPublicKey, SIMPLEBLOB, 0, NULL, &m_iSessionKeySize);
if (m_pSessionKey)
delete m_pSessionKey;
m_pSessionKey = new BYTE[m_iSessionKeySize];
bReturn = CryptExportKey(m_hSessionKey, hPublicKey, SIMPLEBLOB, 0, m_pSessionKey, &m_iSessionKeySize); return bReturn;
}BOOL CSender::Encrypt(const BYTE* pData, DWORD iDataSize)
{
ASSERT(m_hProv);
ASSERT(m_hSessionKey);
ASSERT(pData); //计算需要的缓存字节数,一般大于待加密数据的字节数
//密文一般比实际要加密的数据大,如有必要,还要通知接收端实际的数据字节数
//本程序以'\0'结尾的字符串为测试数据,所以没有通知接收端实际的数据字节数
m_iCipherTextSize = iDataSize;
BOOL bReturn = CryptEncrypt(m_hSessionKey, 0, TRUE, 0, NULL, &m_iCipherTextSize, 0); if (m_pCipherText)
delete m_pCipherText;
m_pCipherText = new BYTE[m_iCipherTextSize]; ZeroMemory(m_pCipherText, m_iCipherTextSize);
CopyMemory(m_pCipherText, pData, iDataSize); //加密数据
bReturn = CryptEncrypt(m_hSessionKey, 0, TRUE, 0, m_pCipherText, &iDataSize, m_iCipherTextSize);
return bReturn;
}
//发送数据端
CSender g_Sender;
//接受数据端
CReceiver g_Receiver;//1.发送端和接受端分别启动CSP
void CSampleView::OnNetworkCspversion()
{
if ( g_Sender.Init() && g_Receiver.Init() )
MessageBox( _T("Init O.K.") );
}//2.接受端随机生成一个RSA密钥对,并把公钥传给发送端。
void CSampleView::OnNetworkPublickey()
{
VERIFY( g_Receiver.CreatePublicKey() ); CString str;
str.Format("The size of the Public Key is %d bytes.", g_Receiver.GetPublicKeySize() );
MessageBox(str);
}//3.发送端随机生成一个DES密钥,用收到的公钥加密,再发送给接受端。
void CSampleView::OnNetworkSessionkeydata()
{
VERIFY( g_Sender.CreateSessionKey( g_Receiver.GetPublicKey(), g_Receiver.GetPublicKeySize() ) ); CString str;
str.Format( "The size of the Session Key is %d bytes.", g_Sender.GetSessionKeySize() );
MessageBox(str);
}//4.接受端用私钥解密DES密钥。
void CSampleView::OnNetworkDecryptsessionkey()
{
VERIFY( g_Receiver.DecryptSessionKey( g_Sender.GetSessionKey(), g_Sender.GetSessionKeySize() ) ); MessageBox( _T("Decryption is done.") );
}//5.发送端用DES密钥加密数据,发送给接受端。
void CSampleView::OnNetworkEncryptdata()
{
//const TCHAR szPlainText[] = _T("Nobody could be happy if that happiness is rooted in the pain of others.");
const TCHAR s[] = _T("Sample Data");
VERIFY( g_Sender.Encrypt( (BYTE*)s, sizeof(s) ) ); CString str;
str.Format("Plain Text: %s", s);
MessageBox(str);
}//6.接受端用DES密钥恢复数据。
void CSampleView::OnNetworkDecryptdata()
{
VERIFY( g_Receiver.Decrypt( g_Sender.GetCipherText(), g_Sender.GetCipherTextSize() ) ); CString str;
str.Format( "Text Decrypted: %s", g_Receiver.GetPlainText());
MessageBox(str);
}