DES algorithm

DES 算法的核心思想是混淆和扩散,我们来看它是怎么做来达到这个目地的。

流程:

密钥置换选择1(pc1) ->密钥循环左移表(rot) ->压缩选排阵(pc2)
初选排阵(ip) ->(扩展选排阵(e) ->S-Box阵(s) ->P选排阵(p)->)*16->末选排阵(fp)

置换使得顺序杂乱无章,密钥循环移位,压缩选排和round()(轮函数)中的扩展选排和S-BOX的替换使得每一位都尽可能的扩散到其它位,达到扩散的目地。

刚开始写时思路不是很清晰,而且对STL中的bitset<_N>的理解只是一知半解,害得我走了好多的弯路,尤其注意这一点,对于位串 bitset<6> b("000001");
b[0]不是0而是1,后来干脆自己写了一个bitset<_N>。

 

代码:

bitset.h

//I'm not accustomed to the bitset container in STL,so I decided to write it in my own habit; //根据DES算法的特点而写,不一定适应其它算法 template<size_t _N> class bitset{ private: bool f[_N]; public: bitset(){ memset(f,0,sizeof(f)); } bitset(string s){ int i,j; for(i=0,j=0;i<s.size();i++)f[j++]=s[i]-'0'; while(j<_N)f[j++]=0; } bitset(int i){ int pos=_N-1; while(i){ f[pos--]=i&1; i>>=1; } while(pos>-1)f[pos--]=0; } // bool & operator[](int pos){ return f[pos]; } void operator=(bitset<_N> b1){ int i; for(i=0;i<_N;i++)f[i]=b1[i]; } // friend ostream & operator<<(ostream &out,bitset<_N> &b1){ int i; for(i=0;i<_N;i++){ out<<b1[i]; } return out; } void operator<<=(short &step){//循环左移一到二位 int i; bool t[2]; t[0]=f[0];if(step==2)t[1]=f[1]; if(step==1){ for(i=0;i<_N-1;i++)f[i]=f[i+1]; f[_N-1]=t[0]; } else{ for(i=0;i<_N-2;i++)f[i]=f[i+2]; f[_N-2]=t[0];f[_N-1]=t[1]; } } bitset<_N> operator^(bitset<_N> b1){ bitset<_N> b0; int i; for(i=0;i<_N;i++)b0[i]=f[i]^b1[i]; return b0; } void operator^=(bitset<_N> b1){ int i; for(i=0;i<_N;i++)f[i]^=b1[i]; } string to_string(){ string s; int i; for(i=0;i<_N;i++)s+=(char)( f[i]+'0'); return s; } unsigned __int64 to_ulong(){ int pos=0; unsigned __int64 i=pow((double)2,_N-1); unsigned __int64 sum=0; while(pos<_N)sum+=f[pos++]*i,i>>=1; return sum; } };

 

 

GetBlockCode.h

#include"round.h" string getBlockCode( bitset<M> part,bitset<PKEY> * key,bool flag ){ //initial permute bitset<M> p1; int i,j; for(i=0;i<M;i++)p1[i]=part[ ip[i] ]; //Li=Ri-1,Ri=Li-1^Round(Ri-1,ki) bitset<HM> left,right,tmp; for(j=0;j<HM;j++){ left[j]=p1[j]; right[j]=p1[j+HM]; } for(i=1;i<=16;i++){ tmp=right; right=left^round(right,key,flag?17-i:i); left=tmp; } //swap left and right swap(left,right); for(i=0;i<HM;i++){ p1[i]=left[i]; p1[i+HM]=right[i]; } //final permute bitset<M> final; for(i=0;i<M;i++)final[i]=p1[ fp[i] ]; // cout<<"final: "<<final<<endl; //to_string string block; bitset<BYTE> ascII; for(i=0;i<8;i++){ for(j=0;j<8;j++){ ascII[j]=final[i*BYTE+j]; } block+=(char)ascII.to_ulong(); } return block; }

 

GetKeys.h

 

