1. DES算法简介

DES算法全称为Data Encryption Standard,即数据加密算法,它是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。

DES 使用一个56 位的密钥以及附加的 8 位奇偶校验位,产生最大
64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用16 个循环,使用异或置换代换移位操作四种基本运算。

DES 的常见变体是三重 DES,使用168 位的密钥对资料进行三次加密的一种机制;它通常(但非始终)提供极其强大的安全性。如果三个 56 位的子元素都相同,则三重 DES 向后兼容DES。

攻击 DES 的主要形式被称为蛮力的或彻底密钥搜索,即重复尝试各种密钥直到有一个符合为止。如果 DES 使用56 位的密钥,则可能的密钥数量是 2 的 56次方个。随着计算机系统能力的不断发展,DES 的安全性比它刚出现时会弱得多,然而从非关键性质的实际出发,仍可以认为它是足够的。不过,DES 现在仅用于旧系统的鉴定,而更多地选择新的加密标准
— 高级加密标准(AdvancedEncryption Standard,AES).

该算法被允许用于安全报文传送MAC机制密文运算,算法的详细过程在ISO8731-1、ISO8732、ISO/IEC10116中定义。

2. DES实现源码

<<DES.h>>

namespace Des
{
enum
{
ECB = 0,
CBC = 1
};
enum
{
ENCRYPT = 0,
DECRYPT = 1
}; typedef BYTE (*PSUBKEY)[16][48]; void ByteToBit(const BYTE* pIn, BYTE byBits, BYTE* pOut);
void BitToByte(const BYTE* pIn, BYTE byBits, BYTE* pOut);
void LeftShift(BYTE* pIn, BYTE byInLen, BYTE byOffset);
void Xor(const BYTE* pIn, BYTE byLen, BYTE* pInOut);
void Transform(const BYTE* pIn, const bool* pTable, BYTE len, bool* pOut);
void S_func(const BYTE in[48], BYTE out[32]);
void F_func(const BYTE ki[48], BYTE out[32]); void SetSubKey(PSUBKEY pSubKey, const BYTE Key[8]);
void DoDes(int nMode, int nOperator, const BYTE* input, int nInLen, const BYTE* key, int nKeyLen, BYTE* output, const BYTE* init_Vector= NULL);
BOOL DoDes(int nMode, int nOperator, string strText, string KEK, string &OutData,const BYTE* init_Vector = NULL);
void DoDesMac(string intText, string KEK, string &OutData, const BYTE* init_Vector = NULL);
void DoSSMac(string intText, string KEK, string &OutData,int _Length);
void DoGPMac(string intText, string KEK, string &OutData);
void RunDes(const BYTE In[8], int nType, BYTE* Key, BYTE Out[8]);
void DoDesMac(const BYTE* input, int nDataLen, const BYTE* key, int nKeyLen, BYTE* output, const BYTE* init_Vector = NULL);
void DoSSMac(const BYTE* input, int nDataLen, const BYTE* key, int nKeyLen, BYTE* output);
void DoGPMac(const BYTE* input, int nInLen, const BYTE* key, int nKeyLen, BYTE* output);
string DesVerify(string Stxt);
}

<<DES.CPP>>

