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

来源:互联网 发布:linux系统安装教程图解 编辑:程序博客网 时间:2024/06/15 15:00

由于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{    /// <summary>    /// 核心模塊的公用涵數類別。    /// </summary>    [Serializable]    public class Tools    {        /// <summary>        /// 常量。        /// </summary>        private static String _ConstValue = "HELLOYOU"; //8碼        /// <summary>        /// 使用DES加密        /// </summary>        /// <param name="Str">待加密的字符串</param>        /// <param name="IncludeLocalInfo">是否包含本地硬件訊息。</param>        /// <returns>加密后的字符串</returns>        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 "";        }        /// <summary>        /// 使用DES解密        /// </summary>        /// <param name="Str">待解密的字符串</param>        /// <param name="IncludeLocalInfo">是否包含本地硬件訊息。</param>        /// <returns>解密后的字符串</returns>        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 <vcl.h>//---------------------------------------------------------------------------////////////////////////////////////////////////////////////////////////                                                                  //// 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个0x00PAD_ISO_2,      // ISO_2填充:数据长度不足8比特的倍数,以0x80,0x00..补足,如果为8比特的倍数,补0x80,0x00..0x00PAD_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 <iostream>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];        //密钥    //构造并生成SubKeysunsigned char nKey = (keylen>>3)>=3 ? 3: (keylen>>3);    for(int i=0;i<nKey;i++)    {        SetSubKey(&m_SubKey[i],&Key[i<<3]);    }    if(bMode == ECB)    //ECB模式    {        if(nKey ==  1)  //单Key        {            int j = padlen>>3;            for(int i=0,j = padlen>>3;i<j;++i,outbuf+=8,tempBuf+=8)            {                DES(outbuf,tempBuf,&m_SubKey[0],bType);            }        }        else        if(nKey == 2)   //3DES 2Key        {            for(int i=0,j = padlen>>3;i<j;++i,outbuf+=8,tempBuf+=8)            {                DES(outbuf,tempBuf,&m_SubKey[0],bType);                DES(outbuf,outbuf,&m_SubKey[1],!bType);                DES(outbuf,outbuf,&m_SubKey[0],bType);            }        }        else            //3DES 3Key        {            for(int i=0,j=padlen>>3;i<j;++i,outbuf+=8,tempBuf+=8)            {                DES(outbuf,tempBuf,&m_SubKey[bType? 2 : 0],bType);                DES(outbuf,outbuf,&m_SubKey[1],!bType);                DES(outbuf,outbuf,&m_SubKey[bType? 0 : 2],bType);            }        }    }    else                //CBC模式{unsigned char   cvec[8] =   ""; // 扭转向量unsigned char   cvin[8] =   ""; // 中间变量memcpy(cvec, Iv, 8);        if(nKey == 1)   //单Key        {for(int i=0,j=padlen>>3;i<j;++i,outbuf+=8,tempBuf+=8)            {if(bType    ==  TDES::ENCRYPT)                {                    for(int j=0;j<8;++j)     //将输入与扭转变量异或                    {                        cvin[j] =   tempBuf[j] ^ cvec[j];                    }                }                else                {                    memcpy(cvin,tempBuf,8);                }                DES(outbuf,cvin,&m_SubKey[0],bType);                if(bType    ==  TDES::ENCRYPT)                {                    memcpy(cvec,outbuf,8);         //将输出设定为扭转变量                }                else                {for(int j=0;j<8;++j)     //将输出与扭转变量异或                    {outbuf[j]  =   outbuf[j] ^ cvec[j];                    }                    memcpy(cvec,cvin,8);            //将输入设定为扭转变量                }}}        else        if(nKey == 2)   //3DES CBC 2Key        {            for(int i=0,j=padlen>>3;i<j;++i,outbuf+=8,tempBuf+=8)            {                if(bType    ==  TDES::ENCRYPT)                {                    for(int j=0;j<8;++j)     //将输入与扭转变量异或                    {cvin[j] =   tempBuf[j] ^ cvec[j];                    }}                else                {                    memcpy(cvin,tempBuf,8);                }                DES(outbuf,cvin,&m_SubKey[0],bType);                DES(outbuf,outbuf,&m_SubKey[1],!bType);                DES(outbuf,outbuf,&m_SubKey[0],bType);                if(bType    ==  TDES::ENCRYPT)                {                    memcpy(cvec,outbuf,8);         //将输出设定为扭转变量                }                else                {                    for(int j=0;j<8;++j)     //将输出与扭转变量异或                    {                        outbuf[j]  =   outbuf[j] ^ cvec[j];                    }                    memcpy(cvec,cvin,8);            //将输入设定为扭转变量                }            }        }        else            //3DES CBC 3Key        {            for(int i=0,j=padlen >>3;i<j;++i,outbuf+=8,tempBuf+=8)            {                if(bType    ==  TDES::ENCRYPT)                {                    for(int j=0;j<8;++j)     //将输入与扭转变量异或                    {                        cvin[j] =   tempBuf[j] ^ cvec[j];                    }                }                else                {                    memcpy(cvin,tempBuf,8);                }                DES(outbuf,cvin,&m_SubKey[bType ? 2 : 0],bType);                DES(outbuf,outbuf,&m_SubKey[1],!bType);                DES(outbuf,outbuf,&m_SubKey[bType ? 0 : 2],bType);                if(bType    ==  TDES::ENCRYPT){                    memcpy(cvec,outbuf,8);         //将输出设定为扭转变量                }                else                {                    for(int j=0;j<8;++j)     //将输出与扭转变量异或                    {outbuf[j]  =   outbuf[j] ^ cvec[j];                    }                    memcpy(cvec,cvin,8);            //将输入设定为扭转变量                }}        }}if(inbuf){delete []inbuf;inbuf = NULL;}if(bType == TDES::DECRYPT){if(PaddingMode    ==  PAD_ISO_1){//待补充}elseif(PaddingMode    ==  PAD_ISO_2){//待补充}elseif(PaddingMode    ==  PAD_PKCS_7){unsigned int l_Out = strlen(Out);unsigned int l_num = Out[l_Out-1];if (l_num <= 8) // 非法密文會造成此處出問題,加以保護memset(Out+l_Out-l_num, 0x00, l_num);}}return true;}/*******************************************************************/  /*  函 数 名 称:  RunPad  功 能 描 述: 根据协议对加密前的数据进行填充  参 数 说 明: bType   :类型:PAD类型In      :数据串指针Out     :填充输出串指针datalen :数据的长度padlen  :(in,out)输出buffer的长度,填充后的长度  返回值 说明: bool    :是否填充成功  修 改 历 史:2014.09.10 修改PKCS7填充算法;修改明文是8byte的整倍数时加密解密算法;修改解密算法  更 新 日 期:  2014.09.10  *//*******************************************************************/bool TDES::RunPad(bool bType, int nType, const unsigned char* In, unsigned datalen, unsigned char* Out, unsigned& padlen){    if (nType < PAD_ISO_1 || nType > 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 00ffffffvoid 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-150x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,//1  16-310x40,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 <iostream>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#代码相互解密。如有不妥之处,欢迎大家提出宝贵意见。

0 0
原创粉丝点击