DES加密詳解

注: 下述全部加法均爲模二加, 即爲亦或運算c++

1 根據輸入的祕鑰獲得16個子祕鑰

1.1 大體流程

graph TB; a[輸入一個64位長度的字符串,即爲祕鑰K_0] b[根據PC-1表挑出56位做爲新祕鑰K_1] c[K_1拆分,循環左移獲得16個子祕鑰k0...k15] d[使用PC-2表從各子祕鑰56位中挑出48位] a-->b-->c-->d
圖1.1.1 算法流程

image-20210301204737481

圖1.1.2 PC-1表及PC-2表

1.2 利用PC-1從K_0中挑出K_1

​ 接下來咱們以輸入的祕鑰爲"0x123456789abcdeff"爲例, 及二進制編碼爲:算法

"0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 1111"編碼

image-20210301210922245

圖1.2.1 初始祕鑰K_0

​ 接下來咱們利用PC-1表生成新祕鑰K_1加密

image-20210301211558977

圖1.2.2 挑出的56位二進制串

"1111 0000 1100 1100 1010 1010 1111"和"1101 0101 1110 0110 1111 1000 1111"spa

兩邊各是28位, 共56位code

1.3 利用PC-2從K_1中挑出16個子祕鑰

​ 對於從1.2得來的一串56位二進制碼, 咱們將其拆分紅兩串28位二進制碼, 即爲:blog

左半部分的"1111 0000 1100 1100 1010 1010 1111", 並將其命名爲C_0ip

右半部分的"1101 0101 1110 0110 1111 1000 1111", 並將其命名爲D_0字符串

​ 接下來, 咱們利用下表, 進行循環左移, 規則以下:it

image-20210301230226344

圖1.3.1 位移規則表

​ 以後咱們按照上面的規則, 展現子祕鑰k_1是如何生成的:

  1. 將C_0和D_0分別循環左移1位, 獲得C_1-"1110 0001 1001 1001 0101 0101 1111"以及D_1-"1010 1011 1100 1101 1111 0001 1111"(PS:循環左移1位就是將首位移動到最後末尾)
  2. 將C_1即D_1拼接起來, 獲得"1110 0001 1001 1001 0101 0101 1111 1010 1011 1100 1101 1111 0001 1111"
  3. 利用PC-2表從拼接獲得的字符串中挑選出子祕鑰k_1, 相似於"利用PC-1表的過程"

image-20210301233109216

圖1.3.2 從C_0和D_0中生成的子祕鑰k_0
  1. 因此子祕鑰k_1爲"0001 1011 0000 0010 1110 1111 1111 1100 0111 1001 0111 0110"

​ 按照一樣的邏輯, 在C_0和D_0已被循環左移的基礎上, 重複上述步驟, 咱們獲得以下16個子祕鑰:

image-20210302004853659

圖1.3.3 生成的全部子祕鑰

PS: 上述輸出爲本身寫的代碼, 在文末會進行展現.

​ 獲得了這16個子祕鑰後, 咱們就能夠對明文進行加密了, 咱們繼續!

2 利用16個子祕鑰對明文進行加密

2.1 大體流程

graph TB; a[對64位的明文進行初始變化,簡稱IP-Initial Permutation] b[將IP後的明文平分紅32位的L0-左半邊和R0-右半邊] c[接下來使用以下公式對L_n和R_n進行變換] d["1.L_n=R_n-1<br>2.R_n=L_n-1 + f(R_n-1, k_n)"] e["f的具體過程以下<br>1.將R_n-1擴展成48位並與k_n-1相加"獲得S盒<br>2.使用8張S表將48位的S盒運算成32位輸出P<br>3.使用P表對輸出P進行位置變換] f["獲得輸出L_16和R_16, 拼接成R_16L_16的64位輸出"] g["對這64位輸出使用IP-1表進行位置變換, 即獲得最終輸出"] a-->b-->c-->d-.-e-.->f-->g d--重複16次-->d
圖2.1.1 算法流程

2.2 將R_0擴展成48位的二進制串, 並與子祕鑰k模二加

​ 咱們以輸入的明文爲"0x0123456789abcdef"爲例, 即二進制編碼爲:

"0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111"

通過變換後,獲得:

"1100 1100 0000 0000 1100 1100 1111 1111 1111 0000 1010 1110 1111 0000 1010 1010"

將其拆分爲L_0及R_0, 各32位

L_0: "1100 1100 0000 0000 1100 1100 1111 1111"

R_0: "1111 0000 1010 1110 1111 0000 1010 1010"

對R_0使用以下規則擴展成48位:

image-20210302212306838

圖2.2.1 R_0擴展成48位規則

PS: 綠色的標出的位數即爲擴展出的12位

所以, 獲得RExtend(8個6位): "011110 100001 010101 011101 011110 100001 010101 010101"

