可以相互解密的C#版及C++版DES算法代码(包括ECB、CBC模式,Zeros、PKCS7填充,以及Base64编解码)

由于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#代码相互解密。如有不妥之处,欢迎大家提出宝贵意见。

你可能感兴趣的:(技术应用)