IoT:电子密本ECB和DES模式详解

1.ECB模式详解

 

转自:https://blog.****.net/sunqiujing/article/details/75066924

DES参考这篇博文:写的好

https://blog.****.net/qq_27570955/article/details/52442092

 

 

ECB模式(电子密码本模式)

在ECB模式中,将明文分组加密之后的结果直接作为密文分组,缺点是会容易攻击,因为明文相同的密文相同

目录

  1. 1概念
  2. 2ECB模式的优缺点

概念

ECB(Electronic Codebook,电码本)模式是分组密码的一种最基本的工作模式。在该模式下,待处理信息被分为大小合适的分组,然后分别对每一分组独立进行加密或解密处理。如下图所示:
我们可以将其理解为是一个巨大的"明文分组→密文分组"的对应表



ECB模式的优缺点

编辑

ECB模式作为一种基本工作模式,具有操作简单,易于实现的特点。同时由于其分组的独立性,利于实现并行处理,并且能很好地防止误差传播。

另一方面由于所有分组的加密方式一致,明文中的重复内容会在密文中有所体现,因此难以抵抗统计分析攻击。

因此,ECB模式一般只适用于小数据量的字符信息的安全性保护,例如**保护。
 

ECB模式优点:

1. 简单

2. 有利于并行计算

3. 误差不会被传送

 

ECB模式缺点:

1. 不能隐藏明文的模式

2. 可能对明文进行主动攻击

 

对ECB模式的攻击,截图来源自图解密码技术一书:

IoT:电子密本ECB和DES模式详解

IoT:电子密本ECB和DES模式详解

 

ECB模式的加密:

IoT:电子密本ECB和DES模式详解

#include <STRING.H>

#define IN
#define OUT

//假设加密分组为4字节一组

/**************************************************************************
*功  能:    加密算法 (与Key异或)
*参  数:    lpszData        当前明文分组数据
*           lpszKey         Key    
*           lpszDeData      加密后的结果
*
*返回值:    
**************************************************************************/
void Encrypt(IN const char *lpszData, IN const char *lpszKey, OUT char *lpszEnData)
{
    int i = 0;
    for (i = 0; i < 4; i++)
    {
        lpszEnData[i] = lpszData[i] ^ lpszKey[i];
    }
}

/**************************************************************************
*功  能:    解密算法 (再次异或还原明文)
*参  数:    lpszData        当前密文分组数据
*           lpszKey         Key    
*           lpszDeData      解密后的结果
*
*返回值:    
**************************************************************************/
void Decrypt(IN const char *lpszData, IN const char *lpszKey, OUT char *lpszDeData)
{
    int i = 0;
    for (i = 0; i < 4; i++)
    {
        lpszDeData[i] = lpszData[i] ^ lpszKey[i];
    }
}

int main(int argc, char* argv[])
{
    char *lpszData = "Hello World!";
    char szEnData[16] = {0};
    char szDeData[16] = {0};
    char *lpszKey = "1234";
    int i = 0;
    
    printf("原始数据: %s\r\n", lpszData);
    
    while (true)
    {
        if (strlen(lpszData + i) == 0)
        {
            break;
        }
        
        Encrypt(lpszData + i, lpszKey, szEnData + i);
        i += 4;
    }
    
    printf("加密后数据: %s\r\n", szEnData);
    
    i = 0;
    while (true)
    {
        if (strlen(szEnData + i) == 0)
        {
            break;
        }
        
        Decrypt(szEnData + i, lpszKey, szDeData + i);
        i += 4;
    }
    
    printf("解密后数据: %s\r\n", szDeData);
    
    return 0;
}

IoT:电子密本ECB和DES模式详解

原数据: Hello World!

