由于C#中对于DES算法有标准类,所以使用起来特别简单;但C++就有点费劲了,经过整合网上资源并修改bug,现在放出完整C++DES算法代码,已测试通过。这里要特别感谢http://blog.csdn.net/bengold1979/article/details/2208930,他的代码中大部分都没问题,但是在PKCS7填充算法的加密解密中有一些问题,经过调整,目前ECB、CBC模式,Zeros、PKCS7填充算法都以可以正常运行,还有其他填充算法尚待补充。
本文所使用的加密思路是先进行DES加密然后进行Base64编码。解密反之。
1.先放出DES加密解密C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Xml;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using System.ComponentModel;
using System.Security.Cryptography;
using DES.Core;
using System.Globalization;
namespace DESConsole
{
class Program
{
static void Main(string[] args)
{
//加密示例 /E /Stext /Y
//解密示例 /D /Stext /Y
if (args.Length == 0) return;
string param1 = args[0];
string param2 = "/S";
bool IncludeLocalInfo = false;
Tools ToolObj = new Tools();
if (param1 == "/E")
{
if (args.Length >= 2)
param2 = args[1];
if (param2.Substring(0, 2) == "/S")
param2 = param2.Substring(2, param2.Length - 2);
if (args.Length >= 3)
IncludeLocalInfo = (args[2] == "Y");
Console.WriteLine("加密:{0}", Tools.Encrypt(param2, IncludeLocalInfo));
}
else if (param1 == "/D")
{
if (args.Length >= 2)
param2 = args[1];
if (param2.Substring(0, 2) == "/S")
param2 = param2.Substring(2, param2.Length - 2);
if (args.Length >= 3)
IncludeLocalInfo = (args[2] == "Y");
Console.WriteLine("解密:{0}", Tools.Decipher(param2, IncludeLocalInfo));
}
}
}
}
namespace DES.Core
{
///
/// 核心模塊的公用涵數類別。
///
[Serializable]
public class Tools
{
///
/// 常量。
///
private static String _ConstValue = "HELLOYOU"; //8碼
///
/// 使用DES加密
///
/// 待加密的字符串
/// 是否包含本地硬件訊息。
/// 加密后的字符串
public static String Encrypt(String Str, bool IncludeLocalInfo)
{
try
{
SymmetricAlgorithm sa = new DESCryptoServiceProvider();
String _Key = _ConstValue;
sa.Key = Encoding.UTF8.GetBytes(_Key);
sa.IV = Encoding.UTF8.GetBytes(_ConstValue);
//指定加密的运算模式
sa.Mode = System.Security.Cryptography.CipherMode.CBC;
//获取或设置加密算法的填充模式
sa.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
ICryptoTransform ct = sa.CreateEncryptor();
byte[] byt = Encoding.UTF8.GetBytes(Str);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(byt, 0, byt.Length);
cs.FlushFinalBlock();
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
catch { }
return "";
}
///
/// 使用DES解密
///
/// 待解密的字符串
/// 是否包含本地硬件訊息。
/// 解密后的字符串
public static String Decipher(String Str, bool IncludeLocalInfo)
{
if (null == Str || 0 == Str.Length) return "";
try
{
SymmetricAlgorithm sa = new DESCryptoServiceProvider();
String _Key = _ConstValue;
sa.Key = Encoding.UTF8.GetBytes(_Key);
sa.IV = Encoding.UTF8.GetBytes(_ConstValue);
ICryptoTransform ct = sa.CreateDecryptor();
byte[] byt = Convert.FromBase64String(Str);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(byt, 0, byt.Length);
cs.FlushFinalBlock();
cs.Close();
return Encoding.UTF8.GetString(ms.ToArray());
}
catch { }
return "";
}
}
}
2.C++代码(BCB编写)此部分请参照http://blog.csdn.net/bengold1979/article/details/2208930,我调整了DES算法函数及填充函数,其他变化不大,另外我增加了Base64编码类
(1)头文件DES.H
声明DES类及Base64编码类
//---------------------------------------------------------------------------
#ifndef DESH
#define DESH
#include
//---------------------------------------------------------------------------
//
// //
// DES.h: declaration of the TDES、TBase64、TBase64DES class. //
// //
//
/* TDES类说明
*
* 该类是DES和3DES算法类
*
*/
class TDES
{
public:
TDES();
virtual ~TDES();
//加密解密
enum
{
ENCRYPT = 0, // 加密
DECRYPT, // 解密
};
//DES算法的模式
enum
{
ECB = 0, // ECB模式
CBC // CBC模式
};
typedef bool (*PSubKey)[16][48];
//Pad填充的模式
enum
{
PAD_ISO_1 = 0, // ISO_1填充:数据长度不足8比特的倍数,以0x00补足,如果为8比特的倍数,补8个0x00
PAD_ISO_2, // ISO_2填充:数据长度不足8比特的倍数,以0x80,0x00..补足,如果为8比特的倍数,补0x80,0x00..0x00
PAD_PKCS_7 // PKCS7填充:数据长度除8余数为n,以(8-n)补足为8的倍数,如果为8比特的倍数,补8个0x08
};
/* 执行DES算法对文本加解密
*
* Description : 执行DES算法对文本加解密
* @param bType : 类型:加密ENCRYPT,解密DECRYPT
* @param bMode : 模式:ECB,CBC
* @param In : 待加密串指针
* @param Out : 待输出串指针
* @param datalen : 待加密串的长度,同时Out的缓冲区大小应大于或者等于datalen
* @param Key : 密钥(可为8位,16位,24位)支持3密钥
* @param keylen : 密钥长度,多出24位部分将被自动裁减
* @return true--成功;false--失败;
*/
static bool RunDES(bool bType, bool bMode, int PaddingMode, const unsigned char* IV, const unsigned char* In,
unsigned char* Out, unsigned datalen, const unsigned char* Key, unsigned keylen);
protected:
//计算并填充子密钥到SubKey数据中
static void SetSubKey(PSubKey pSubKey, const unsigned char Key[8]);
//DES单元运算
static void DES(unsigned char Out[8], const unsigned char In[8], const PSubKey pSubKey, bool Type);
/* 补足8位数据
*
* Description : 根据协议对加密前的数据进行填充
* @param nType : 类型:PAD类型
* @param In : 数据串指针
* @param Out : 填充输出串指针
* @param datalen : 数据的长度
* @param padlen : (in,out)输出buffer的长度,填充后的长度
* @return true--成功;false--失败;
*/
static bool RunPad(bool bType, int nType, const unsigned char* In,
unsigned datalen, unsigned char* Out, unsigned& padlen);
};
//---------------------------------------------------------------------------
/* TBase64类说明
*
* 该类是Base64编码类
*
*/
class TBase64
{
public:
static char* Base64_Encode(const char* src);
static char* Base64_Decode(const char* src);
protected:
static void Base64_Encode(unsigned char* src,unsigned char* dest, int srclen);
static void Base64_Decode(unsigned char* src, unsigned char* dest, int srclen);
static int GetLenEncode(const char* src);
static int GetLenDecode(const char* src);
};
//---------------------------------------------------------------------------
#endif
(2)DES.CPP文件请参考http://blog.csdn.net/bengold1979/article/details/2208930,我将有变动的部分贴出来。
//---------------------------------------------------------------------------
#pragma hdrstop
#include "DES.h"
#include
using namespace std;
//---------------------------------------------------------------------------
#pragma package(smart_init)
///
// //
// DES.cpp: implementation of the TDES and TBase64 class. //
// //
// Date: 2014.09.10 //
// Description: //
// DES类,支持ECB、CBC算法,PAD_ISO_1、PAD_ISO_2、PKCS7填充模式 //
// BASE64类,支持将BYTE转为Base64编码 //
// //
///
const char _ConstValue[] = {"HELLOYOU"};//8碼
。。。。。。。。。部分代码请参考上文提到的链接。。。。。。。。。。。。。。。。
/*使用示例:
*/
bool TDES::RunDES(bool bType, bool bMode, int PaddingMode, const unsigned char* Iv, const unsigned char* In,
unsigned char* Out, unsigned datalen, const unsigned char* Key, unsigned keylen)
{
memset(Out, 0x00, strlen(Out));
unsigned char* outbuf = Out;
//判断输入合法性
if(!(/*In && */outbuf && Key && /*datalen &&*/ keylen>=8)) // 空字符串加密的时候In和datalen都为0,应该去掉此判断
return false;
unsigned char* inbuf = new unsigned char[datalen + 8];
memset(inbuf, 0x00, datalen + 8);
memcpy(inbuf, In, datalen);
unsigned padlen = datalen;
// 根据填充模式填充
if (!RunPad(bType, PaddingMode, In, datalen, inbuf, padlen))
{
delete []inbuf; inbuf = NULL;
return false;
}
unsigned char* tempBuf = inbuf;
bool m_SubKey[3][16][48]; //密钥
//构造并生成SubKeys
unsigned char nKey = (keylen>>3)>=3 ? 3: (keylen>>3);
for(int i=0;i>3;
for(int i=0,j = padlen>>3;i>3;i>3;i>3;i>3;i>3;i PAD_PKCS_7)
return false;
if (In == NULL || datalen < 0 || Out == NULL)
return false;
int res = (datalen & 0x07);
if(bType == TDES::DECRYPT)
{
padlen = datalen;
memcpy(Out, In, datalen);
return true;
}
padlen = (datalen+8-res);
memcpy(Out,In,datalen);
if(nType == PAD_ISO_1)
{
memset(Out+datalen,0x00,8-res);
}
else
if(nType == PAD_ISO_2)
{
memset(Out+datalen,0x80,1);
memset(Out+datalen,0x00,7-res);
}
else
if(nType == PAD_PKCS_7)
{
memset(Out+datalen,8-res,8-res);
}
else
{
// 其他填充模式尚待补充
return false;
}
return true;
}
//转换前 aaaaaabb ccccdddd eeffffff
//转换后 00aaaaaa 00bbcccc 00ddddee 00ffffff
void TBase64::Base64_Encode(unsigned char* src,unsigned char* dest, int srclen)
{
//编码函数
unsigned char EncodeIndex[] =
{
//编码索引表
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/','='
};
int sign = 0;
for (int i = 0; i!= srclen; i++,src++,dest++)
{
switch(sign)
{
case 0://编码第1字节
*(dest) = EncodeIndex[*src >> 2];
break;
case 1://编码第2字节
*dest = EncodeIndex[((*(src-1) & 0x03) << 4) | (((*src) & 0xF0) >> 4)];
break;
case 2://编码第3字节
*dest = EncodeIndex[((*(src-1) &0x0F) << 2) | ((*(src) & 0xC0) >> 6)];
*(++dest) = EncodeIndex[(*(src) &0x3F)];//编码第4字节
break;
}
(sign == 2)?(sign = 0):(sign++);
}
switch(sign)
{
//3的余数字节,后补=处理
case 0:
break;
case 1:
// *(dest++) = EncodeIndex[((*(src-1) & 0x03) << 4) | (((*src) & 0xF0) >> 4)];
*(dest++) = EncodeIndex[((*(src-1) & 0x03) << 4) ];
*(dest++) = '=';
*(dest++) = '=';
break;
case 2:
// *(dest++) = EncodeIndex[((*(src-1) &0x0F) << 2) | ((*(src) & 0xC0) >> 6)];
*(dest++) = EncodeIndex[((*(src-1) &0x0F) << 2)];
*(dest++) = '=';
break;
default:
break;
}
}
//---------------------------------------------------------------------------
void TBase64::Base64_Decode(unsigned char* src, unsigned char* dest, int srclen)
{
unsigned char DecodeIndex[] =
{
//解码索引表
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,//0 00-15
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,//1 16-31
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x3E,0x40,0x40,0x40,0x3F,//2 32-47 43[+](0x38) 47[/](0x39)
0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x40,0x40,0x40,0x40,0x40,0x40,//3 48-63 48[0](0x34)- 57[9](0x3D) 61[=](0x40)
0x40,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,//4 64-79 65[A](0x00)- 79[O](0x0E)
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x40,0x40,0x40,0x40,0x40,//5 80-95 80[P](0x0F)- 90[Z](0x19)
0x40,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,//6 96-111 97[a](0x1A)-111[o](0x28)
0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x40,0x40,0x40,0x40,0x40 //7 112-127 122[p](0x29)-122[z](0x33)
};
//解码处理函数 //len%4 == 0总为true;
for (int i = 0; i != srclen/4; i++)//对于不足4个的不作计算
{
//每个字符,通过数组直接得到其值,比较快
*dest = (DecodeIndex[*src] << 2) | ((DecodeIndex[*(src+1)] & 0x30) >> 4);
*(dest+1) = (DecodeIndex[*(src+1)] << 4) | ((DecodeIndex[*(src+2)] &0x3C) >> 2);
*(dest+2) = ((DecodeIndex[*(src+2)] & 0x03) << 6) | (DecodeIndex[*(src+3)] & 0x3F);
src += 4;
dest += 3;
}
}
//---------------------------------------------------------------------------
//*/
int TBase64::GetLenEncode(const char* src)
{
//求编码后的长度
int len = strlen((char*)src);
return (len + (len%3 == 0? 0:(3-len%3)))/3*4 + 1;
}
//---------------------------------------------------------------------------
int TBase64::GetLenDecode(const char* src)
{
//求解码后的长度
int len = strlen(src);
return len/4*3 + 1;
}
//---------------------------------------------------------------------------
char* TBase64::Base64_Encode(const char* src)
{
int src_len = strlen(src);
int lenEncode = GetLenEncode(src);
unsigned char* Base64Out = new unsigned char[lenEncode];
memset(Base64Out, 0x00, lenEncode);
Base64_Encode((unsigned char *)src, (unsigned char *)Base64Out, src_len);//原字符长度
return Base64Out;
}
//---------------------------------------------------------------------------
char* TBase64::Base64_Decode(const char* src)
{
int lenEncode = strlen(src);
int lenDecode = GetLenDecode((const char *)src);//获得编码后字符串的再解码的长度
unsigned char* pDecodeStr = new unsigned char[lenDecode];
memset(pDecodeStr, 0x00, lenDecode);
Base64_Decode((unsigned char *)src, pDecodeStr, lenEncode);//编码后的字符长度
return pDecodeStr;
}
//---------------------------------------------------------------------------
(3)测试代码头文件Base64DES.H
//---------------------------------------------------------------------------
#ifndef Base64DESH
#define Base64DESH
#include "DES.h"
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) WINAPI void MainTest();
#endif
(4)测试代码Base64DES.CPP文件
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Base64DES.h"
#include
using namespace std;
//---------------------------------------------------------------------------
#pragma package(smart_init)
extern const char _ConstValue[];
/*
测试代码1
*/
extern "C" __declspec(dllexport) WINAPI void MainTest()
{
puts("Testing RunDES......");
char In[1024] = {0};
char Out[1024] = {0};
char Key[8] = {0};
memcpy(Key, _ConstValue, 8);
char IV[8] = {0};
memcpy(IV, _ConstValue, 8);
puts("please input your words");
gets(In);
// 对str进行DES加密,CBC + PKCS7模式
memset(Out, 0x00, 1024);
TDES::RunDES(TDES::ENCRYPT, TDES::CBC, TDES::PAD_PKCS_7, IV, In, Out, strlen(In), Key, strlen(Key));
puts("after encrypting:");
puts(Out);
// 将加密后的strout进行Base64编码
char* Base64Out = TBase64::Base64_Encode(Out);
printf("Base64编码之后,您的文件经过DES加密后的密文是:\n");
printf("%s\n", Base64Out);
// 对Base64编码的pEncodeStr进行解码
char* ByteIn = TBase64::Base64_Decode(Base64Out);
printf("Base64解码之后的明文是:\n");
puts(ByteIn);
// 用Base64解码后的pDecodeStr进行DES解密,CBC + PKCS7模式
memset(In, 0x00, 1024);
TDES::RunDES(TDES::DECRYPT, TDES::CBC, TDES::PAD_PKCS_7, IV, ByteIn, In, strlen(ByteIn), Key, strlen(Key));
printf("Base64解码之后,您的文件经过DES解密后的明文是:\n");
puts(In);
// 用未经编码的strout直接DES解密,CBC + PKCS7模式
puts("after decrypting:");
memset(In, 0x00, 1024);
TDES::RunDES(TDES::DECRYPT, TDES::CBC, TDES::PAD_PKCS_7, IV, Out, In, strlen(Out), Key, strlen(Key));
puts(In);
delete []Base64Out; Base64Out=NULL;
delete []ByteIn; ByteIn=NULL;
}
// ---------------------------------------------------------------------------
经过测试,此部分C++DES算法可以和C#代码相互解密。如有不妥之处,欢迎大家提出宝贵意见。