DES 编码的原理及实现

DES(Data Encryption Standard), 出自于IBM的研究项目, 1977 年被美国政府正式采用.

DES的特点为 Working On Bits

假设有一组KEY为 "133457799BBCDFF1" 8 bytes, 资料为 "0123456789ABCDEF" 8 bytes, 则加密后的资料为 8 bytes 的 "85E813540F0AB405" 

那么加密的算法为何?


Step1: 由 KEY 算出 16 组的 subkeys, 每一个 subkey 为 48 bits
1) 首先将 KEY "133457799BBCDFF1" 转换成 64 bits binary string:
   K+: 0001001100110100010101110111100110011011101111001101111111110001 
   它是由一组对应表转换而成。
   my %codemap = ('0' => '0000', '1' => '0001', '2' => '0010', '3' => '0011',
                  '4' => '0100', '5' => '0101', '6' => '0110', '7' => '0111',
                  '8' => '1000', '9' => '1001', 'A' => '1010', 'B' => '1011',
                  'C' => '1100', 'D' => '1101', 'E' => '1110', 'F' => '1111');


2) 再由一组置换阵列

   (其数值就表示 K+ 中的第几个 bit, starting from 1, instead of from 0)

   my @pc1map = (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);
   转换成 56 bits binary string
   K0: 11110000110011001010101011110101010101100110011110001111


3) 将 K0 分成左右两个部分,每个部分为 28 bits binary string

   C0: 1111000011001100101010101111
   D0: 0101010101100110011110001111
   Ci 与 Di (i=1..16) 分别按下表进行位移处理:
   my %iterations = ( 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);

   按上表 C1=》C0 位移 1 位: C0 的第 2 位为 C1 的第 1 位, C0 的第 3 位为 C1 的第 2 位,

                           ..., C0 的第 1 位为 C1 的最后 1 位

         D1=》D0 位移 1 位: D0 的第 2 位为 D1 的第 1 位, D0 的第 3 位为 D1 的第 2 位, 

                           ..., D0 的第 1 位为 D1 的最后 1 位

         C3=》C2 位移 2 位: C2 的第 3 位为 C3 的第 1 位, C2 的第 4 位为 C3 的第 2 位,..., 

                            C2 的第 1 位为 C3 的倒数第 2 位, C2 的第 2 位为 C3 的最后 1 位

         D3=》D2 位移 2 位: D2 的第 3 位为 D3 的第 1 位, D2 的第 4 位为 D3 的第 2 位,..., 

                            D2 的第 1 位为 D3 的倒数第 2 位, D2 的第 2 位为 D3 的最后 1 位

   依此可得
   C1 = 1110000110011001010101011111
   D1 = 1010101011001100111100011110

   C2 = 1100001100110010101010111111
   D2 = 0101010110011001111000111101

   C3 = 0000110011001010101011111111
   D3 = 0101011001100111100011110101

   C4 = 0011001100101010101111111100
   D4 = 0101100110011110001111010101

   C5 = 1100110010101010111111110000
   D5 = 0110011001111000111101010101

   C6 = 0011001010101011111111000011
   D6 = 1001100111100011110101010101

   C7 = 1100101010101111111100001100
   D7 = 0110011110001111010101010110

   C8 = 0010101010111111110000110011
   D8 = 1001111000111101010101011001

   C9 = 0101010101111111100001100110
   D9 = 0011110001111010101010110011

   C10 = 0101010111111110000110011001
   D10 = 1111000111101010101011001100

   C11 = 0101011111111000011001100101
   D11 = 1100011110101010101100110011

   C12 = 0101111111100001100110010101
   D12 = 0001111010101010110011001111

   C13 = 0111111110000110011001010101
   D13 = 0111101010101011001100111100

   C14 = 1111111000011001100101010101
   D14 = 1110101010101100110011110001

   C15 = 1111100001100110010101010111
   D15 = 1010101010110011001111000111

   C16 = 1111000011001100101010101111

   D16 = 0101010101100110011110001111


4) 将 Ci, Di 组合起来 CiDi 再经过置换阵列

   my @pc2map = (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);

   转换可得 16 组 subkeys

    K1 = 000110110000001011101111111111000111000001110010
    K2 = 011110011010111011011001110110111100100111100101
    K3 = 010101011111110010001010010000101100111110011001
    K4 = 011100101010110111010110110110110011010100011101
    K5 = 011111001110110000000111111010110101001110101000
    K6 = 011000111010010100111110010100000111101100101111
    K7 = 111011001000010010110111111101100001100010111100
    K8 = 111101111000101000111010110000010011101111111011
    K9 = 111000001101101111101011111011011110011110000001
   K10 = 101100011111001101000111101110100100011001001111
   K11 = 001000010101111111010011110111101101001110000110
   K12 = 011101010111000111110101100101000110011111101001
   K13 = 100101111100010111010001111110101011101001000001
   K14 = 010111110100001110110111111100101110011100111010
   K15 = 101111111001000110001101001111010011111100001010
   K16 = 110010110011110110001011000011100001011111110101