將其與子祕鑰"0001 1011 0000 0010 1110 1111 1111 1100 0111 1001 0111 0110"

亦或得S盒"0110 0001 0001 0111 1011 0010 1000 0110 0110 1100 0010 0011"

2.3 使用S1-S8表將48位變回32位

​ 爲何上面S盒要備註8個6位呢? 緣由就是要以8個6位爲輸入, 分別通過S1-S8盒的運算,獲得8個4位輸出, 也就變成了32位.

image-20210302152840419

圖2.3.1 S1-S8表

咱們的S盒長這樣"011000 010001 011110 110010 100001 100110 110000 100011"

以第一個6位"011000"爲輸入, 代入到S1表變換

"011000"的首位和末尾拼起來的數字爲行號, 中間4位爲列號(固然都是二進制的), 即第0(00b)行, 第15(1100b)列, 查詢S1表, 爲S1(0, 12) = 5 = 0101b

這樣就能夠獲得第一個4位的輸出, 按照這樣的方式能夠獲得8個4位的輸出, 合在一塊兒就是一個32位的輸出, 通過運算是"0101 1100 1000 0001 1011 0101 1010 0001"

2.4 使用P表對32位輸出進行位置變換, 並和L0相加

​ 咱們已經獲得通過"擴位"和"縮位"的變換, 如今要按照P表進行簡單的位置變換:

image-20210302154240976

圖2.4.1 P表

image-20210302223935952

圖2.4.2 32位輸出的每一位狀況

照着P表生成新的32位輸出"1010 0001 0000 1000 1010 1101 1001 1011"

再將輸出與L_0相加, L_0:"1100 1100 0000 0000 1100 1100 1111 1111"

獲得結果: "0110 1101 0000 1000 0110 0001 0110 0100"

2.5 往復這樣的步驟16次, 將獲得的R_16和L_16拼接並經IP^-1變換

​ 如題, 獲得最終結果:

"1110 1100 1010 1001 0011 1101 1001 1100 1110 0100 1101 1001 1001 1001 1100 1110"

3 代碼實現

/*
 * @Description: 
 * @Autor: Shmily
 * @Date: 2021-03-01 23:40:00
 * @LastEditTime: 2021-03-02 22:35:49
 */

#include <bits/stdc++.h>
using namespace std;

const int8_t PC_1[56] = {
  57, 49, 41, 33, 25, 17, 9, 1,
  58, 50, 42, 34, 26, 18, 10, 2,
  59, 51, 43, 35, 28, 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 int8_t PC_2[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 int8_t left_move[16] = {
  1, 1, 2, 2, 2, 2, 2, 2,
  1, 2, 2, 2, 2, 2, 2, 1
};

const int8_t S8[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}
  }
};

const int8_t PTable[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, 4,
  22, 11, 4, 25
};

const int8_t IP[2][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, 16, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5,
    63, 55, 47, 39, 31, 23, 15, 7
  },
  {
    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
  }
};

void out_int8_t(int8_t* out, int len) {
  for (int i = 0; i < len; i++) {
    printf("%d", out[i]);
    if ((i + 1) % 4 == 0) cout << " ";
  }
  cout << endl;
}

void fun_left_move(int8_t* C_0, int8_t* D_0, int times_left) {
  for (int i = 0; i < times_left; i++) {
    int8_t temp1 = C_0[0];
    int8_t temp2 = D_0[0];
    for (int j = 1; j < 28; j++) {
      C_0[j - 1] = C_0[j];
      D_0[j - 1] = D_0[j];
    }
    C_0[27] = temp1;
    D_0[27] = temp2;
  }
}

void Extend32To48(int8_t (*R) [32], int8_t (*RExtend) [48], int times) {
  RExtend[times][0] = R[times][31];
  RExtend[times][47] = R[times][0];
  for (int i = 1; i < 47; i++) {
    // 6個位一組, 即爲一行
    int LineNumber = (int)(i / 6);
    RExtend[times][i] = R[times][i - 1 - LineNumber*2];
  }
}

void XOR(int8_t (*RExtend) [48], int8_t (*k) [48], int8_t (*S) [48], int times) {
  for (int i = 0; i < 48; i++) {
    // 進行模二加運算
    S[times][i] = (RExtend[times][i] + k[times][i]) % 2;
  }
}

void XOR(int8_t (*L) [32], int8_t (*Pchanged) [32], int8_t (*R) [32], int times) {
  for (int i = 0; i < 32; i++) {
    R[times + 1][i] = (L[times][i] + Pchanged[times][i]) % 2;
  }
}

