DES原理与实现

一 DES综述

DES是对称密码的一种,它使用56位秘钥对64位长分组进行加密。DES对每个分组的内容都会进行16轮迭代,每轮的操作相同但是对应不同的子秘钥。所有的子秘钥都是由主密钥推导而来。

64位明文加密过程如下:

1. 按位置换(IP)

2. 明文被分成L0和R0两部分。

3. L1=R0  R1=L0⊕f(R0,k1)

4. 重复步骤3 16次

5. 按位置换(IP^-1)

 

二 细节分析

其中的重点在于:1. 如何实现函数f  2. 如何生成子秘钥k

1. 函数f 输入与输出的数据为32位。

  E:    将输入的数据分成8个4位的分组。这个过程在E盒中进行。E盒是一种特殊的置换。32位输入中有16位输入位在输出中出现了两次。分别为第1 4 5 8 9 12 ... 32位。E盒的输入数据为32位,输出为48位,仅有置换操作。

  S:   将拓展得到的48位结果与密钥ki进行XOR操作,将8个6位长的分组送入8个不同的替换盒S中,将6位输出裁剪成4位。S盒的输入数据为48位,输出为32位,有和密钥的XOR操作,也有置换。

  P:   按位置换,以实现扩散。P盒的输入和输出均为32位,仅有置换操作。

2. 密钥生成函数GetKey的输入为64位密钥,输出为16个48位子密钥。

  密钥的实际有效位数为56位,其余8位为奇校验位。PC-1处理得到的56位密钥分为C和D两部分。首先将C和D按照轮数移动一位或者两位。然后将C和D合起来,用PC-2将56位密钥置换成48位密钥。

  PC-1:置换的意义是去掉校验位。

  PC-2:意义是将56位置换成48位。

 

三 几个小问题

1. 从总体上来说,DES是什么?

  前面杂七杂八的扯了那么多细节问题,不免让人头昏脑涨。用最简单的话讲,DES是什么?一种加密方法。将8位密钥处理得到16组子密钥。它还将待加密数据分成许多个分组,每个分组有8个字符组成。然后每组待加密数据,做16轮加密处理,每轮加密处理都用不同的密钥,即最初得到的16组子密钥。

  举例说明:

密钥:12345678

待加密数据:i am a good student

子密钥:

Array ( 
[1] => 010100000010110010101100010101110010101011000010
[2] => 010100001010110010100100010100001010001101000111
[3] => 110100001010110000100110111101101000010010001100
[4] => 111000001010011000100110010010000011011111001011
[5] => 111000001001011000100110001111101111000000101001
[6] => 111000001001001001110010011000100101110101100010
[7] => 101001001101001001110010100011001010100100111010
[8] => 101001100101001101010010111001010101111001010000
[9] => 001001100101001101010011110010111001101001000000
[10] => 001011110101000101010001110100001100011100111100
[11] => 000011110100000111011001000110010001111010001100
[12] => 000111110100000110011001110110000111000010110001
[13] => 000111110000100110001001001000110110101000101101
[14] => 000110110010100010001101101100100011100110010010
[15] => 000110010010110010001100101001010000001100110111
[16] => 010100010010110010001100101001110100001111000000 )

   

待加密数据:
i am a g => 281EBCF251148911 (16进制) ood stud =>ECFB5BFD44D714EF (16进制) ent00004 =>BFBE729B56B9B540(16进制)#最后一组待加密数据位数不足8位,用0补齐,最后一位表示补0的个数

2. 怎么实现置换?

  置换在代码中的实现尤为简单,具体见最下方的代码 function move()。

3. 函数过程中数据应该是以二进制流动的,二进制如何与字母数字转化?

  被加密字符采用了ASCII码到二进制的转换。密钥每一位都被当做10进制数字处理。

  被加密的字符首先被转化成两位16进制表示的ASCII码,然后每个字符转换成8位2进制,即为二进制原始待加密数据。

4. 密钥的格式是什么:字母或者是数字?多少位?

  在整个加密过程中,共生成16组子密钥,分别用于16轮加密。每个生成的子密钥的实际均为48位的二进制数组。具体格式如上所示。具体转换的方法是:用户提供的密钥中的每一位数字,都由1位十进制转化成8位二进制,不足8位的在最前方补0。即得出64位二进制原始密钥。

 

四 贴代码(php)

$S = array(
    1 => array(
        array(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7),
        array(0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8),
        array(4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0),
        array(15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13),
    ),
    2 => array(
        array(15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10),
        array(3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5),
        array(0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15),
        array(13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9),
    ),
    3 =>array(
        array(10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8),
        array(13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1),
        array(13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7),
        array(1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12),
    ),
    4 => array(
        array(7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15),
        array(13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9),
        array(10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4),
        array(3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14),
    ),
    5 => array(
        array(2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9),
        array(14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6),
        array(4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14),
        array(11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3),
    ),
    6 => array(
        array(12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11),
        array(10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8),
        array(9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6),
        array(4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13),
    ),
    7 => array(
        array(4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1),
        array(13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6),
        array(1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2),
        array(6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12),
    ),
    8 => array(
        array(13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7),
        array(1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2),
        array(7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8),
        array(2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11),
    ),
);

$E = array(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);

$P = array(
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,
);


$PC1 = array(
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);

$PC2 = array(
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,
);

$IP = array(
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,
);

$IP1 = array(
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,
);

