算法系列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 ...
随机推荐
- 图像JPEG格式介绍
1 JPG格式介绍 JPEG (Joint PhotographicExperts GROUP)是由国际标准组织和国际电话电报咨询委员会为静态图像所建立的第一个国际数字图像压缩标准,也是至今一直在使用 ...
- 用 vs2013 创建 windows service 程序
windows services 是运行在后台的服务程序,可以用 vs2013 来创建,创建的步骤如下: 1.打开 vs2013 , Files -->New Project --> wi ...
- tar: 从成员名中删除开头的“/”
在压缩文件时,当后面的备份目录使用绝对路径时,会出现: tar zcvf /usr/OutFile.tar.gz /data/CTest tar: 从成员名中删除开头的“/” 此时,对tar增加 ...
- SQL:每年每月最高的两个温度
SET QUOTED_IDENTIFIER ONGO CREATE TABLE [dbo].[Temperature]( [ID] [int] IDENTITY(1,1) NOT NULL, [Mon ...
- 关闭GS选项,解决注入后崩溃
利用CreateRemoteThread向进程注入远程代码时,一般会有以下两种做法: 利用LoadLibrary在目标进程加载指定的DLL 将代码复制到目标进程,然后启动这段代码 上面的第二种方法其实 ...
- JS实现星级评分
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- 解决服务器复制中SID冲突问题
解决服务器复制中SID冲突问题 如果你有多部的主机需要安装,最快的方法是什么?想必就是用像GHOST之类的软件来进行硬盘的复制.当然,如果是安装在虚拟机之中,则需要复制虚拟的硬盘档案即可,以微软的VP ...
- 正宗PC Unix实验环境
首先解释一下PCUNIX环境,在PC服务器上可以安装多种UNIX系统例如ScoUnix,SunSolarisx86系统,BSD系统等等,但是唯一应用在生产系统(例如邮政储蓄,证券和某些银行前置机等)的 ...
- 完成《Java编程入门》初稿
Java编程入门 现在的运维工程师不但要懂得集合网络.系统管理而且要和开发人员一起调试系统,社会上也需要"复合性"的运维人员,所以需要做运维的也要懂一些开发,知道软件系统接口的调试 ...
- html5 搖一搖
<script> // 首先在页面上要监听运动传感事件 function init(){ if (window.DeviceMotionEvent) { // 移动浏览器支持运动传感事件 ...