使用 OpenSSL 的 DES_set_key / DES_ecb_encrypt 等 API 時,發現密鑰調度結構體 DES_key_schedule (通常別名 DES_ks_struct) 大小為 128 字節(16 個 DES_LONG,每個 4 或 8 字節),而 DES 密鑰實際僅 8 字節(56 位有效 + 8 位校驗),疑惑為何需要如此大的結構體,且形參實參如何結合。
DES 加密演算法包含 16 輪迭代,每輪需要一個 48 位的子密鑰。密鑰調度 是將用戶提供的 8 字節主密鑰,通過 PC-1 置換、循環左移、PC-2 置換等操作,預先計算出 16 個子密鑰並存儲。這避免了每次加密塊都重複計算子密鑰,提升性能。
在 openssl/des.h 中定義:
typedef struct DES_ks_struct {
DES_LONG ks[16]; // 16 個子密鑰,每個 32 位或 64 位視架構而定
} DES_key_schedule;
DES_LONG = 4 字節 → 16 × 4 = 64 字節DES_LONG = 8 字節 → 16 × 8 = 128 字節題主環境為 64 位,故結構體大小 128 字節完全正常。
API 簽名:
void DES_set_key(const_DES_cblock *key, DES_key_schedule *schedule);
void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks, int enc);
key:指向 8 字節密鑰塊的指針(實參)。schedule:指向調用者分配的 DES_key_schedule 結構體的指針(實參,輸出參數)。schedule 指向的內存。schedule 指針,直接讀取預計算子密鑰。#include
#include
int main() {
// 1. 準備 8 字節密鑰 (需設置奇校驗位,或用 DES_set_key_unchecked)
DES_cblock key = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
// 2. 分配密鑰調度結構 (棧上或堆上)
DES_key_schedule ks; // 大小 128 字節 (x64)
// 3. 生成子密鑰表
DES_set_key_unchecked(&key, &ks); // 不檢查校驗位,常用於測試
// 4. 加密單個 8 字節塊
DES_cblock input = "12345678"; // 8 字節
DES_cblock output;
DES_ecb_encrypt(&input, &output, &ks, DES_ENCRYPT);
// 5. 解密
DES_cblock decrypted;
DES_ecb_encrypt(&output, &decrypted, &ks, DES_DECRYPT);
return 0;
}
EVP_* 高級 API)。legacy 提供者或降級策略。