数据加密标准DES是分组密码的典型代表,是上世纪八九十年代很常用的加密算法。

DES的整体结构采用16圈Feistel模型。大致过程如下:

1.将待加密的明文分组,每组64比特

2.对于每一组,进行初始置换

3.置换后将明文分为左半部分和右半部分各32比特,接着进行16圈迭代

3.1 每一圈中,右半部分在48比特圈(子)密钥k的作用下进行f变换,得到的32比特数据

      与左半部分按位异或,产生的32比特数据作为下一圈迭代的右半部分

3.2 原右半部分直接作为下一圈迭代的左半部分

3.3

4.最后左右部分合并再进行一次置换,即可得到密文

 

接下来介绍一下圈(子)密钥k的生成算法

/*输入64位初始密钥(这里是16位16进制数),迭代16轮,每一轮输出48位圈密钥
1.对64位的初始密钥进行置换选择1
2.将置换选择1输出的56比特数据分成左右两部分,每部分28位
3.1 每一轮将两部分分别进行循环左移,左移的位数与其所在圈数有关,进行16轮
3.2 左移后进行置换选择2得到48比特的圈密钥
4. 重复第3步16次,总共得到16圈子密钥
*/

c++实现如下:

#include<bits/stdc++.h>
bool key[66] , C[29] ,D[29];
int k(0);
int table1[56] = {57,49,41,33,25,17,9,1   //置换选择表1,用于从64位初始密钥中选择56位
                ,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};
int table2[48] = {14,17,11,24,1,5,  //置换选择表2,将得到的56位进行置换选择2,得到真正的圈密钥
                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};
int dis[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};//C寄存器和D寄存器循环左移的位数
void to_binary(int n)  //将10进制数转换为4位2进制数
{
    int K = k+3;
    while(n)
    {
        key[K--] = n % 2;
        n /= 2;
    }
    while(k <= K)
        key[K--] = 0;
    k = k + 4;
}
void transform16_64(char *s)//将16位16进制数转换为64位二进制
{
    for(int i = 0 ; s[i] ; i++)
    {
        if(s[i] < 65)
            to_binary(s[i] - '0');
        else to_binary(s[i] - 55);
    }
}
void exchange1() //置换选择1,产生C,D各28位
{
    for(int i(0) ; i < 28 ; i ++)
        C[i] = key[table1[i] - 1] ;
    for(int i(28) , j(0) ; i < 56 ; i++ , j++)
        D[j] = key[table1[i] - 1] ;
}
void exchange2(int n)//置换选择2,并输出第n圈的圈密钥
{
    printf("K%d:\t" , n);
    for(int i = 0 ; i < 48 ; i++)
    {
        int t = table2[i] - 1 ;
        printf("%d" , t > 27 ? D[t-28] : C[t]);
    }
    puts("\n");
}
void displace(int n , bool *c)//移位操作,n表示第n次移位
{
    int p = dis[n];
    bool t[p];
    for(int i = 0 ; i < p ; i++)
        t[i] = c[i];
    for(int i = p ; i < 28 ; i++)
        c[i-p] = c[i];
    for(int i = 28-p ; i < 28 ; i++)
        c[i] = t[i-(28-p)];
}
int main()
{
    char K[20];
    while(scanf("%s" , K) != EOF)//输入16位16进制数(初始密钥)
    {
        transform16_64(K);//16进制转64进制

        exchange1(); //置换选择1

        for(int i(0) ; i < 16 ; i++) //进行16圈迭代
        {
            displace(i , C);  //第i圈迭代,进行移位操作
            displace(i , D);

            exchange2(i+1) ;//置换选择2
        }
    }
    return 0;
}
//K = FEDCBA9876543210  初始密钥  k