加密后: yW_X^d[C^W

解密后: Hello World!

 

2.密码算法详解——DES

0 DES简介

  在20世纪60年代后期,IBM公司成立了一个由Horst Feistel负责的计算机密码学研究项目。1971年设计出密码算法LUCIFER后,该项目宣告结束。LUCIFER被卖给了伦敦的Lloyd公司,用在同样由IBM公司开发的现金发放系统上。LUCIFER是分组长度为64位、**长度为128位、具有Feistel结构的分组密码算法。因为LUCIFER非常成功,IBM决定开发一个适合于芯片实现的商业密码产品。这一次由Walter Tuchman和Carl Meyer牵头,参与者不仅有IBM公司的研究人员,而且还有美国国家安全局(NSA)的技术顾问。这次努力的结果是给出了LUCIFER的一个修订版,它的抗密码分析能力更强,而且**长度减小为56位。

  1973年,美国国家标准局(NBS)征求美国国家密码标准方案时,IBM将Tuchman-Meyer方案提交给NBS,它是所有应征方案中最好的一个,所以1977年NBS将它采纳为数据加密标准,即DES。

  以上内容直接来自与参考文献[1],参考文献[2]给出了更加详细的一些介绍,有兴趣可以阅读。

1 Feistel

  分组密码常用的结构有SP、Feistel[3]、Lai-Massey、MISTY等,其中Feistel结构的使用较为普遍,不仅DES用到了,后续的很多经典算法中都有涉及,故在此先对其进行介绍。

1.1 Feistel介绍

IoT:电子密本ECB和DES模式详解

  Feistel是以发明者Horst Feistel的名字命名的。加解密的原理如右图1,左边表示的加密过程,右边表示解密过程。

  在每一轮加密过程中,明文被分成左右两部分。

  加密和解密公式如下:

IoT:电子密本ECB和DES模式详解

  不同的是,在加密过程中,轮数和轮**从小开始递增;解密时正好相反,从最大开始递减。

  从图中可以看出,加密最后一轮的操作与前面的有所不同,最后一轮得到的两个部分没有交换,之所以这样是为了保持解密的流程和加密一致,这样在硬件设计时可以使用相同的结构,进而减少硬件面积。

  但是对于Feistel结构最本质的特点到底是什么,我也一直不太明白,比较浅显的一点认识就是:每一轮只有一半的比特位参与计算,另外一半直接作为下一轮的输入。

 

1.2 一个简单的例子

  假设明文为(L0,R0),一共有两轮计算,每轮的**分别为k0、k1,加解密的流程如图2。

IoT:电子密本ECB和DES模式详解

2 算法流程

IoT:电子密本ECB和DES模式详解

  DES算法原理如右图,相关参数如下: 

    • 明文分组长度:64 bits
    • **长度:64 bits
    • 轮数:16轮

  整个操作可以分为3部分:

    • 初始置换和逆初始置换:这是一对可逆操作,一组数字经过初始置换(或逆初始置换)后,再经过逆初始置换(或初始置换)即可恢复原来的值;
    • 每轮的加解密操作:64位明文和48为**经过一定的操作,输出64位密文;
    • 轮**计算:64位初始**经过置换、循环移位等得到16轮的**,每轮**长度为48位。

  接下来分别对这三种核心操作进行介绍。

 

 

2.1 初始置换与逆初始置换

  置换的操作如下表1、表2,将一个64位的输入通过各位的提到得到一个新的64位输出。观察可以发现x = IP-1 ( IP(x) ) = IP ( IP-1(x) )。  

  需要注意的一点是,图中的索引值从1开始(下文中的数字也类似),有些资料中是从0开始的,如果从零开始,则所有的数字减1即可。

IoT:电子密本ECB和DES模式详解

2.2 每轮的操作

  每一轮的流程如图4,从图中可以看出DES用到了Feistel结构。F即为图中虚线框的内容。

IoT:电子密本ECB和DES模式详解

                                                                                                        图4 轮操作流程

  每一轮主要涉及3中操作:

    • 扩展/置换:将32位输入扩展成48位输出,如表3;
    • S盒:将48位输入分成8组分别作为8个S盒的输入,每组6位,最高位和最低位作为行索引,中间4位作为列索引,得到一个值x(0<=x<=15),表示为二进制即为4位,8个S盒的输出和在一起正好32位。表4是S1的数值;
    • 置换:对32位输入进行位的变化,输出仍为32位,如表5。

IoT:电子密本ECB和DES模式详解

2.3 轮**扩展

  从图1和图4中可以得出,**扩展流程可以表示如下:

    1) 64位初始**P进行置换选择1,得到56位输出K;

    2) 将K循环左移一定位数,再进行置换选择2得到48位输出k1(即第一轮的**);

    3) 循环步骤2),直至得到16轮的**(k1、k2、……、k16);

    4) 结束。

  置换选择1、置换选择2和左移次数的值分别如表6、表7、表8。

 IoT:电子密本ECB和DES模式详解

