现代对称密码之DES算法Cpp源码
DES算法原理
DES(Data Encryption Standard)曾是使用最广泛的数据加密标准,这个算法本身被称为数据加密算法(DEA)。DES于1977年被美国国家标准局即现在的国家标准和技术研究所采纳为联邦信息处理标准46(FIPS PUB 46)。
DES目前被推荐在一般商业应用中使用,而不用DES来保护官方的数据,新版本的数据加密采用了三重DES。因为DES与三重DES的加密、解密方法是相同的,因此理解DES算法仍有很重要的意义。
DES目前被推荐在一般商业应用中使用,而不用DES来保护官方的数据,新版本的数据加密采用了三重DES。因为DES与三重DES的加密、解密方法是相同的,因此理解DES算法仍有很重要的意义。
DES算法的输入是64位明文,密钥长度为64位。在64位的密钥中,第8、16、24、32、40、48、56和64位是校验位,因此,DES算法的实际密钥长度是56位。DES算法的加密过程如下所示:
(1)在获得64位明文后,对明文进行一个初始置换,即IP置换。
(2)对置换后的明文进行分组,分成左半部分和右半部分。
(3)进行16轮完全相同的运算,这个运算的函数也被称为F函数。在每一轮的运算过程中使用各自不同的密钥。
(2)对置换后的明文进行分组,分成左半部分和右半部分。
(3)进行16轮完全相同的运算,这个运算的函数也被称为F函数。在每一轮的运算过程中使用各自不同的密钥。
(4)在经过16轮运算后,将左右两部分合在一起,再经过一个末置换(初始置换的逆置换),这样就完成了算法的全部过程。
DES的解密过程的算法与加密过程的算法完全一样,不同的地方有两点:第一个不同点是解密密钥的顺序与加密密钥正好相反,加密密钥分别是,解密密钥分别是。第二个不同点是子密钥产生时采用循环左移来产生子密钥,而解密密钥是通过循环右移来产生子密钥。解密子密钥循环右移的位数为:0,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1。这种解密模式是典型的Feistel密码结构的解密模式。
DES算法的核心部分是基本过程中的第3步,第3步是关于每一轮的运算过程,该运算过程的具体步骤如下图所示。
DES的解密过程的算法与加密过程的算法完全一样,不同的地方有两点:第一个不同点是解密密钥的顺序与加密密钥正好相反,加密密钥分别是,解密密钥分别是。第二个不同点是子密钥产生时采用循环左移来产生子密钥,而解密密钥是通过循环右移来产生子密钥。解密子密钥循环右移的位数为:0,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1。这种解密模式是典型的Feistel密码结构的解密模式。
DES算法的核心部分是基本过程中的第3步,第3步是关于每一轮的运算过程,该运算过程的具体步骤如下图所示。
上图的左半部分为一轮的加密过程,右半部分为这一轮加密密钥的生成方法。每一轮的加密都采用不同的子密钥。
DES密钥生成
DES算法输入的密钥为64位,由于不考虑每个字节的第8位,那么DES算法的密钥就从64位减至56位,这个过程通过一置换操作来完成,置换方法见下表。
通过上表的置换操作去掉了每个字节的第8位,同时还对输人的密钥进行了混淆操作。在获得了56位的密钥之后,将56位的密钥分成两部分。根据轮数不同对左右两部分分别循环左移1位或2位。每轮移位的多少见下表。
在完成循环左移之后对获得的密钥再进行压缩置换,压缩置换进行了两部分的操作,一部分是进行压缩,将56位的密钥压缩为48位的密钥,另一部分是进行置换操作,其结果是实现了对密钥的混淆。
压缩置换的具体细节见下表。
经过压缩置换后获得的密钥用于每一轮的加密。
解密密钥与加密密钥相同,使用的时候正好与加密密钥的顺序相反。
在经过扩展置换之后,获得的数据的位数与密钥的位数相同,均为48位。此时将扩展置换得到的数据与密钥进行“异或”运算,并将“异或"运算的结果进行S盒代换。DES算法的S盒共有8个,48位的输入被分为8个6位的分组,每个分组对应一个s
盒进行代换搡作:分组1由第1个S盒进行操作,分组2由第2个S盒进行操作,以此类推。每个S盒是6位输入,4位输出,因此48位的输人数据经过s盒代换后输出32位数据。S盒的代换基本原理见下图。
S盒代换输出见下表。
DES算法确定S盒项的方法与S-DES算法类似。假设S盒的输入是的6位输人,那么和组合构成一个2位数,从0到3,确定S盒的行。从到构成一个4位数,从0到15,确定S的列。
例如,S盒的输人是110101。第1位和第6位组合就得到11,它对应着S盒的第3行(注:S盒是从第0行、第0列开始计算的)。中间的4位为1010,对应第10列。以S1盒为例计算输出,,那么对应的输出则为0110。
S盒代换是DES算法最关键的一步,DES算法的其他步骤的计算都是线性的,只有S盒是非线性运算,它对DES的安全性起到了关键作用。S盒代换后获得32位的输出,将S盒的输出进行P盒运算,P盒运算实际上就是一种置换运算,P盒的置换方法见下表。
将P盒置换后得到的结果与最初的64位分组的左半部分进行“异或”,然后按照前面的图所示的方法将左、右两部分进行交换,在进入下一轮的运算。在第16轮运算结束时,左、右两半不再进行交换。将左、右两半合并在一起形成输出,然后进行末置换。末置换其实就是初始置换的逆过程。末置换的方法见下表。
末置换的输出就是整个加密过程的输出。解密过程除密钥的使用顺序不同以外,其他过程和加密过程完全相同。
解密密钥与加密密钥相同,使用的时候正好与加密密钥的顺序相反。
DES算法加密过程
DES加密算法的输入明文为64位的明文,其加密过程的第1步是对输入的明文进行IP置换,置换的方法见下表。
经过IP置换得到混淆的明文,将IP置换后得到的数据分割成左右两部分,将右半部分的32位扩展到48位,这个操作产生了与密钥长度相同的数据,可以和密钥进行异戚操作。扩展置换的具体方法见下表。
在上表中,中间部分为输入的数据,左右两部分为扩展得到的数据,扩展置换的原理见下图。
在经过扩展置换之后,获得的数据的位数与密钥的位数相同,均为48位。此时将扩展置换得到的数据与密钥进行“异或”运算,并将“异或"运算的结果进行S盒代换。DES算法的S盒共有8个,48位的输入被分为8个6位的分组,每个分组对应一个s
盒进行代换搡作:分组1由第1个S盒进行操作,分组2由第2个S盒进行操作,以此类推。每个S盒是6位输入,4位输出,因此48位的输人数据经过s盒代换后输出32位数据。S盒的代换基本原理见下图。
例如,S盒的输人是110101。第1位和第6位组合就得到11,它对应着S盒的第3行(注:S盒是从第0行、第0列开始计算的)。中间的4位为1010,对应第10列。以S1盒为例计算输出,,那么对应的输出则为0110。
S盒代换是DES算法最关键的一步,DES算法的其他步骤的计算都是线性的,只有S盒是非线性运算,它对DES的安全性起到了关键作用。S盒代换后获得32位的输出,将S盒的输出进行P盒运算,P盒运算实际上就是一种置换运算,P盒的置换方法见下表。
DES算法实现
DES.h的源代码如下:
#ifndef DES_H #define DES_H #include "string" using namespace std; class DES{ public: DES(); void setKey(string k); void setPlainText(string p); unsigned long long permutations(unsigned long long num, const int p[],int pmax,int n); void genEncKey(); unsigned long long SBoxes(unsigned long long num); void encryption(); void decryption(); void showBinary(unsigned long long num); void showResult(); private: unsigned long long keyLShift(unsigned long long k,int n); unsigned long long key; unsigned long long plainText; unsigned long long cipherText; unsigned long long decipherText; unsigned long long encKey[16]; static const int IP[64]; static const int IPI[64]; static const int keyIP[56]; static const int encKeyRound[16]; static const int CP[48]; static const int EP[48]; static const int SBox[32][16]; static const int P[32]; }; #endifDES.cpp的源代码如下:
#include "DES.h" #include <iostream> #include <vector> DES::DES(){ key=0; //初始化密钥为0 plainText=0; //初始化明文为0 cipherText=0; //初始化密文为 decipherText=0; //初始化解密明文为0 } const int DES::IP[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 }; const int DES::IPI[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 }; const int DES::keyIP[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 }; const int DES::encKeyRound[16]={1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; const int DES::CP[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 }; const int DES::EP[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 }; const int DES::SBox[32][16]={ 14, 4 , 13, 1 , 2 , 15, 11, 8 , 3 , 10, 6 , 12, 5 , 9 , 0 , 7 , //S1 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, 15, 1 , 8 , 14, 6 , 11, 3 , 4 , 9 , 7 , 2 , 13, 12, 0 , 5 , 10, //S2 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 , 10, 0 , 9 , 14, 6 , 3 , 15, 5 , 1 , 13, 12, 7 , 11, 4 , 2 , 8 , //S3 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, 7 , 13, 14, 3 , 0 , 6 , 9 , 10, 1 , 2 , 8 , 5 , 11, 12, 4 , 15, //S4 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, 2 , 12, 4 , 1 , 7 , 10, 11, 6 , 8 , 5 , 3 , 15, 13, 0 , 14, 9 , //S5 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 , 12, 1 , 10, 15, 9 , 2 , 6 , 8 , 0 , 13, 3 , 4 , 14, 7 , 5 , 11, //S6 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, 4 , 11, 2 , 14, 15, 0 , 8 , 13, 3 , 12, 9 , 7 , 5 , 10, 6 , 1 , //s7 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, 13, 2 , 8 , 4 , 6 , 15, 11, 1 , 10, 9 , 3 , 14, 5 , 0 , 12, 7 , //S8 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 }; const int DES::P[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 }; void DES::setKey(string k){ int i; unsigned long long c; for(i=0;i<8;i++){ c=k[i]; key=(c<<(7-i)*8)|key; } } void DES::setPlainText(string p){ int i; unsigned long long c; for(i=0;i<8;i++){ c=p[i]; plainText= (c<<(7-i)*8)|plainText; } } void DES::genEncKey(){ unsigned long long gKey; //临时计算的密钥 gKey=permutations(key,keyIP,64,56); //密钥初始置换 int i; for(i=0;i<16;i++ ){ gKey=keyLShift(gKey, encKeyRound[i]); encKey[i]=permutations(gKey,CP,56,48); //压缩置换 } } unsigned long long DES::keyLShift (unsigned long long k,int n){ unsigned long long tempKey=0; unsigned long long L, R; //密钥的左右两半 L=(k&0xFFFFFFF0000000LL)>>28; R=k&0x0000000FFFFFFF; if(n==0){ tempKey=k; } if(n==1){ tempKey=k; } if(n==1){ L=((L&0x7FFFFFF)<<1)|((L>>27)&1); R=((R&0x7FFFFFE)<<1)|((R>>27)&1); tempKey=(L<<28)|R; } if(n==2){ L=((L&0x3FFFFFF)<<2)|((L>>26)&3) ; R=((R&0x3FFFFFF)<<2)|((R>>26)&3) ; tempKey=(L<<28)|R; } return tempKey; } unsigned long long DES::permutations (unsigned long long num, const int p[], int pmax, int n){ unsigned long long temp= 0; int i; for(i=0;i<n;i++){ temp<<=1; //temp左移一位 temp|=(num>>(pmax-p[1]))&1; } return temp; } void DES::encryption(){ unsigned long long temp=permutations(plainText,IP,64,64); int i,j; unsigned long long L, R, tempR; L=(temp&0xFFFFF0000000LL)>>32; R=(temp&0x0000000FFFFFFLL); tempR=R; for(i=0;i<16;i++){ tempR=permutations(R, EP, 32, 48); tempR=tempR^encKey[1]; tempR=SBoxes (tempR); tempR=permutations(tempR,P,32,32); tempR=tempR^L; L=R; R=tempR; temp=(R<<32)|L; temp=permutations(temp, IPI, 64, 64) ; cipherText=temp; } } void DES::decryption(){ unsigned long long temp=permutations(cipherText,IP,64,64); int i,j; unsigned long long L, R, tempR; L=(temp & 0xFFFFFFFF00000000LL)>>32; R=(temp & 0x00000000FFFFFFFFLL); tempR=R; for(i=0;i<16;i++){ tempR=permutations(R,EP,32,48); tempR=tempR^encKey[15-i]; tempR=SBoxes(tempR); tempR=permutations(tempR, P,32,32); tempR=tempR^L; L=R; R=tempR; temp=(R<<32)|L; temp=permutations(temp, IPI,64, 64); decipherText=temp; } } void DES::showBinary(unsigned long long num){ vector<int> v; do{ v.push_back(num%2); num=(num-num%2)/2; }while(num!=0); for(int i=(v.size()-1);i>=0;i--){ cout<<v[i]; } cout<<endl; } void DES::showResult(){ int i; cout<<"key="; for(i=0; i<8; i++){ cout<<(char)((key>>(7-i)*8)&0xFF); } cout<<endl; cout<<"plainText="; for(i=0;i<8;i++){ cout<<(char)((plainText>>(7-i)*8)&0xFF); } cout<<endl; cout<<"decipherText="; for(i=0;i<8;i++){ cout<<(char)((decipherText>>(7-i)*8)&0xFF); } cout<<endl; } unsigned long long DES::SBoxes(unsigned long long num){ int i; unsigned long long temp; unsigned long long result = 0; for(i=0;i<8;i++){ temp=(num>((7-i)*6))&0x3F; int x=((temp>>4)&0x2)|(temp&0x1) + i*4; int y=(temp>>1)&0xF; temp=SBox[x][y]; temp=temp<<((7-i)*4); result=result|temp; } return result; }main.cpp的源代码如下:
#include <iostream> #include "DES.h" /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char** argv) { DES des; des.setKey("!2bcde<~"); des.setPlainText("ABs5EFGH"); des.genEncKey(); des.encryption(); des.decryption(); des.showResult(); return 0; }