Step2: 对每个 64 bit data block 进行编码

1) 将 Data '0123456789ABCDEF' 转换成 64 bits binary string

   M = '0000000100100011010001010110011110001001101010111100110111101111'


2) 将 M 进行第一次的置换

   my @IP = (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);   

   可得: IP = '1100110000000000110011001111111111110000101010101111000010101010'


3) 将 IP 分为左右两个部分, 每部分 32 bits binary string

   L0 = 11001100000000001100110011111111
   R0 = 11110000101010101111000010101010


4) 将 L0, R0 按如下规则迭代运算: i=1..16
   L[i] = R[i-1]
   R[i] = L[i-1] + f(R[i-1], K[i])
   上式的加法为 XOR on bits, f 的作用为
   *1 R[i-1] 为 32 bit, 而 K[i] 为 48 bit, 需要将 R[i-1] 扩充为 48 bit, 规则如下置换阵列
   my @selection_table = (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);
   以计算 L1, R1 为例: EXP = 011110100001010101010101011110100001010101010101

   *2 扩充好的 binary string exp 与 K[i] 作用 xor on bits, 

      可得 48 bits binary string - xor

   EXP = 011110100001010101010101011110100001010101010101
   K1  = 000110110000001011101111111111000111000001110010
   ---------------------------------------------------------
   XOR = 011000010001011110111010100001100110010100100111 

   *3 计算 XOR 的 sboxes: 将 XOR 6 bit 为 1 组分成 8 组 xor[i] (i=0..7) 

      每一组对应一组 sbox, 可得 8 个 sbox index

   my @sb1 = (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);


   my @sb2 = (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);


   my @sb3 = (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);


   my @sb4 = ( 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);


   my @sb5 = ( 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);


   my @sb6 = (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);


   my @sb7 = ( 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);


   my @sb8 = (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);    
   
   以上例解释: XOR 可分为 011000 010001 011110 111010 100001 100110 010100 100111
   其 sbox index 的运算规则为 row number = 第 1 位与最后 1 位组合起来的值; col number = 中间 4 位组合起来的值
   依序可得 sbox index 
   
(00, 1100), (01, 1000), (00, 1111), (10, 1101), (11, 0000), (10, 0011), (00, 1010), (11, 0011)
   取值为 
   (0, 12),    (1, 8),     (0, 15),    (2, 13),    (3, 0),     (2, 3),     (0, 10),    (3, 3)
   依序对应 
   SB1[0, 12], SB2[1, 8],  SB3[0, 15], SB4[2, 13], SB5[3, 0],  SB6[2, 3],  SB7[0, 10], SB8[3, 3]
   =>
   5,          12,         8,          2,          11,         5,          9,          7
   =>
   0101,       1100,       1000,       0010,       1011,       0101,       1001,       0111        
   SBS = 0101 1100 1000 0010 1011 0101 1001 0111
   *4 SBS 经置换阵列
   my @sp = (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);
   PC = 00100011010010101010100110111011


   依此规则可得:
   L1 = 11110000101010101111000010101010
   R1 = 11101111010010100110010101000100
   L2 = 11101111010010100110010101000100
   R2 = 11001100000000010111011100001001
   L3 = 11001100000000010111011100001001
   R3 = 10100010010111000000101111110100
   L4 = 10100010010111000000101111110100
   R4 = 01110111001000100000000001000101
   L5 = 01110111001000100000000001000101
   R5 = 10001010010011111010011000110111
   L6 = 10001010010011111010011000110111
   R6 = 11101001011001111100110101101001
   L7 = 11101001011001111100110101101001
   R7 = 00000110010010101011101000010000
   L8 = 00000110010010101011101000010000
   R8 = 11010101011010010100101110010000
   L9 = 11010101011010010100101110010000
   R9 = 00100100011111001100011001111010
   L10 = 00100100011111001100011001111010
   R10 = 10110111110101011101011110110010
   L11 = 10110111110101011101011110110010
   R11 = 11000101011110000011110001111000
   L12 = 11000101011110000011110001111000
   R12 = 01110101101111010001100001011000
   L13 = 01110101101111010001100001011000
   R13 = 00011000110000110001010101011010
   L14 = 00011000110000110001010101011010
   R14 = 11000010100011001001011000001101
   L15 = 11000010100011001001011000001101
   R15 = 01000011010000100011001000110100
   L16 = 01000011010000100011001000110100
   R16 = 00001010010011001101100110010101