3 其它密码算法

  近期介绍了DES、AES和Simon3种密码算法,他们都属于分组密码算法,后续有时间再介绍其它分组密码算法、流密码算法、杂凑函数(Hash算法)等。读者有兴趣可以参考《密码学与网络安全——原理与实践》以及网上相关资料,算法原理基本都差不多。

4 参考资料

[1] William Stallings著;王张宜等译. 密码编码学与网络安全——原理与实践(第五版)[M]. 北京:电子工业出版社,2012.1.

[2] http://en.wikipedia.org/wiki/Data_Encryption_Standard

[3] http://en.wikipedia.org/wiki/Feistel_cipher

[4] https://github.com/tarequeh/DES

 

DES代码

#include<memory.h>
#include "DES.h"
#include<stdio.h>
char szKeys[16][48];//存储16组48bit**
char szCipherText[64];//存储64位密文
char szplaintText[64];//存储64位明文
char szCiphertextInBytes[8];//储存8位密文
char szPlaintextInBytes[8];//储存8位明文字符串
char szCiphertextInBinary[65]; //储存二进制密文(64个Bits) 
char szCiphertextInHex[17]; //储存十六进制密文,最后一位存'\0'
 
// permuted choice table (PC1)
const static char PC1_Table[56] = {//64位**去掉8,16,24...等8位奇偶位,对PC1_Table进行置换,**A=0--27,
	57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,  //B=28--56 [注:数字为数组下标]
	10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
	63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
	14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
};
// permuted choice key (PC2)
const static char PC2_Table[48] = {//A,B俩个28bit的**进行i次迭代后,组合成56bit**,对PC2_Table进行置换,
	14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,//生成子**,子**与进行i次迭代的数据进行位异或操作
	23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
	41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
	44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};
// number left rotations of pc1 
const static char Shift_Table[16] = { //第i次迭代次数
	1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};
// initial permutation (IP)
const static char IP_Table[64] = {//明文数据对此表进行置换,得到新的64bit数据
	58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
	57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
	61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};
// expansion operation matrix (E)
const static char E_Table[48] = {//把IP_Table置换过的明文数据分为left,right两部分,left不变,right对E_Table进行扩展,成48bit
	32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,//然后与i次迭代生成的子**进行位异或操作,得到新的right数据
	8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
	16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
	24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
};
// The (in)famous S-boxes 
const static char S_Box[8][4][16] = {//把新的到的right48bit数据压缩成32bit,1.把48bit数据分割成8个6bit数据,
	// S1																	2.把6bit的数据第1位和第6位组合位此表纵坐标,2-5位横坐标,得到相关值
	14,  4,	13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,		//	3.把数据转为4bit  S[i]对应i次迭代的数据
	0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,		//	4.最终得到32bit数据
	4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
	15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,
	// S2 
	15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
	3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
	0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
	13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,
	// S3 
	10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
	13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
	13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
	1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,
	// S4 
	7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
	13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
	10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
	3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,
	// S5 
	2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
	14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
	4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
	11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,
	// S6 
	12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
	10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
	9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
	4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,
	// S7 
	4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
	13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
	1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
	6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,
	// S8 
	13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
	1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
	7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
	2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};
// 32-bit permutation function P used on the output of the S-boxes 
const static char P_Table[32] = {//将得到的32bit right数据按P_Table进行置换,得到新数据right
	16, 7, 20, 21, 29, 12, 28, 17, 1,  15, 23, 26, 5,  18, 31, 10,//将right与left进行位异或操作,结果赋值给right
	2,  8, 24, 14, 32, 27, 3,  9,  19, 13, 30, 6,  22, 11, 4,  25 //将本次的原始right值赋值给left
};													//得到的left和right进行下一次迭代操作
// final permutation IP^-1 
const static char IPR_Table[64] = {//将left和right结合,按IPR_Table表进行置换,结果为最终的加密数据
	40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
	38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
	36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
	34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25
};
 
extern "C" void initialization()
{
	memset(szKeys, 0, 16 * 48);
	memset(szCipherText, 0, 64);
	memset(szplaintText, 0, 64);
	memset(szCiphertextInBytes, 0, 8);
	memset(szPlaintextInBytes, 0, 8);
	memset(szCiphertextInBinary, 0, 65);
	memset(szCiphertextInHex, 0, 17);
 
 
}
extern "C" char *DES_GetszCiphertextInBytes()
{
	return szCiphertextInBytes;
}
extern "C" char *DES_GetszPlaintextInBytes()
{
	return szPlaintextInBytes;
}
extern "C" void DES_InitializeKey(char* srcBytes)
{
	char sz_64key[64] = { 0 };
	char sz_56key[56] = { 0 };
	DES_Bytes2Bits(srcBytes, sz_64key, 64);
	for (int i = 0; i < 56; i++)    //置换64位**为56位
	{
		sz_56key[i] = sz_64key[PC1_Table[i]-1];
	}
	DES_CreateSubKey(sz_56key);
}
 
