首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

DES 加密算法原理與 VC++ 實現(下):子金鑰生成、解密流程與完整測試向量

     編輯:關於VC++

前言

接續上篇「DES 加密核心流程(IP 置換、16 輪迭代、f 函數、S 盒、P 置換)」,本文詳細解析子金鑰生成演算法、解密流程,並提供完整測試向量(明文、金鑰、中間值、最終密文),供實作驗證參考。

子金鑰生成:從 64 位主金鑰到 16 個 48 位子金鑰

1. PC-1 置換:64 位 → 56 位(捨棄奇偶校驗位)

PC-1 表(輸出位來自輸入位):
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

輸入 64 位金鑰 K,經 PC-1 得 56 位串,分為左 28 位 C₀、右 28 位 D₀。

2. 循環左移與 PC-2 產生子金鑰 Kᵢ

每輪 i:Cᵢ₋₁、Dᵢ₋₁ 循環左移 LSᵢ 位 → Cᵢ、Dᵢ → 合併 56 位 → PC-2 置換 → 48 位 Kᵢ。

3. 左移位數表 LSᵢ

輪次 i12345678910111213141516
LSᵢ1122222212222221

4. PC-2 置換:56 位 → 48 位

PC-2 表:
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

5. VC++ 子金鑰生成核心代碼片段

// PC-1: 64位 -> 56位
for (i = 1; i < 57; i++) k0[i] = k[PC_1[i-1]];

// 分為 C0, D0 (各 28 位)
// 以下以生成 K8 為例 (LS8 = 2)
for (i = 1; i < 27; i++) {      // 循環左移 2 位
    C8[i] = C7[i+2];
    D8[i] = D7[i+2];
}
C8[27] = C7[1];  D8[27] = D7[1];
C8[28] = C7[2];  D8[28] = D7[2];

// 合併 C8, D8 -> 56 位
for (i = 1; i <= 28; i++) {
    C[i] = C8[i];
    C[i+28] = D8[i];
}

// PC-2 -> 48 位 K8
for (i = 1; i <= 48; i++)
    K8[i] = C[PC_2[i-1]];

注意:實際實作時需對 16 輪分別套用對應 LSᵢ,不可固定左移 2 位。

解密流程:逆序使用子金鑰

DES 解密結構與加密完全相同,唯一差別:16 輪迭代使用子金鑰順序相反:

  • 加密:K₁, K₂, ..., K₁₆
  • 解密:K₁₆, K₁₅, ..., K₁

數學證明:第 1 輪解密輸入 (L₁₆, R₁₆),使用 K₁₆ 經 f 函數後與 L₁₆ 異或還原 R₁₅,以此類推,最終還原 (L₀, R₀)。

完整測試向量(供程式驗證)

輸入

  • 明文 m = "learning" (8 字元 = 64 位)
  • 金鑰 k = "computer" (8 字元 = 64 位)

明文 ASCII 二進制

m = 01101100 01100101 01100001 01110010
    01101110 01101001 01101110 01100111

金鑰 ASCII 二進制

k = 01100011 01101111 01101101 01110000
    01110101 01110100 01100101 01110010

IP 置換後

11111111 00001000 11010011 10100110
00000000 11111111 01110001 11011000
L₀ = 11111111 00001000 11010011 10100110
R₀ = 00000000 11111111 01110001 11011000

16 輪迭代中間值 (Lᵢ, Rᵢ) 摘錄

L₁ = R₀
R₁ = L₀ ⊕ f(R₀, K₁) = 00110101 00110001 00111011 10100101
...
L₁₆ = 01010000 11100100 11011101 10100011
R₁₆ = 01111101 10101000 01001100 01100001

f 函數輸出 f₁~f₁₆ (32 位)

f₁  = 11001010 00111001 11101000 00000011
f₂  = 00010111 00011101 11001011 01011111
...
f₁₆ = 01100011 11100001 11110100 00000000

16 個子金鑰 K₁~K₁₆ (48 位)

K₁  = 11110000 10111110 11101110 11010000
K₂  = 11100000 10111110 11110110 10010101
...
K₁₆ = 11110001 10111110 00101110 00000001

S 盒查表結果 (每輪 8 個 4 位輸出)

第 1 輪: 5, 11, 4, 1, 0, 3, 13, 9
第 2 輪: 7, 13, 15, 8, 12, 12, 13, 1
...
第 16 輪: 12, 3, 4, 6, 9, 3, 3, 0

Cᵢ, Dᵢ 迴轉過程 (28 位)

C₀ = 0000000011111111111111111011
D₀ = 1000001101110110000001101000
...
C₁₆ = C₀, D₁₆ = D₀  (16 輪後恢復初始值)

最終密文

R₁₆ || L₁₆ 經 IP⁻¹ 置換後得到 64 位密文。

實作驗證清單

  1. PC-1/PC-2 表索引是否正確(1-based ↔ 0-based 轉換)
  2. 循環左移邊界處理(C[27]=C[1], C[28]=C[2])
  3. E 擴展表、S 盒、P 置換表與標準 FIPS 46-3 一致
  4. 異或運算使用位元級 ^ 運算子,非邏輯 !=
  5. 解密時子金鑰陣列逆序索引
  6. 大小端序:DES 定義為大端序(網路序),位組順序需一致
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved