算法系列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 ...
随机推荐
- 慕课网-安卓工程师初养成-2-7 Java中变量的使用规则
来源:http://www.imooc.com/code/1242 不得不接受的变量小脾气: 1.Java 中的变量需要先声明后使用 2.变量使用时,可以声明变量的同时进行初始化,也可以先声明后赋值 ...
- 终于解决了PHP调用SOAP过程中的种种问题。(转)
最近在做公司和第三方的一个合作项目,需要调用统一验证接口和统一支付接口.由于牵涉公司机密,所以我要单独写一层PHP的接口给第三方用.前面那个验证接口主要卡在了des加密的方式上,这个有时间再说.这篇主 ...
- 【HTML/XML 8】XSL,可扩展样式表语言
导读:上篇博客说了在XML文档中实现表现形式的一种形式:CSS层叠样式表,本篇博客将接着说明其另一种实现方式XSL,并将分析XSL和CSS之间的 关系. 一.XSL简介 XSL(eXtensible ...
- AX 利用windows粘贴板功能实现批量数据快速导出EXCEL
static void test(Args _args) { int lineNum; int titleLines; SysExcelApplication excel; SysExcelWorkb ...
- js对象的相关操作方法
//在js的对象中可以直接将一个方法赋值给一个属性,这种方法非常好用. //在js中虽然没有像其他语言中的class关键字,但是我们也可以用函数,字面量的方式来模拟. var myHome={ nam ...
- HBase优化
1.hbase的balance策略是region数量策略,即维持每个regionserver的region数量基本一致,这并未考虑一个table的region可能都落到一个refionserver的不 ...
- CentOS 安裝 VMware Workstation / VMware Player
参考:http://www.vixual.net/blog/archives/650 序列号:1F04Z-6D111-7Z029-AV0Q4-3AEH8 注意说明:刚开始有很长的一系列协议信息,可以用 ...
- aspx网页相对布局
网页的布局 <body bgcolor="#b6b7bc"> <form id="form1" runat="server" ...
- 2.3搭建Android应用程序开发环境
1.安装Android SDK (1)首选下载Android SDK: (2)下载完成之后,在Ubuntu系统下进行解压: (3)解压完成之后,配置环境变量: ①用vim打开/etc/profile文 ...
- 淮安团购网美团联盟网赚版 v5.7
淮安团购网,主要是利用美团联盟的hao123版API大家可以注册http://union.meituan.com获取api 核心采用dede5.7所以在安装上没有大的问题,安装好后后台恢复备份就可以了 ...