extern "C" void DES_CreateSubKey(char* sz_56key)
{
	int i, j;
	char sz_leftKey[28] = { 0 };
	char sz_rightKey[28] = { 0 };
	char sz_tempL[28] = { 0 };
	char sz_tempR[28] = { 0 };
	char sz_temp56[56] = { 0 };
	memcpy(sz_leftKey, sz_56key, 28);
	memcpy(sz_rightKey, sz_56key+28, 28);
	for (i = 0; i < 16; i++)
	{
		memcpy(sz_tempL, sz_leftKey + Shift_Table[i], 28 - Shift_Table[i]); //移位操作
		memcpy(sz_tempL + 28 - Shift_Table[i], sz_leftKey, Shift_Table[i]);
 
		memcpy(sz_tempR, sz_rightKey + Shift_Table[i], 28 - Shift_Table[i]);//移位操作
		memcpy(sz_tempR + 28 - Shift_Table[i], sz_rightKey, Shift_Table[i]);
 
		memcpy(sz_temp56, sz_tempL, 28);
		memcpy(sz_temp56+28, sz_tempR, 28);
		for (j = 0; j < 48; j++)
		{
			szKeys[i][j] = sz_temp56[PC2_Table[j]-1];  //生成16组48位的子**
		}
		memcpy(sz_leftKey, sz_tempL, 28);
		memcpy(sz_rightKey, sz_tempR, 28);
	}
}
extern "C" void DES_EncryptData(char* _srcBytes) //加密8位字符串
{
	int i = 0,j=0;
	char sz_srcBits[64] = { 0 };
	char sz_shiftIP[64] = { 0 };
	char sz_srcL[32] = { 0 };
	char sz_srcR[32] = { 0 };
	char sz_resultBits[64] = { 0 };
	DES_Bytes2Bits(_srcBytes, sz_srcBits, 64);  
	for (i = 0; i < 64; i++)
	{
		sz_shiftIP[i] = sz_srcBits[IP_Table[i]-1];  //64位明文置换
	}
	memcpy(sz_srcL, sz_shiftIP, 32);
	memcpy(sz_srcR, sz_shiftIP + 32, 32);
	for (i = 0; i<16; i++)    //16次迭代操作
	{
		DES_FunctionF(sz_srcL, sz_srcR, i);
	}
	memcpy(sz_resultBits, sz_srcR, 32);  //组合left、right
	memcpy(sz_resultBits + 32, sz_srcL, 32);
 
	for (j = 0; j<64; j++)
	{
		szCipherText[j] = sz_resultBits[IPR_Table[j] - 1];   //进行逆置换
	}
	DES_Bits2Bytes(szCiphertextInBytes, szCipherText, 64);
}
extern "C" void DES_FunctionF(char* sz_srcL, char* sz_srcR, unsigned int iKey)
{
	int i = 0;
	char sz_P32[32] = { 0 };
	char sz_R[32] = { 0 };
	char sz_48R[48] = { 0 };
	char sz_key[48] = { 0 };
	char sz_xor[48] = { 0 };
	char compressData32[32] = { 0 };
	for (i = 0; i < 48; i++)	//right 扩展
	{
		sz_48R[i] = sz_srcR[E_Table[i]-1];
	}
	memcpy(sz_key, szKeys[iKey], 48);
	DES_XOR(sz_48R, sz_key, 48, sz_xor); //扩展后的right与子**进行异或操作
	DES_CompressFunc(sz_xor, compressData32);//异或结果进行压缩成32bit
	for (i = 0; i<32; i++)
	{
		sz_P32[i] = compressData32[P_Table[i] - 1]; // 压缩后的数据进行置换
	}
	DES_XOR(sz_P32, sz_srcL, 32, sz_R);  //置换后的right与left数据进行异或
 
	memcpy(sz_srcL, sz_srcR, 32);    //传入的初始right赋值给left作为下次的left
	memcpy(sz_srcR, sz_R, 32);//左右异或生成的right的值作为下次运算的right
 
}
extern "C" void DES_XOR(char* szParam1, char* szParam2, unsigned int uiParamLength, char* szReturnValueBuffer)//异或操作
{
	unsigned int i = 0;
	for (i = 0; i<uiParamLength; i++)
	{
		szReturnValueBuffer[i] = szParam1[i] ^ szParam2[i];
	}
}
extern "C" void DES_CompressFunc(char* _src48, char* _dst32)//压缩数据
{
	char tempBit[8][6] = { 0 };
	char dest4bit[4] = { 0 };
	int i = 0, X = 0, Y = 0, j = 0;
 
	for (i = 0; i<8; i++)
	{
		memcpy(tempBit[i], _src48 + i * 6, 6);
		X = (tempBit[i][0] << 1 )+ (tempBit[i][5]);
		Y = 0;
		for (j = 1; j<5; j++)
		{
			Y += tempBit[i][j] << (4 - j);
		}
		DES_Int2Bits(S_Box[i][X][Y], dest4bit);
		memcpy(_dst32 + i * 4, dest4bit, 4);
	}
}
extern "C" void DES_Bytes2Bits(char *srcBytes, char* dstBits, unsigned int sizeBits)
{
	unsigned int i = 0;
	for (i = 0; i < sizeBits; i++)
		dstBits[i] = ((srcBytes[i >> 3] << (i & 7)) & 128) >> 7;
}
 
