算法系列1《DES》
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》的更多相关文章
- 5.Java 加解密技术系列之 DES
Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比 ...
- JAVA算法系列 冒泡排序
java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...
- JAVA算法系列 快速排序
java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- 三白话经典算法系列 Shell排序实现
山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...
- 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 ...
- 【C#实现漫画算法系列】-判断 2 的乘方
微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...
- 玩转算法系列--图论精讲 面试升职必备(Java版)
第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...
- 数据结构与算法系列——排序(4)_Shell希尔排序
1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...
- 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归
知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...
随机推荐
- 初探接口测试框架--python系列2
点击标题下「蓝色微信名」可快速关注 坚持的是分享,搬运的是知识,图的是大家的进步,没有收费的培训,没有虚度的吹水,喜欢就关注.转发(免费帮助更多伙伴)等来交流,想了解的知识请留言,给你带来更多价值,是 ...
- Android开发-API指南-常用Intent
Common Intents 英文原文:http://developer.android.com/guide/components/intents-common.html 采集(更新)日期:2014- ...
- 缓存之Memcached
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...
- navicat 连接oracle
Navicat远程连接oracle数据库数据库需要设置一下oci.dll. 下面介绍如何进行设置. 工具/原料 Navicat Pre instantclient-basiclite-nt-12. ...
- EasyUI学习笔记
1,tabs获得被选中的标题 var tabTitle = $('#tabs').tabs('getSelected').panel('options').title;//获得被选中的标题 2.当设置 ...
- Facebook React完全解析
2004年,对于前端社区来说,是里程碑式的一年.Gmail横空出世,它带来基于前端渲染的原生应用级别的体验,相对于之前的服务端渲染网页可谓提升了一个时代,触动了用户的G点.自此,前端渲染的网站成为无数 ...
- SQL笔记-第二章,数据表的创建和管理
数据类型 分5类:整数.数值.字符相关.日期时间以及二进制 1.整数 数据库系统 类型 说明 MYSQL tinyint [unsigned] 一个很小的整数.有符号的范围是-128 到127,无符号 ...
- Html.ActionLink
一 Html.ActionLink("linkText","actionName") 该重载的第一个参数是该链接要显示的文字,第二个参数是对应的控制器的方法, ...
- 必须会的SQL语句(二) 创建表、修改表结构、删除表
1.创建数据库表 --使用哪个数据库,如果不写这一句是默认的数据库,也可以用鼠标选当前数据库 use testDB --创建表 Create Table tablename ( ...
- 第一部分 CLR基础:第2章 生成、打包、部署和管理应用程序及类型
2.1.NET Framework部署目标 Microsoft Windows多年来因不稳定和复杂而口碑不佳.造成的原因:1.应用程序都使用来自微软和厂商的动态链接库(dynamic-link lib ...