namespace Des
{
// initial permutation IP
const BYTE IP_Table[64] = {
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
}; // final permutation IP^-1
const BYTE IPR_Table[64] = {
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
}; // expansion operation matrix
const BYTE E_Table[48] = {
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
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
}; // 32-bit permutation function P used on the output of the S-boxes
const BYTE P_Table[32] = {
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
}; // permuted choice table (key)
const BYTE PC1_Table[56] = {
57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
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 (table)
const BYTE PC2_Table[48] = {
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
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 BYTE LR_Table[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}; // The (in)famous S-boxes
const BYTE S_Box[8][4][16] = {
// S1
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
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
}; void ByteToBit(const BYTE* pIn, BYTE byBits, BYTE* pOut)
{
for (int i = 0; i < byBits; ++ i)
{
pOut[i] = (pIn[i >> 3] >> (7 - i & 7)) & 1;
}
} void BitToByte(const BYTE* pIn, BYTE byBits, BYTE* pOut)
{
memset(pOut, 0, byBits >> 3);
for (int i = 0; i < byBits; ++ i)
{
pOut[i >> 3] |= (pIn[i] << (7 - i & 7));
}
} void LeftShift(BYTE* pIn, BYTE byInLen, BYTE byOffset)
{
BYTE temp[256];
memcpy(temp, pIn, byOffset);
memcpy(pIn, pIn + byOffset, byInLen - byOffset);
memcpy(pIn + byInLen - byOffset, temp, byOffset);
} void Xor(const BYTE* pIn1, const BYTE* pIn2, BYTE byLen, BYTE* pInOut)
{
for (int i = 0; i < byLen; ++ i)
{
pInOut[i] = pIn1[i] ^ pIn2[i];
}
} void Transform(const BYTE* pIn, const BYTE* pTable, BYTE len, BYTE* pOut)
{
BYTE temp[64]; for (int i = 0; i < len; ++ i)
{
temp[i] = pIn[pTable[i] - 1];
}
memcpy(pOut, temp, len);
} void S_func(const BYTE in[48], BYTE out[32]) //4BIT 代替 6BIT
{
for (BYTE i = 0, j, k; i < 8; ++ i, in += 6, out += 4)
{
j = (in[0] << 1) + in[5];
k = (in[1] << 3) + (in[2] << 2) + (in[3] << 1) + in[4]; //组织SID下标 for (BYTE l = 0; l < 4; ++ l) //把相应4bit赋值
{
out[l] = (S_Box[i][j][k] >> (3 - l)) & 1;
}
}
} void F_func(const BYTE ki[48], BYTE out[32])
{
BYTE MR[48];
Transform(out, E_Table, 48, MR); //扩展置换E
Xor(ki, MR, 48, MR);
S_func(MR, out);
Transform(out, P_Table, 32, out);
} void SetSubKey(PSUBKEY pSubKey, const BYTE Key[8])
{
BYTE K[64];
BYTE* KL = &K[0];
BYTE* KR = &K[28];
ByteToBit(Key, 64, K);
Transform(K, PC1_Table, 56, K);
for (int i = 0; i < 16; ++ i)
{
LeftShift(KL, 28, LR_Table[i]);
LeftShift(KR, 28, LR_Table[i]);
Transform(K, PC2_Table, 48, (*pSubKey)[i]);
}
} void RunDes(const BYTE* In, int nOperator, const PSUBKEY pSubKey, BYTE* Out)
{
BYTE M[64];
BYTE temp[32];
BYTE* li = &M[0];
BYTE* ri = &M[32];
ByteToBit(In, 64, M);
Transform(M, IP_Table, 64, M); //
if (ENCRYPT == nOperator)
{
for (int i = 0; i < 16; ++ i)
{
memcpy(temp, ri, 32); //Ri[i-1] 保存
F_func((*pSubKey)[i], ri); //Ri[i-1]经过转化和SBox输出为P盒
Xor(li, ri, 32, ri); //Ri[i] = P XOR Li[i-1]
memcpy(li, temp, 32); //Li[i] = Ri[i-1]
}
}
else
{
for (int i = 15; i >= 0; --i)
{
memcpy(temp, ri, 32); //Ri[i-1] 保存
F_func((*pSubKey)[i], ri); //Ri[i-1]经过转化和SBox输出为P
Xor(li, ri, 32, ri); //Ri[i] = P XOR Li[i-1]
memcpy(li, temp, 32); //Li[i] = Ri[i-1]
}
}
LeftShift(M, 64, 32); //Ri与Li换位重组M
Transform(M, IPR_Table, 64, M); //最后结果进行转化
BitToByte(M, 64, Out); //组织成字符
} void DoDes(int nMode, int nOperator, const BYTE* input, int nInLen, const BYTE* key, BYTE nKeyLen, BYTE* output, const BYTE* init_Vector)
{
BYTE bySubKey[3][16][48]; //秘钥
memset(bySubKey, 0x01, sizeof(bySubKey)); //构造并生成SubKeys
BYTE nKey = (nKeyLen >> 3) > 3 ? 3 : (nKeyLen >> 3);
for (int i = 0; i < nKey; i++)
{
SetSubKey(&bySubKey[i], &key[i << 3]);
} int j = nInLen >> 3;
if (nMode == ECB) //ECB模式
{
if (1 == nKey) //单Key
{
for (int i = 0; i < j; ++i, output += 8, input += 8)
{
RunDes(input, nOperator, &bySubKey[0], output);
}
}
else if (2 == nKey) //3DES 2Key
{
for (int i = 0; i < j; ++i, output += 8, input += 8)
{
RunDes(input, nOperator, &bySubKey[0], output);
RunDes(output, !nOperator, &bySubKey[1], output);
RunDes(output, nOperator, &bySubKey[0], output);
}
}
else //3DES 3Key
{
for (int i = 0; i < j; ++i, output += 8, input += 8)
{
RunDes(input, nOperator, &bySubKey[nOperator ? 2 : 0], output);
RunDes(output, !nOperator, &bySubKey[1], output);
RunDes(output, nOperator, &bySubKey[nOperator ? 0 : 2], output);
}
}
}
else //CBC模式 如果init_Vector为NULL则设置初始向量为8字节的0
{
BYTE byVector[8]; //扭转向量
BYTE byTemp[8]; //中间变量 memset(byVector, 0x00, sizeof(byVector));
memset(byTemp, 0x00, sizeof(byTemp)); if (init_Vector)
{
memcpy(byVector, init_Vector, 8);
} if (nKey == 1) //单Key
{
for (int i = 0; i < j; ++i, output += 8, input += 8)
{
if (ENCRYPT == nOperator)
{
Xor(input, byVector, 8, byTemp); //将输入与扭转变量异或
}
else
{
memcpy(byTemp, input, 8);
} RunDes(byTemp, nOperator, &bySubKey[0], output); if (ENCRYPT == nOperator)
{
memcpy(byVector, output, 8); //将输出设定为扭转变量
}
else
{
Xor(output, byVector, 8, output); //将输出与扭转变量异或 memcpy(byVector, byTemp, 8); //将输入设定为扭转变量
}
}
}
else if (nKey == 2) //3DES CBC 2Key
{
for (int i = 0; i < j; ++i, output += 8, input += 8)
{
if (ENCRYPT == nOperator)
{
for (int j = 0; j < 8; ++j) //将输入与扭转变量异或
{
byTemp[j] = input[j] ^ byVector[j];
}
}
else
{
memcpy(byTemp, input, 8);
} RunDes(byTemp, nOperator, &bySubKey[0], output);
RunDes(output, !nOperator, &bySubKey[1], output);
RunDes(output, nOperator, &bySubKey[0], output); if (ENCRYPT == nOperator)
{
memcpy(byVector, output, 8); //将输出设定为扭转变量
}
else
{
for (int j = 0; j < 8; ++j) //将输出与扭转变量异或
{
output[j] = output[j] ^ byVector[j];
}
memcpy(byVector, byTemp, 8); //将输入设定为扭转变量
}
}
}
else //3DES CBC 3Key
{
for (int i = 0; i < j; ++i, output += 8, input += 8)
{
if (ENCRYPT == nOperator)
{
for (int j = 0; j < 8; ++j) //将输入与扭转变量异或
{
byTemp[j] = input[j] ^ byVector[j];
}
}
else
{
memcpy(byTemp, input, 8);
} RunDes(byTemp, nOperator, &bySubKey[nOperator ? 2 : 0], output);
RunDes(output, !nOperator, &bySubKey[1], output);
RunDes(output, nOperator, &bySubKey[nOperator ? 0 : 2], output); if (ENCRYPT == nOperator)
{
memcpy(byVector, output, 8); //将输出设定为扭转变量
}
else
{
for (int j = 0; j < 8; ++j) //将输出与扭转变量异或
{
output[j] = output[j] ^ byVector[j];
}
memcpy(byVector, byTemp, 8); //将输入设定为扭转变量
}
}
}
}
} BOOL DoDes(int nMode, int nOperator, string strText, string KEK, string &OutData,const BYTE* init_Vector)
{
BYTE key[33]= {0};
BYTE input[512] = {0};
BYTE output[512] = {0};
int nInLen = strText.length()/2;
BYTE nKeyLen=(BYTE)KEK.length()/2;
strings::HexToAsc(strText, input);
strings::HexToAsc(KEK, key);
if(nInLen%8!=0 || nKeyLen%8!=0 || nInLen==0 || nKeyLen==0){
return false;
} DoDes(nMode, nOperator, input, nInLen, key, nKeyLen, output, init_Vector);
strings::AscToHex(output, nInLen, OutData);
return true;
} //ANSI X9.9 MAC DES CBC
void DoDesMac(string intText, string KEK, string &OutData, const BYTE* init_Vector)
{
BYTE byVector[8];
BYTE byTemp[8];
BYTE byData[128]; BYTE Input[512]={0};
BYTE Key[512]={0};
int nInLen;
BYTE nKeyLen;
BYTE Output[512]={0}; BYTE *input=Input;
BYTE *key=Key;
BYTE *output=Output; nInLen=(BYTE)intText.length()/2;
nKeyLen=(BYTE)KEK.length()/2; strings::HexToAsc(intText, input);
strings::HexToAsc(KEK, key); memset(byVector, 0x00, sizeof(byVector));
memset(byTemp, 0x00, sizeof(byTemp));
memset(byData, 0x00, sizeof(byData)); BYTE bySubKey[3][16][48]; //秘钥 memset(bySubKey, 0x01, sizeof(bySubKey)); //构造并生成SubKeys
BYTE nKey = (nKeyLen >> 3) > 3 ? 3 : (nKeyLen >> 3);
for (int i = 0; i < nKey; i ++ )
{
SetSubKey(&bySubKey[i], &key[i << 3]);
} int j = nInLen >> 3; if (init_Vector != NULL)
{
memcpy(byVector, init_Vector, 8);
} if (1 == nKey) //单倍长Key(8字节)
{
for (int i = 0; i < j; ++ i, input += 8)
{
Xor(input, byVector, 8, byTemp);
RunDes(byTemp, ENCRYPT, &bySubKey[0], output); memcpy(byVector, output, 8); //将输出设定为扭转变量
}
}
else if (2 == nKey) //双倍长Key(16字节)
{
for (int i = 0; i < j; ++ i, input += 8)
{
Xor(input, byVector, 8, byTemp);
RunDes(byTemp, ENCRYPT, &bySubKey[0], output);
RunDes(output, DECRYPT, &bySubKey[1], output);
RunDes(output, ENCRYPT, &bySubKey[0], output); memcpy(byVector, output, 8); //将输出设定为扭转变量
}
}
else //三倍长Key(24字节) 尚未验证
{
for (int i = 0; i < j; ++ i, input += 8)
{
Xor(input, byVector, 8, byTemp);
RunDes(byTemp, ENCRYPT, &bySubKey[0], output);
RunDes(output, DECRYPT, &bySubKey[1], output);
RunDes(output, ENCRYPT, &bySubKey[2], output); memcpy(byVector, output, 8); //将输出设定为扭转变量
}
} strings::AscToHex(Output, 8, OutData);
} //该函数的计算结果与卫士通dll计算MAC的结果一样
//input中要有80 + 00.... input的前8字节作为初始向量
void DoSSMac(string intText, string KEK, string &OutData,int _Length)
{
int nInLen=(int)intText.length()/2;
int nKeyLen=(int)KEK.length()/2;
unsigned char *input = new unsigned char[nInLen];
unsigned char *key = new unsigned char[nKeyLen]; strings::HexToAsc((const unsigned char*)intText.c_str(), nInLen*2, input);
strings::HexToAsc((const unsigned char*)KEK.c_str(), nKeyLen*2, key); BYTE byInitVec[8]; //初始向量
BYTE byTemp[8];
BYTE output[8];
memset(byInitVec, 0x00, sizeof(byInitVec));
memset(byTemp, 0x00, sizeof(byTemp));
memset(output, 0x00, sizeof(output)); memcpy(byInitVec, input, 8);
BYTE bySubKey[3][16][48]; //秘钥
memset(bySubKey, 0x01, sizeof(bySubKey)); int i = 0;
int j = (nInLen >> 3); //构造并生成SubKeys
BYTE nKey = (BYTE)((nKeyLen >> 3) > 3 ? 3 : (nKeyLen >> 3));
for (i = 0; i < nKey; i ++ )
{
SetSubKey(&bySubKey[i], &key[i << 3]);
} memcpy(output, input, 8);
if (1 == nKey) //单倍长Key(8字节)
{
j--;
for (int i = 0; i < j; ++ i)
{
Xor(input + 8 * (i + 1), output, 8, output);
RunDes(output, 0, &bySubKey[0], output); //memcpy(byInitVec, output, 8); //将输出设定为扭转变量
}
}
else if (2 == nKey) //双倍长Key(16字节)
{
j -= 2;
for (i = 0; i < j; ++ i)
{
Xor(input + 8 * (i + 1), output, 8, output);
RunDes(output, 0, &bySubKey[0], output); //将输出设定为扭转变量
}
Xor(input + 8 * ( ++ i), output, 8, output); //最后一块数据和上面加密结果异或
RunDes(output, 0, &bySubKey[0], output);
RunDes(output, 1, &bySubKey[1], output);
RunDes(output, 0, &bySubKey[0], output);
}
else //三倍长Key(24字节) 尚未验证
{
//j -= 2;
for (i = 0, j = (nInLen >> 3) - 2; i < j; ++ i, input += 8)
{
Xor(input + 8 * (i + 1), output, 8, byTemp);
RunDes(byTemp, 0, &bySubKey[0], output); memcpy(byInitVec, output, 8); //将输出设定为扭转变量
}
Xor(input + 8 * i, output, 8, output);
RunDes(output, 2, &bySubKey[0], output);
RunDes(output, 1, &bySubKey[1], output);
RunDes(output, 0, &bySubKey[0], output);
}
strings::AscToHex(output, _Length , OutData);
} //input中不要自己填补80 + 00.... 初始向量固定为8字节的0
void DoGPMac(string intText, string KEK, string &OutData)
{
BYTE byInData[256]; //密钥,输入数据
BYTE byEnter[256];
BYTE byResult[256]; //算法模式,算法操作,输入,结果
int nInLen;
int nKeyLen;
BYTE Output[512]={0};
BYTE Input[512]={0};
BYTE Key[512]={0};
BYTE *input=Input;
BYTE *key=Key;
BYTE *output=Output; nInLen=intText.length()/2;
nKeyLen=KEK.length()/2; strings::HexToAsc(intText, input);
strings::HexToAsc(KEK, key); memset(byInData, 0x00, sizeof(byInData));
memcpy(byInData, input, nInLen);
byInData[nInLen] = 0x80;
nInLen ++ ;
nInLen += (8 - nInLen % 8); //80 + (nInLen % 8)个00 int j = 0;
memset(byResult, 0x00, sizeof(byResult));
for (int i = 0; i < nInLen / 8; i ++ )
{
memset(byEnter, 0x00, sizeof(byEnter));
for (j = 0; j < 8; j ++ )
{
byEnter[j + 8] = byResult[j] ^ byInData[8 * i + j]; //byEnter的前8字节(全0)为初始向量)
}
// DoSSMac(byEnter, 16, key, nKeyLen, byResult); //特别注意
} memcpy(output, byResult, 8);
strings::AscToHex(Output,strlen((char*)Output) , OutData);
} //ANSI X9.9 MAC
void DoDesMac(const BYTE* input, int nInLen, const BYTE* key, BYTE nKeyLen, BYTE* output, const BYTE* init_Vector)
{
BYTE byVector[8];
BYTE byTemp[8];
BYTE byData[128]; memset(byVector, 0x00, sizeof(byVector));
memset(byTemp, 0x00, sizeof(byTemp));
memset(byData, 0x00, sizeof(byData)); BYTE bySubKey[3][16][48]; //秘钥 memset(bySubKey, 0x01, sizeof(bySubKey)); //构造并生成SubKeys
BYTE nKey = (nKeyLen >> 3) > 3 ? 3 : (nKeyLen >> 3);
for (int i = 0; i < nKey; i++)
{
SetSubKey(&bySubKey[i], &key[i << 3]);
} int j = nInLen >> 3; if (init_Vector != NULL)
{
memcpy(byVector, init_Vector, 8);
} if (1 == nKey) //单倍长Key(8字节)
{
for (int i = 0; i < j; ++i, input += 8)
{
Xor(input, byVector, 8, byTemp);
RunDes(byTemp, ENCRYPT, &bySubKey[0], output); memcpy(byVector, output, 8); //将输出设定为扭转变量
}
}
else if (2 == nKey) //双倍长Key(16字节)
{
for (int i = 0; i < j; ++i, input += 8)
{
Xor(input, byVector, 8, byTemp);
RunDes(byTemp, ENCRYPT, &bySubKey[0], output);
RunDes(output, DECRYPT, &bySubKey[1], output);
RunDes(output, ENCRYPT, &bySubKey[0], output); memcpy(byVector, output, 8); //将输出设定为扭转变量
}
}
else //三倍长Key(24字节) 尚未验证
{
for (int i = 0; i < j; ++i, input += 8)
{
Xor(input, byVector, 8, byTemp);
RunDes(byTemp, ENCRYPT, &bySubKey[0], output);
RunDes(output, DECRYPT, &bySubKey[1], output);
RunDes(output, ENCRYPT, &bySubKey[2], output); memcpy(byVector, output, 8); //将输出设定为扭转变量
}
}
} //input中要有80+00.... input的前8字节作为初始向量
void DoSSMac(const BYTE* input, int nInLen, const BYTE* key, BYTE nKeyLen, BYTE* output)
{
BYTE byInitVec[8]; //初始向量
BYTE byTemp[8]; memset(byInitVec, 0x00, sizeof(byInitVec));
memset(byTemp, 0x00, sizeof(byTemp)); memcpy(byInitVec, input, 8); BYTE bySubKey[3][16][48]; //秘钥 memset(bySubKey, 0x01, sizeof(bySubKey)); int i = 0;
int j = (nInLen >> 3); //构造并生成SubKeys
BYTE nKey = (nKeyLen >> 3) > 3 ? 3 : (nKeyLen >> 3);
for (i = 0; i < nKey; i++)
{
SetSubKey(&bySubKey[i], &key[i << 3]);
} memcpy(output, input, 8);
if (1 == nKey) //单倍长Key(8字节)
{
j--;
for (int i = 0; i < j; ++i)
{
Xor(input + 8 * (i + 1), output, 8, output);
RunDes(output, 0, &bySubKey[0], output); //memcpy(byInitVec, output, 8); //将输出设定为扭转变量
}
}
else if (2 == nKey) //双倍长Key(16字节)
{
j -= 2;
for (i = 0; i < j; ++i)
{
Xor(input + 8 * (i + 1), output, 8, output);
RunDes(output, 0, &bySubKey[0], output); //将输出设定为扭转变量
}
Xor(input + 8 * (++i), output, 8, output); //最后一块数据和上面加密结果异或
RunDes(output, 0, &bySubKey[0], output);
RunDes(output, 1, &bySubKey[1], output);
RunDes(output, 0, &bySubKey[0], output);
}
else //三倍长Key(24字节) 尚未验证
{
//j -= 2;
for (i = 0, j = (nInLen >> 3) - 2; i < j; ++i, input += 8)
{
Xor(input + 8 * (i + 1), output, 8, byTemp);
RunDes(byTemp, 0, &bySubKey[0], output); memcpy(byInitVec, output, 8); //将输出设定为扭转变量
}
Xor(input + 8 * i, output, 8, output);
RunDes(output, 2, &bySubKey[0], output);
RunDes(output, 1, &bySubKey[1], output);
RunDes(output, 0, &bySubKey[0], output);
}
} //input中不要自己填补80+00.... 初始向量固定为8字节的0
void DoGPMac(const BYTE* input, int nInLen, const BYTE* key, int nKeyLen, BYTE* output)
{
BYTE byInData[256]; //密钥,输入数据
BYTE byEnter[256];
BYTE byResult[256]; //算法模式,算法操作,输入,结果 memset(byInData, 0x00, sizeof(byInData));
memcpy(byInData, input, nInLen);
byInData[nInLen] = 0x80;
nInLen++;
nInLen += (8 - nInLen % 8); //80 + (nInLen % 8)个00 int j = 0;
memset(byResult, 0x00, sizeof(byResult));
for (int i = 0; i < nInLen / 8; i++)
{
memset(byEnter, 0x00, sizeof(byEnter));
for (j = 0; j < 8; j++)
{
byEnter[j + 8] = byResult[j] ^ byInData[8 * i + j]; //byEnter的前8字节(全0)为初始向量)
}
DoSSMac(byEnter, 16, key, (BYTE)nKeyLen, byResult); //特别注意
} memcpy(output, byResult, 8);
} string DesVerify(string Stxt)
{
string OutPut;
DoDes(ECB, ENCRYPT, "0000000000000000", Stxt, OutPut);
return OutPut.substr(0, 6);
}
}

3. DES加解密工具

Des工具可以实现Des,3Des,Mac,Disp(离散)等功能,支持批量Des计算(需选择File)。对数据不足8的倍数字节实现自动补齐。DES工具下载地址:http://download.csdn.net/detail/yxstars/7728833,软件界面如下:

文/yanxin8原创,获取更多信息请移步至yanxin8.com...

算法系列1《DES》的更多相关文章

  1. 5.Java 加解密技术系列之 DES

    Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比 ...

  2. JAVA算法系列 冒泡排序

    java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...

  3. JAVA算法系列 快速排序

    java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...

  4. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  5. 三白话经典算法系列 Shell排序实现

    山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...

  6. Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx  Aitit algo fix 算法系列补充.docx Atiitt 兼容性提示的艺术 attilax总结.docx Atitit 应用程序容器化总结 v2 s66.docx Atitit file cms api

    Atitit s2018.6 s6  doc list on com pc.docx Atitit s2018.6 s6  doc list on com pc.docx  Aitit algo fi ...

  7. 【C#实现漫画算法系列】-判断 2 的乘方

    微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...

  8. 玩转算法系列--图论精讲 面试升职必备(Java版)

    第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...

  9. 数据结构与算法系列——排序(4)_Shell希尔排序

    1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...

  10. 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归

    知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...

随机推荐

  1. CODESOFT 2015中的二维码该怎样生成

    由于二维条码具有储存量大.保密性高.追踪性高.抗损性强.备援性大.成本便宜等特性,其应用 渐趋广泛,因此二维码的制作对于CODESOFT条码设计软件的用户来讲可谓司空见惯.我们最常见的二维码要数QR码 ...

  2. IIS发布,图片和样式显示不了的问题

    今天本地IIS部署在visual stuio 2013里运行成功的一个项目时,出现了样式和图片显示不了的情况,如下图 所有页面的样式和图片不显示,刚开始以为是发布之后的图片和样式的文件夹没有权限,可是 ...

  3. 慕课网-安卓工程师初养成-1-3 使用记事本编写Java程序

    来源:http://www.imooc.com/video/1501 step1: myProgram.java    源文件       使用记事本编辑 step2: compiler        ...

  4. 将U盘分成 启动盘+文件存储区

    我看了很多帖子,发现想要将U盘分区的朋友绝大部分是和我一样,想用U盘做成一个启动盘同时兼顾文件存储,分区的目的很简单,就是想将启动部分单独做成一个区,以免在日常的应用中使得启动文件染毒或者误操作造成损 ...

  5. 在使用 百度编辑器 Ueditor 时,不能进入 Controller 相应的 Action 的处理方法

    如果在前端的页面中使用了 Ueditor 编辑器,那么在提交表单数据时,将不会执行 期望的 Controller 中的 Action ,造成这样的原因是: 在 MVC 4 的框架中,当前端页面需要提交 ...

  6. AX 利用windows粘贴板功能实现批量数据快速导出EXCEL

    static void test(Args _args) { int lineNum; int titleLines; SysExcelApplication excel; SysExcelWorkb ...

  7. css3多列example

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. rel=nofollow

    nofollow是什么意思? nofollow是html标签的一个属性值,Google推荐使用nofollow,告诉机器(爬虫)无需追踪目标页,是指禁止蜘蛛爬行和传递权重,但是如果你是通过sitema ...

  9. Knockout.Js官网学习(text绑定)

    前言 text 绑定到DOM元素上,使得该元素显示的文本值为你绑定的参数.该绑定在显示<span>或者<em>上非常有用,但是你可以用在任何元素上. 简单绑定 Today's ...

  10. 常见的HTTP错误总结

    一般来说HTTP2XX,代表请求正常完成,HTTP3XX代表网站重定向,HTTP4XX,代表客户端出现错误,HTTP5XX,代服务器端出现了错误 HTTP301:请求的数据具有新的位置 HTTP302 ...