RSA 依賴 512~4096 位大整數運算,遠超編譯器原生類型(32/64 位)。三種實現路線:
| 方案 | 原理 | 優缺點 |
|---|---|---|
| 十進制字符串模擬豎式 | 字符數組存十進制,逐位運算 | 易理解,效率極低(基數小,循環多) |
| 二進制流邏輯操作 | 位移、邏輯運算模擬加減乘除 | 代碼複雜、可讀性差、調試難 |
| N 進制數組(推薦) | 基數 2^16 或 2^32,數組元素存一「位」 | 循環少、利用硬件乘法、邏輯清晰 |
本文採用 基數 2^16 (65536),元素類型 unsigned short。乘除時擴展為 unsigned long(32 位)計算,避免溢出,兼顧速度與可讀性。1024 位大數 = 64 個 unsigned short。
d ≡ e⁻¹ mod φ(n),遞歸實現 ax + by = gcd(a,b)。c = m^e mod n 核心。掃描指數位,平方乘模,配合蒙哥馬利約減避免大數除法。
// 產生大素數 p, q (Rabin-Miller 測試 + 小素數篩選)
n = p * q;
φ = (p-1)*(q-1);
選擇 e (常用 65537),gcd(e, φ)=1;
d = exgcd(e, φ) 模 φ; // d*e ≡ 1 (mod φ)
公鑰 (n, e),私鑰 (n, d) 或 (p, q, d, dp, dq, qinv) 用於 CRT 加速
00 02 [PS] 00 [Data]。c = m^e mod n (公鑰操作)。m = c^d mod n (私鑰操作),可用 CRT (中國剩餘定理) 4 倍加速。
// 大數結構
typedef struct { short len; unsigned short d[MAX_DIGITS]; int sign; } BigInt;
// 關鍵函數
char GenKey(BigInt *n, BigInt *e, BigInt *d);
char EncRSA(const unsigned char *in, int inlen, BigInt *e, BigInt *n,
unsigned char *out, int *outlen, int keytype);
char DecRSA(const unsigned char *in, int inlen, BigInt *d, BigInt *n,
unsigned char *out, int *outlen, int keytype);
// 輔助
char IsNotPrime(BigInt *p); // 小素數篩選
char RabinMillerTest(BigInt *p, int t); // 概率素性測試
char GenPrime(BigInt *p); // 產生大素數
char Str2BigInt(BigInt *a, char *str, int base); // 字符串↔大數
char BigInt2Str(char *str, BigInt *a, int base);
/dev/urandom, getrandom, BCryptGenRandom)。explicit_bzero),防止內存轉儲洩露。RSA 核心是大整數模冪運算,工程難點在於大數高效實現、側信道防護、填充標準合規。理解原理有助於正確選型與配置庫,但切勿在生產代碼中使用自製加密實現。