$r = array(1=>1,2=>1,3=>2,4=>2,5=>2,6=>2,7=>2,8=>2,9=>1,10=>2,11=>2,12=>2,13=>2,14=>2,15=>2,16=>1,);

 

 

  1 $k = array();
  2 
  3 function index($data,$key,$type=1){
  4     global $k;
  5     $k=GetKey($key);
  6     if($type==1){
  7         $str=BitByte($data);
  8         return DES($str);
  9     }
 10     else{
 11         $str=DecodeTrans($data);
 12         return ToASCII(DES($str,2));
 13     }
 14 }
 15 
 16 function shiftleft($data,$num) {    //循环左移一位
 17     return substr($data, $num, (strlen($data) - $num)) . substr($data, 0, $num);
 18 }
 19 
 20 function move($array, $data) {        //置换
 21     $rs = '';
 22     foreach($array as $index) {
 23         $rs .= $data[$index-1];
 24     }
 25 
 26     return $rs;
 27 }
 28 
 29 function dataXOR($data1, $data2) {
 30     if(strlen($data1) != strlen($data2)) {
 31         exit('xor err');
 32     }
 33 
 34     $rs = '';
 35     for($i=0; $i<strlen($data1); $i++){
 36         $rs .= ($data1[$i] == $data2[$i])?0:1;
 37     }
 38 
 39     return $rs;
 40 }
 41 
 42 function S($EL) {
 43     global $S;
 44 
 45     $B = array();
 46     for($i=1;$i<=8;$i++){
 47         $B[$i] = substr($EL, 6*($i-1),6);
 48     }
 49 
 50     $BI = array();
 51     foreach($B as $id => $row) {
 52         $a = base_convert($row[0] . $row[5], 2, 10);
 53         $b = base_convert(substr($row, 1, 4), 2, 10);
 54         $BICurrent = base_convert($S[$id][$a][$b], 10, 2);
 55 
 56         while(strlen($BICurrent) < 4) {
 57             $BICurrent = 0 . $BICurrent;
 58         }
 59 
 60         $BI[$id] = $BICurrent;
 61     }
 62 
 63     return implode('', $BI);
 64 }
 65 
 66 function BitByte($data){
 67     $str='';
 68     for($i=0;$i<strlen($data); $i++){
 69         $temp=base_convert(ord($data[$i]), 10, 2);
 70         while(strlen($temp) < 8) {
 71             $temp = 0 . $temp;
 72         }    
 73 
 74         $str .= $temp;    
 75     }
 76 
 77     return $str;
 78 }
 79 
 80 function DecodeTrans($data){    //16进制转换为二进制
 81     $result = '';
 82     for($start = 0; $start < strlen($data); $start += 2) {
 83         $bin = substr($data, $start, 2);
 84         $temp= strtoupper(base_convert($bin, 16, 2));
 85         while(strlen($temp) < 8) {
 86             $temp = 0 . $temp;
 87         }
 88 
 89         $result .=$temp;
 90     }
 91 
 92     return $result;
 93 }
 94 
 95 function GetKey($key){
 96     global $PC1,$PC2;
 97 
 98     if(strlen($key)!=8){
 99         exit('密钥长度错误!');
100     } 
101 
102     $binKey=BitByte($key);    //key转成二进制
103     $keyPC1 = move($PC1,$binKey);    //对key(binkey)进行pc-1处理
104     $C[0] = substr($keyPC1, 0, 28);
105     $D[0] = substr($keyPC1, 28, 28);
106     $C=GetMove($C);
107     $D=GetMove($D);    
108 
109     for($i=1; $i<=16; $i++) {
110         $concat = $C[$i] . $D[$i];
111         $k[$i]=move($PC2,$concat);
112     }
113 
114     return $k;
115 }
116 
117 function GetMove($data)    //获取左移之后的密钥
118 {
119     global $r;
120 
121     for($i=1; $i<=16; $i++) {
122         $shift = $data[$i-1];
123         $data[$i] = shiftleft($shift,$r[$i]);
124     }
125 
126     return $data;
127 }
128 
129 
130 function DES($data,$type=1){
131     global $IP,$IP1,$E,$k,$P;
132     $temp=move($IP,$data);
133 
134     $L = $R = array();
135     $L[0] = substr($temp, 0, 32);
136     $R[0] = substr($temp, 32, 32);
137 
138     
139     for($i=1; $i<=16; $i++) {
140         $L[$i] = $R[$i-1];
141         $EL = move($E, $L[$i]);
142 
143         $EL = ($type==1)?dataXOR($EL, $k[$i]): dataXOR($EL, $k[17-$i]);
144         $s = S($EL);
145         $f = move($P, $s);
146         $R[$i] = dataXOR($L[$i-1], $f);
147     }    
148         
149     $concat = $R[16] . $L[16];
150 
151     $encoded = move($IP1, $concat);
152     $result = '';
153     for($start = 0; $start < strlen($encoded); $start += 4) {
154         $bin = substr($encoded, $start, 4);
155         $result .= strtoupper(base_convert($bin, 2, 16));
156     }
157 
158     return $result;
159 }
160 
161 function ToASCII($data){
162     $str='';
163     for($start = 0; $start < strlen($data); $start += 2) {
164         $bin = substr($data, $start, 2);
165         $str .= chr(base_convert($bin, 16, 10));
166     }
167 
168     return $str;
169 }