5) 将 R16 与 L16 组合成 R16L16, 再经过最后一个置换即可得加密后的资料 FINAL
   my @fp = (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);

   FINAL = 85E813540F0AB405


Perl code 实现如下: 

#!/usr/bin/perl -w

# DES algorithm - reference to http://orlingrabbe.com/des.htm

sub iteration_handle {
  my ($bitstring, $pad) = @_;
  my $bitstringp = pack 'b*', $bitstring;
  my @bitarray = split(//, unpack('b*',$bitstringp));

  my @subkey;
  # perl give four zeros append the last of packed string
  my ($d1, $d2) = (scalar(@bitarray) - 4, scalar(@bitarray) - 1);
  delete @bitarray[$d1..$d2];

  #print "PAD=$pad\n";

  # handle last $pad bits
  for ($n=$pad; $n>0; $n--) {
    $subkey[scalar(@bitarray)-$n] = $bitarray[$pad - $n]; 
  }

  # handle head of bits
  for($i=0; $i<(scalar(@bitarray)-$pad); $i++) {
    #if ($i == $#bitarray) {
    #  $subkey[$i] = $bitarray[0];
    #} else {
    $subkey[$i] = $bitarray[$i+$pad];
    #}
    #print $i. ": ". $subkey[$i]. "\n";
  }
  return join('', @subkey);
}

sub tobit {
  my $uncode = shift;
  my %codemap = ('0' => '0000', '1' => '0001', '2' => '0010', '3' => '0011',
                 '4' => '0100', '5' => '0101', '6' => '0110', '7' => '0111',
                 '8' => '1000', '9' => '1001', 'A' => '1010', 'B' => '1011',
                 'C' => '1100', 'D' => '1101', 'E' => '1110', 'F' => '1111');
  my $coded = '';
  my @chars = split('', $uncode);
  foreach $c (@chars) {
      $coded .= $codemap{$c};
  }
  return $coded;
}


sub tohex {
  my $origin = shift;
  my @hexbits = split(//, $origin);
  my $ret = '';
  for ($j=0; $j<@hexbits; $j=$j+4) {
    $hex = join '', @hexbits[$j..($j+3)];
    $ret .=  sprintf ("%x", oct('0b' .$hex)); 
  }
  return $ret;
}

sub permuted {

  my $unpermuted = shift;

  # the first permutation chooser map table
  my @pc1map = (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);
 
  my $permuted = '';

  my @unpermutation = split(//, $unpermuted);
  foreach $d (@pc1map) {
    $permuted .= $unpermutation[$d-1]; # start from index 1

  }
  return $permuted; 
}

sub generate_subkey {
  my $origin = shift;
  
  # the second permutation chooser map table
  my @pc2map = (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); 

  my $permuted = '';
  my @unpermutation = split(//, $origin);
  foreach $d (@pc2map) {
    $permuted .= $unpermutation[$d-1]; # start from index 1
  }
  return $permuted; 
  
}

sub initial_permutation {
  my $origin = shift;

  # the initial permutation map table
  my @IP = (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);

  my $permuted = '';
  my @unpermutation = split(//, $origin);
  foreach $d (@IP) {
    $permuted .= $unpermutation[$d-1]; # start from index 1
  }
  return $permuted;
}

sub expand {
  my $origin = shift;

  # bit selection table
  my @selection_table = (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);  

  my $permuted = '';
  my @unpermutation = split(//, $origin);
  foreach $d (@selection_table) {
    #print "array of position $d: $unpermutation[$d-1]\n";
    $permuted .= $unpermutation[$d-1]; # start from index 1
  }
  return $permuted;

}

sub subxor {
  my ($a, $b) = @_;
  my @as = split(//, $a);
  my @bs = split(//, $b);

  my @targets;

  for ($z=0; $z<@as; $z++) {
    if ($as[$z] eq '0' && $bs[$z] eq '0') {
      $targets[$z] = '0';
    } elsif ($as[$z] eq '1' && $bs[$z] eq '1') {
      $targets[$z] = '0';
    } else { 
      $targets[$z] = '1';
    }    
  }

  return join '', @targets;
}

sub cal_sboxes {
  my $origin = shift;
  
  my @sboxes;
 
  my @scalars = split(//, $origin);

  my @sb1 = (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);

  my @sb2 = (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);

  my @sb3 = (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);

  my @sb4 = ( 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);

  my @sb5 = ( 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);

  my @sb6 = (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);

  my @sb7 = ( 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);

  my @sb8 = (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);

  @sboxes = (\@sb1, \@sb2, \@sb3, \@sb4, \@sb5, \@sb6, \@sb7, \@sb8);

  my $ret = '';
  my $index = 0;
  for ($i=0; $i<@scalars; $i=$i+6, $index++) {
      $row = oct('0b'. join ('', @scalars[$i,($i+5)]));
      $col = oct ('0b'. join ('', @scalars[($i+1)..($i+4)]));
      #print "ROW: $row, COL= $col\n";
      $sindex = $row == 0 ? ($row * 15 + $col) : ($row * 16 + $col);
      #print "SINDEX = $sindex\n";
      #print "ROW= $row, COL= $col, V= $sboxes[$index][$sindex]\n";
      #print sprintf("%04b", $sboxes[$index][$sindex]);
      $ret .= sprintf("%04b", $sboxes[$index][$sindex]);
  }

  return $ret;
}

sub second_permutation {
  my $origin = shift;

  # bit selection table
  my @sp = (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);

  my $permuted = '';
  my @unpermutation = split(//, $origin);
  foreach $d (@sp) {
    $permuted .= $unpermutation[$d-1]; # start from index 1
  }
  return $permuted;
}

sub handle_func {
  
  my ($rp, $key) = @_;

  # expand $rp[n-1] from 32 bits to 48 bits
  my $expands = expand $rp;
  #print "EXP= $expands\n";

  # XOR
  my $xor = subxor $key, $expands;

  #print "XOR= $xor\n";
  my $ret = '';
  # calcute sboxes
  my $sbs = cal_sboxes($xor); 
  #print "SBS= $sbs\n";
  
  $ret = second_permutation $sbs;
  #print "FP = $final\n";

  return $ret;
}

sub final_permutation {
  my $origin = shift;

  # bit selection table
  my @fp = (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);

  my $permuted = '';
  my @unpermutation = split(//, $origin);
  foreach $d (@fp) {
    $permuted .= $unpermutation[$d-1]; # start from index 1
  }
  return $permuted;
}

# Step1: Create 16 subkeys, each of which is 48-bits long.
$original_key = '133457799BBCDFF1'; 
print "KEY   = ". $original_key. "\n";

my $keybits = tobit $original_key;

print "K = ". $keybits. "\n";

$permutation = permuted $keybits;

print "K+ = ". $permutation. "\n\n";

my @subkeys;

$subkeys[0] = $permutation;

my @permutations = split(//, $permutation);

my @leftpart;
my @rightpart;

$leftpart[0] = join('', @permutations[0..27]);
$rightpart[0] = join ('', @permutations[28..55]);

print "C0: ". $leftpart[0]. "\n";
print "D0: ". $rightpart[0]. "\n\n";

# irations table for shift N
my %iterations = (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);

for ($j=1; $j<=16; $j++) {
  $leftpart [$j] = iteration_handle $leftpart[$j-1], $iterations{$j};
  $rightpart[$j] = iteration_handle $rightpart[$j-1], $iterations{$j};
  #print "C". $j. " = ". $leftpart[$j]. "\n";
  #print "D". $j. " = ". $rightpart[$j]. "\n\n";
  $subkeys[$j] = generate_subkey($leftpart[$j]. $rightpart[$j]);
  print "K". $j. " = ". $subkeys[$j]. "\n";
}

# Step 2: Encode each 64-bit block of data

my $data = '0123456789ABCDEF';
print "DATA  = ". tobit($data). "\n";
my $ip = initial_permutation(tobit($data));
print "IP = ". $ip. "\n";

# $ip = $lp[0] + $rp[0]

my (@lp, @rp);
$lp[0] = join '', (split(//, $ip))[0..31];
$rp[0] = join '', (split(//, $ip))[32..63];

print "L0 = ". $lp[0]. "\n";
print "R0 = ". $rp[0]. "\n";

for ($x=1; $x<=16; $x++) {
  $lp[$x] = $rp[$x-1];
  #print "L". $x. " = ". $lp[$x]. "\n";
  #print "R". ($x-1). " = ". $rp[$x-1]. "\n";
  #print "K". $x. " = ". $subkeys[$x]. "\n";
  #print "L". ($x-1). " = ". $lp[$x-1]. "\n";
  $rp[$x] = subxor($lp[$x-1], handle_func($rp[$x-1], $subkeys[$x]));
  #print "R". $x. " = ". $rp[$x]. "\n";
}

my $reverse = $rp[16]. $lp[16];
#print "R16L16 = ". $reverse. "\n";

my $final = final_permutation $reverse;
$final = uc(tohex $final);

print "FINAL = $final\n";


你可能感兴趣的:(JOIN,c,String,table,encryption,permutation)