void UseS48To32(int8_t (*S) [48], int8_t (*P) [32], int times) {
  for (int i = 0; i < 8; i++) {
    int line = 0, row = 0;
    // 計算出行號及列號
    line = line + S[times][i*6]*2 + S[times][5 + i*6];
    row = row + S[times][1 + i*6]*8 + S[times][2 + i*6]*4 + S[times][3 + i*6]*2 + S[times][4 + i*6];
    // 從S表中挑出答案
    int8_t ans = S8[i][line][row];
    for (int j = 0; j < 4; j++) {
      int subtrahend = pow(2, (3 - j));
      if (ans - subtrahend >= 0) {
        P[times][j + i*4] = 1;
        ans -= subtrahend;
      }
      else P[times][j + i*4] = 0;
    }
  }
}

void UsePChangeP(int8_t (*P) [32], int8_t (*PChanged) [32], int times) {
  for (int i = 0; i < 32; i++) {
    PChanged[times][i] = P[times][PTable[i] - 1];
  }
}

void UseIPChange(int8_t* in, int8_t* out, int8_t choice) {
  for (int i = 0; i < 64; i++) {
    out[i] = in[IP[choice][i] - 1];
  }
}

int main(void) {
  // 對祕鑰進行處理
  // 輸入爲64位祕鑰, 輸出位16個32位子祕鑰
  int8_t K_0[64], K_1[56], k[16][48];
  // 祕鑰爲"0x123456789abcdeff"
  char in[] = "0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 1111";
  int len = strlen(in);
  // 將輸入的祕鑰存儲到K_0中
  for (int i = 0, j = 0; i < len; i++) {
    if (in[i] == '0') K_0[j++] = 0;
    else if (in[i] == '1') K_0[j++] = 1;
  }
  // 利用PC-0表, 從K_0中取出K_1
  for (int i = 0; i < 56; i++) {
    // 注意-1
    K_1[i] = K_0[PC_1[i]-1];
  }
  // 上述完成了第一步利用PC-1表
  // 接下來利用PC-2表
  int8_t C_0[28], D_0[28];
  // 將K_1拆分
  for (int i = 0; i < 56; i++) {
    if (i < 28) C_0[i] = K_1[i];
    else D_0[i - 28] = K_1[i];
  }
  // 循環16次生成16個子祕鑰
  for (int i = 0; i < 16; i++) {
    int8_t times_left = left_move[i];
    fun_left_move(C_0, D_0, times_left);
    for (int j = 0; j < 48; j++) {
      int8_t sub = PC_2[j] - 1;
      if (sub < 28) k[i][j] = C_0[sub];
      else k[i][j] = D_0[sub - 28];
    }
    // printf("子祕鑰k[%.2d]: ", i + 1);
    // out_int8_t(k[i], 48);
  }

  
  // 對明文進行處理
  // 明文爲"0x0123456789abcdef"
  char in_text[] = "0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111";
  int8_t PlainText[64], IP_PlainText[64], EnchiperTextInitial[64], EnchiperText[64];
  int8_t L[17][32], R[17][32], RExtend[16][48], S[16][48], P[16][32], PChanged[16][32];
  int len_text = strlen(in_text);
  // 64位明文存儲到PlainText中
  for (int i = 0, j = 0; i < len; i++) {
    if (in_text[i] == '0') PlainText[j++] = 0;
    else if (in_text[i] == '1') PlainText[j++] = 1;
  }
  // 使用IP對PlainText進行變換
  UseIPChange(PlainText, IP_PlainText, 0);
  // 將PlainText分左右存儲到L_0及R_0中
  for (int i = 0; i < 64; i++) {
    if (i < 32) L[0][i] = IP_PlainText[i];
    else R[0][i - 32] = IP_PlainText[i];
  }
  // 循環16次
  for (int times = 0; times < 16; times++) {
    // L_n = R_n-1
    for (int i = 0; i < 32; i++) {
      L[times + 1][i] = R[times][i];
    }
    
    // L_n = L_n-1 + f(R_n-1, k_n)
    // 對R進行擴展
    Extend32To48(R, RExtend, times);
 
    // 將RExtend與k_n-1模二加
    XOR(RExtend, k, S, times);

    // 使用S表將S盒48位壓縮成32位
    UseS48To32(S, P, times);

    // 使用P表對P進行位置變換
    UsePChangeP(P, PChanged, times);
    
    // 生成的PChanged就是通過f以後的
    // 模二加後放入R_n
    XOR(L, PChanged, R, times);
  }

  for (int i = 0; i < 64; i++) {
    if (i < 32) EnchiperTextInitial[i] = R[16][i];
    else EnchiperTextInitial[i] = L[16][i - 32];
  }
  // 使用IP^-1對EnchiperTextInitial的進行變換獲得Enchiper
  UseIPChange(EnchiperTextInitial, EnchiperText, 1);

  //最終結果輸出
  out_int8_t(EnchiperText, 64);

  return 0;
}
相關文章
相關標籤/搜索