void getKeys(string k0,bitset<PKEY> * key) { bitset<M> orig=stringToBit(k0); bitset<KEY> p1; //一次点名pc-1 int i; for(i=0;i<KEY;i++){ p1[i]=orig[ pc1[i] ]; } //get k1~k16 bitset<HKEY> left,right; for(i=0;i<HKEY;i++)left[i]=p1[i],right[i]=p1[HKEY+i] ; int j; bitset<KEY> tmp; for(i=1;i<=16;i++){ left<<=rot[i-1]; right<<=rot[i-1]; tmp=bitset<KEY>( left.to_string()+right.to_string() ); for(j=0;j<PKEY;j++)key[i][j]=tmp[ pc2[j] ]; // cout<<"//k"<<i<<':'<<' '<<key[i]<<endl; } }

 

main.cpp

/* id:ysjjovo lang:C++ task:des decryption description:this des algorithm version is originally invented by Lin,I wish everyone will enjoy it ,correct it and tell me! */ #include"variable.h" #include"bitset.h" #include"stringToBit.h" #include"getKeys.h" #include"getBlockCode.h" string des(string mes,string k0,bool flag){ bitset<PKEY> key[17];//k1-k16 k0 isn't exist getKeys(k0,key); int i; string code; int cnt=mes.size() / BYTE+( mes.size()%BYTE?1:0 ); for(i=0;i<cnt;i++){ code+=getBlockCode( stringToBit( mes.substr(i*BYTE,BYTE) ) , key,flag); } return code; } //bitset<_N> 初使值为0 //string 初使值为""(空) //char(0)为空字符 str+char(0) == str char m[4000]; int main(){ ifstream cin1("message.in"),cin2("key.in"); string message,key; cin1.getline(m,sizeof(m),EOF);cin1.close(); message=string(m); cin2.getline(m,sizeof(m),EOF);cin2.close(); key=string(m); //F^-1( F(M,K) , K )=M ----加密后解密为原文,false为加密,true为解密 //f^-1(f(x))=x cout<<des( des(message,key,false),key,true )<<endl; return 0; } /* sample*/ //message:abcdefgh key:12345678 //messgae bit: 0110000101100010011000110110010001100101011001100110011101101000 //cryption bit: 0010100001000001001110001011100110101001000011100101111011110011 //k1: 111100001011111001100110101110000111000000110010 //k2: 111000001011111001110110100110110100100110100101 //k3: 111001001111011001110110000000100100101110010001 //k4: 111001101101011101110010110100110010000100010101 //k5: 111011101101001101110011111000110000001110001000 //k6: 101011111101001101011011010100000011001100001111 //k7: 001011110101001111011011011101100001000010101100 //k8: 001111110101100111011001010000000011100111101011 //k9: 000111110101100111011001011011001110010110000001 //k10: 000111110110100111011101101010100100010001001011 //k11: 000111110110110110001101110011101101001100000010 //k12: 010110110010110110101101100101000100011101101000 //k13: 110110011010110010101101110110001001101001000000 //k14: 110100011010111010101110110100001110011000111000 //k15: 111100001011111010100110001110010011111000001000 //k16: 111100001011111000100110000010100001011010110101

 

round.h

//扩展选排阵(e) ->S-Box阵(s) ->P选排阵(p) bitset<HM> round(bitset<HM> half,bitset<PKEY> *key,int n){ bitset<PKEY> exM; //extend and permute int i; for(i=0;i<48;i++){ exM[i]=half[ e[i] ]; } exM^=key[n]; //s-box replacement bitset<2> row; bitset<4> colum,ans; int j; for(i=0;i<8;i++){ row[0]= exM[i*6]; row[1]=exM[i*6+5]; for(j=0;j<4;j++){ colum[j]=exM[i*6+j+1]; } // ans=bitset<4>( s[i*64+ row.to_ulong()*16 + colum.to_ulong() ] ); ans=bitset<4>( s[i][ row.to_ulong() ][ colum.to_ulong() ] ); for(j=0;j<4;j++)half[i*4+j]=ans[j]; } // bitset<HM> tran; for(i=0;i<HM;i++){ tran[i]=half[ p[i] ]; } return tran; }

 

StringToBit.h

 

//8*8位一组 少于8字符用NULL填充!不影响结果. bitset<M> stringToBit(string mes){ int size=( mes.size()>=8?8:mes.size() ); bitset<BYTE> b1; string tmp; for(int i=0;i<size;i++){ b1=bitset<BYTE>( mes[i] ); tmp+=b1.to_string(); } // cout<<tmp<<endl; // cout<<bitset<M>(tmp)<<endl; return bitset<M>(tmp); }

 

variable.h

#pragma warning(disable: 4800) #include<iostream> #include<cmath> #include<algorithm> #include<string> #include<fstream> using namespace std; #define M 64 #define HM 32 #define KEY 56 #define HKEY 28 #define PKEY 48 #define BYTE 8 /* 书上的下标是从1开始,而实际的是0开始因此全部减1 但S-box和置换选择表(pc1)保持一致。 因为S-box中的元素和下标无关, pc1表中的处理方法和书上的不一样,这里的方法是忽略高位,也就是(0,8,16,24,32,40,56) */ //初选排阵 /* Initial permutation IP */ char ip[]= { 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, 56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6 }; //末选排阵 /* Final permutation IP^-1 */ char fp[]= { 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, 32, 0, 40, 8, 48, 16, 56, 24 }; //扩展选排阵 char e[]= { 31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 16, 15, 16, 17, 18, 19, 20, 19, 20, 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0 }; //P选排阵 char p[]= { 15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9, 1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24 }; // cut high bit(0,8,16,24,32,40,48,56) // rest permute //密钥置换选择1(pc1) char pc1[] = { 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 }; //密钥循环左移表(rot) short rot[] = /* Number left rotations of pc1 */ { 1, 1, 2, 2, 2, 2, 2, 6, 1, 2, 2, 2, 2, 2, 2, 1 }; //压缩选排阵(pc2) char pc2[]= { 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; //S-Box阵 char s[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 };

 

message.in(输入明文)

可自义,只要是文本文件就行!

Time Limit: 1000.0ms, Special Time Limit:2500.0ms, Memory Limit:64000.0KB Total submit users: 0, Accepted users: 0 Problem 1013:No special judgement 真三国无双 Description 真三国无双是魔兽的一个游戏,该游戏是以中国三国的历史背景而制作的,该游戏是5 V 5的游戏模式,敌对双方各5个英雄,推掉了对方的大本营就算取得了胜利。 ZYH和SN都喜欢玩这个游戏,但是他们谁也不服谁,都觉得自己的操作比对方厉害,因此他们两人决定以单挑的方式来一决高下。ZYH选择了他最喜欢的英雄:关羽,SN也选择了他喜欢的英雄:典韦。 在他们开始正式比赛前,裁判介绍了一下关羽和典韦的技能。典韦有个脚踢地面而造成群晕的技能,简称为T,由于是游戏,它会有个动画效果,因此典韦使用T分为三个阶段: 点击T à T的动画 à T的释放 点击T的时间可以忽略,T的动画需要a(MS);T的释放时间为b(MS),在这段时间内,如果对方英雄在地面,就会被击晕。 而关羽使用技能D,过程是这样的: 点击D à 选择方向à 转身(英雄会逆时针转身到选择的方向)à 跳到空中à 落下 点击D和选择方向的时间可以忽略,转身时间为c(MS),跳到空中停留的时间为d(MS)。英雄当前方向与选择方向之间的逆时针夹角叫做旋转角度。转身时间c = 旋转角度 × 10 (MS)。在游戏中,旋转角度的范围为[0, 360),不可能小于0或者大于等于360。 因此关羽和典韦单挑的时候,关羽喜欢用自己的技能D躲典韦的技能T,这就必须满足在典韦技能T释放的b(MS)时间内,关羽必须在空中。为了简化问题,我们认为,关羽在起跳或者落地的瞬间,典韦的技能T对他是无效的。 裁判正式介绍技能后,ZYH(关羽)就和SN(典韦)开始单挑了,他们在打架多次后,ZYH(关羽)和SN(典韦)的血量都处于死亡的边缘,此时SN(典韦)果断使用了自己的技能T,希望可以把ZYH(关羽)杀了,而ZYH(关羽)也在同时使用了技能D。 现在ZYH(关羽)求救于你,希望你能帮他计算关羽能选择的最小旋转角度,他的命就掌握在你的手上,你可不能随便应付吧。另外注意一点的就是,他们的技能现在只能释放一次。 Input 输入的第一行表示测试数据的组数N。下面输入包括N行,每行包括三个整数,分别表示a, b, d (1 ≤ a ≤ 10000, 1 ≤ b ≤ 10000, 1 ≤ d ≤ 10000)。 Output 如果ZYH(关羽)可以成功躲掉SN(典韦)的技能T,则输出能成功躲避的最小旋转角度(小数点后保留两位有效数字)。否则输出IMPOSSIBLE;每个输出后都换一行。 Sample Input 3 1 1 1 1 2 1 2 1 2 Sample Output 0.10 IMPOSSIBLE 0.10 JudgeStatus Problems Ranklist

 

key.in(输入密钥)

可自定义,但我写的DES算法里只取最前面的8个字符做为密钥,不足补NULL,不影响结果!

I love it!

 

绝对原创,希望大家转载时注明出处!

你可能感兴趣的:(DES algorithm)