这几日工作需要研究 windows 的 CrptoAPI 实现3DES加密解密,着实耗费了一番功夫
除了windows CrptoAPI之外还是openssl可以实现3des比较便捷,可是需要配置,于是我选择使用的是windows的API
我们实现的简单的ECB模式 补码模式选用PKCS#7
3DES 对应的是 24位秘钥
windows提供了自己生成 Session key 方法,利用自己的 password ,经过hash,derive等方法生成
但是我们是已经拥有了key,并不需要自己生成
所以需要自己构建
struct keyBlob{
BLOBHEADER hdr;
DWORD cbKeySize;
BYTE rgbKeyData[24];
}keyBlob;
这个结构体是为了 CryptImportKey 使用,需要满足windows内部的格式才如此麻烦
下面是初始化
keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
keyBlob.hdr.reserved = 0;
keyBlob.hdr.aiKeyAlg = CALG_3DES;
keyBlob.cbKeySize = 24;
DWORD dwLength = key.length();
for(int i = 0; i < 24; ++i)
{
keyBlob.rgbKeyData[i] = (BYTE)key[i];
}
注意 keyBlob.hdr.aiKeyAlg = CALG_3DES 这句话, 后面对应的 CALG_3DES 就是对应你选的算法。
rgbKeyData 就是你所使用的key
HCRYPTPROV hProv;
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)
这是初始化你的秘钥池,是为了Import key,import的时候需要一个池子。
接下去就是 Imoprt Key了;
HCRYPTKEY hKey;
CryptImportKey(hProv, (BYTE*)(&keyBlob), sizeof(keyBlob), 0, 0, &hKey)
DWORD dwLen = text.length();
BYTE *pCryptData = new BYTE[dwLen*2];
for(int i = 0;i < dwLen; i++)
{
pCryptData[i] = (BYTE)text[i];
}
errJiaoYan = dwLen % 8;
errJiaoYan = 8 - errJiaoYan;
for(int i = 0;i < errJiaoYan;i++)
{
pCryptData[i+dwLen] = errJiaoYan;
}
dwLen = dwLen + errJiaoYan;
if(!CryptEncrypt(hKey, 0, FALSE, 0, pCryptData, &dwLen, dwLen*2)){
int err = GetLastError();
}
最后你就完成了加密,但是此时加密的结果是一堆2进制数据,你必须通过Base64Encode一下
LPCSTR result = Base64Encode((LPCBYTE)pCryptData,dwLen);
最后记得 释放 hKey,hProv
CryptDestroyKey(hKey);
delete pCryptData;
CryptReleaseContext(hProv, 0);
#include
#include
#include
using namespace std;
#pragma comment(lib, "crypt32.lib")
LPTSTR Base64Decode(LPCTSTR lpData, DWORD &dwSize)
{
DWORD dwResult = 0;
if(CryptStringToBinary(lpData, dwSize, CRYPT_STRING_BASE64, NULL, &dwResult,NULL,NULL))
{
LPTSTR lpszBase64Decoded = new TCHAR[dwResult+(sizeof(TCHAR) * 2)];
memset(lpszBase64Decoded,0,dwResult);
if(CryptStringToBinary(lpData, dwSize, CRYPT_STRING_BASE64,(BYTE *)lpszBase64Decoded, &dwResult,NULL,NULL))
{
dwSize = dwResult;
return lpszBase64Decoded;
}
}
return NULL;
}
LPTSTR Base64Encode(LPCBYTE lpData, DWORD dwSize)
{
DWORD dwResult = 0;
if(CryptBinaryToString(lpData, dwSize, CRYPT_STRING_BASE64, NULL, &dwResult))
{
LPTSTR lpszBase64 = new TCHAR[dwResult];
if(CryptBinaryToString(lpData, dwSize, CRYPT_STRING_BASE64, lpszBase64, &dwResult))
{
TCHAR pByteLF = *(LPWORD)(lpszBase64 + dwResult -1);
TCHAR pByteCR = *(LPWORD)(lpszBase64 + dwResult -2);
if(pByteCR == 0x0D && pByteLF == 0x0A)
{
*(LPWORD)(lpszBase64 + dwResult -2) = 0;
}
return lpszBase64;
}
}
return NULL;
}
BOOL Encrypt3DES(string key,string text, string& encrpted){
int errJiaoYan = 0;
struct keyBlob{
BLOBHEADER hdr;
DWORD cbKeySize;
BYTE rgbKeyData[24];
}keyBlob;
keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
keyBlob.hdr.reserved = 0;
keyBlob.hdr.aiKeyAlg = CALG_3DES;
keyBlob.cbKeySize = 24;
DWORD dwLength = key.length();
for(int i = 0; i < 24; ++i)
{
keyBlob.rgbKeyData[i] = (BYTE)key[i];
}
HCRYPTPROV hProv;
if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0))
{
HCRYPTKEY hKey;
if (CryptImportKey(hProv, (BYTE*)(&keyBlob), sizeof(keyBlob), 0, 0, &hKey))
{
DWORD dwMode = CRYPT_MODE_ECB;
CryptSetKeyParam(hKey, KP_MODE, (BYTE*)(&dwMode), 0);
DWORD dwLen = text.length();
BYTE *pCryptData = new BYTE[dwLen*2];
for(int i = 0;i < dwLen; i++)
{
pCryptData[i] = (BYTE)text[i];
}
errJiaoYan = dwLen % 8;
errJiaoYan = 8 - errJiaoYan;
for(int i = 0;i < errJiaoYan;i++)
{
pCryptData[i+dwLen] = errJiaoYan;
}
dwLen = dwLen + errJiaoYan;
if(!CryptEncrypt(hKey, 0, FALSE, 0, pCryptData, &dwLen, dwLen*2)){
int err = GetLastError();
}
LPCSTR result = Base64Encode((LPCBYTE)pCryptData,dwLen);
encrpted = result;
CryptDestroyKey(hKey);
delete pCryptData;
}
CryptReleaseContext(hProv, 0);
}
return true;
}
BOOL Decrypt3DES(string key,string text, string &decrypted){
struct keyBlob{
BLOBHEADER hdr;
DWORD cbKeySize;
BYTE rgbKeyData[24];
}keyBlob;
keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
keyBlob.hdr.reserved = 0;
keyBlob.hdr.aiKeyAlg = CALG_3DES;
keyBlob.cbKeySize = 24;
int len = key.length();
for(int i = 0; i < len; i++)
{
keyBlob.rgbKeyData[i] = (BYTE)key[i];
}
HCRYPTPROV hProv;
if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0))
{
HCRYPTKEY hKey;
if (CryptImportKey(hProv, (BYTE*)(&keyBlob), sizeof(keyBlob), 0, 0, &hKey))
{
DWORD dwMode = CRYPT_MODE_ECB;
CryptSetKeyParam(hKey, KP_MODE, (BYTE*)(&dwMode), 0);
DWORD dwLen = text.length();
LPTSTR pDecryptData = Base64Decode(text.c_str(),dwLen);
BYTE *pDecrypt = (BYTE*)pDecryptData;
if(!CryptDecrypt(hKey, 0, FALSE, 0, pDecrypt, &dwLen)){
int err = GetLastError();;
cout< 0 && ch < 9 && dwLen > 0){
dwLen -= 1;
ch = 0;
}else{
break;
}
}while (true);
decrypted.assign(pDecrypt, pDecrypt + dwLen);
CryptDestroyKey(hKey);
}
CryptReleaseContext(hProv, 0);
}
return true;
}
int main(){
string key = "BU4jWNCl9W14yqdWCCgHKg49";
string text = "SP#000017#TjWGjNfphIchj0t9";
string encrpt = "pE35dbhcakaxuQ7+SQzoNKUUFMtrsMBFHPHClIX+cYA=";
string answer = " ";
BOOL bRes = Encrypt3DES(key,text,answer);
cout<
http://bbs.csdn.net/topics/300048230
http://www.vckbase.com/index.php/wv/716
http://www.mythroad.net/2012/11/01/3des%E7%AE%97%E6%B3%95java%E4%B8%8Ec%E7%9A%84%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98%E8%AF%A6%E7%BB%86%E5%88%86%E6%9E%90%E4%B8%8E%E5%AE%9E%E7%8E%B0/