extern "C" void DES_Bits2Bytes(char *dstBytes, char* srcBits, unsigned int sizeBits)
{
	unsigned int i = 0;
	memset(dstBytes, 0, sizeBits >> 3);
	for (i = 0; i < sizeBits; i++)
		dstBytes[i >> 3] |= (srcBits[i] << (7 - (i & 7)));
}
 
extern "C" void DES_Int2Bits(unsigned int _src, char* dstBits)
{
	unsigned int i = 0;
	for (i = 0; i < 4; i++)
		dstBits[i] = ((_src << i) & 8) >> 3;
}
 
extern "C" void DES_Bits2Hex(char *dstHex, char* srcBits, unsigned int sizeBits)
{
	unsigned int i = 0, j = 0;
	memset(dstHex, 0, sizeBits >> 2);
	for (i = 0; i < sizeBits; i++) //convert to int 0-15
		dstHex[i >> 2] += (srcBits[i] << (3 - (i & 3)));
	for (j = 0; j < (sizeBits >> 2); j++)  
		dstHex[j] += dstHex[j] > 9 ? 55 : 48; //convert to char '0'-'F'
}
                          
extern "C" void DES_Hex2Bits(char *srcHex, char* dstBits, unsigned int sizeBits)
{
	unsigned int i = 0, j = 0;
	memset(dstBits, 0, sizeBits);
	for (i = 0; i < (sizeBits >> 2); i++)
		srcHex[i] -= srcHex[i] > 64 ? 55 : 48; //convert to char int 0-15
	for (j = 0; j < sizeBits; j++)
		dstBits[j] = ((srcHex[j >> 2] << (j & 3)) & 15) >> 3;
 
}
extern "C" void DES_DecryptData(char* _srcBytes) //解密8位字符串
{
	int i = 0, j = 0;
	char sz_srcBits[64] = { 0 };
	char sz_shiftIP[64] = { 0 };
	char sz_srcL[32] = { 0 };
	char sz_srcR[32] = { 0 };
	char sz_resultBits[64] = { 0 };
	DES_Bytes2Bits(_srcBytes, sz_srcBits, 64);
	for (i = 0; i < 64; i++)
	{
		sz_shiftIP[i] = sz_srcBits[IP_Table[i] - 1];  
	}
	memcpy(sz_srcR, sz_shiftIP, 32);
	memcpy(sz_srcL, sz_shiftIP + 32, 32);
	for (i = 0; i<16; i++)    
	{
		DES_FunctionF(sz_srcR, sz_srcL, 15 - i);
	}
	memcpy(sz_resultBits, sz_srcL, 32);  
	memcpy(sz_resultBits + 32, sz_srcR, 32);
 
	for (j = 0; j<64; j++)
	{
		szplaintText[j] = sz_resultBits[IPR_Table[j] - 1];   
	}
	DES_Bits2Bytes(szPlaintextInBytes, szplaintText, 64);
}