Crypto
- 一、DES加密算法
-
- [1 整体结构:Feistel网络的经典实现](#1 整体结构:Feistel网络的经典实现)
-
- [1.1 Feistel网络的核心思想](#1.1 Feistel网络的核心思想)
- [2 轮函数F的细节](#2 轮函数F的细节)
-
- [2.1 扩展置换(E)](#2.1 扩展置换(E))
- [2.2 与子密钥异或](#2.2 与子密钥异或)
- [2.3 S-box压缩](#2.3 S-box压缩)
- [2.4 P置换(P)](#2.4 P置换(P))
- [3 密钥调度](#3 密钥调度)
- 二、AES加密算法
-
- [1 AES的代数结构](#1 AES的代数结构)
-
- [1.1 有限域 G F ( 2 8 ) GF(2^8) GF(28)](#1.1 有限域 G F ( 2 8 ) GF(2^8) GF(28))
- [1.1 状态矩阵](#1.1 状态矩阵)
- [2 AES的轮函数结构](#2 AES的轮函数结构)
-
- [2.1 SubBytes(字节代换)](#2.1 SubBytes(字节代换))
- [2.2 ShiftRows(行移位)](#2.2 ShiftRows(行移位))
- [2.3 MixColumns(列混合)](#2.3 MixColumns(列混合))
- [2.4 AddRoundKey(轮密钥加)](#2.4 AddRoundKey(轮密钥加))
- [3 密钥扩展(Key Schedule)](#3 密钥扩展(Key Schedule))
- [4 加解密流程](#4 加解密流程)
-
- 4.1加密
- [4.2 解密](#4.2 解密)
- [5 分组密码工作模式](#5 分组密码工作模式)
- 三、RSA加密算法
-
- [1 数学基础](#1 数学基础)
-
- [1.1 预备知识](#1.1 预备知识)
- [1.2 密钥生成](#1.2 密钥生成)
- [1.3 加密与解密](#1.3 加密与解密)
- [1.4 数值示例](#1.4 数值示例)
- [1.5 中国剩余定理 (CRT) 加速](#1.5 中国剩余定理 (CRT) 加速)
- 攻击方式
-
- [1 破解模数n(已知 n, e, c,分解 n 求 p, q)](#1 破解模数n(已知 n, e, c,分解 n 求 p, q))
- [2 共模攻击(相同 n,不同 e1, e2)](#2 共模攻击(相同 n,不同 e1, e2))
- [3 模不互素(多个 n 共享素数)](#3 模不互素(多个 n 共享素数))
- [4 e = 2, 4, 8 ...(低加密指数,但 e 为偶数时的 Rabin 密码)](#4 e = 2, 4, 8 ...(低加密指数,但 e 为偶数时的 Rabin 密码))
- [5 e = 3, 5, 7 ...(低加密指数小明文攻击)](#5 e = 3, 5, 7 ...(低加密指数小明文攻击))
- [6 d泄漏攻击(已知 d, n, e, c)](#6 d泄漏攻击(已知 d, n, e, c))
- [7 dp和dq泄漏(已知 p, q, dp, dq, c,求解 mp,mq,InvQ,m)](#7 dp和dq泄漏(已知 p, q, dp, dq, c,求解 mp,mq,InvQ,m))
一、DES加密算法
DES 全称Data Encryption Standard(数据加密标准),它奠定了现代分组密码设计的基础。DES是一个分组密码,分组长度64位,密钥有效长度56位,使用16轮迭代的Feistel网络结构。
1 整体结构:Feistel网络的经典实现
1.1 Feistel网络的核心思想
Feistel网络将数据块分为左右两半(各32位): L i L_i Li 和 R_i 。每一轮加密只对右半部分应用轮函数 F F F,然后与左半部分异或,最后交换左右。其数学描述为:
L i + 1 = R i R i + 1 = L i ⊕ F ( R i , K i ) \begin{array}{l}{{L_{i+1}=R_{i}}}\\ {{R_{i+1}=L_{i}\oplus F(R_{i},K_{i})}}\end{array} Li+1=RiRi+1=Li⊕F(Ri,Ki)这种结构的巨大优势在于加解密完全相同(只需逆序使用子密钥),极大简化了硬件实现。
DES的16轮Feistel结构如下:
- 初始置换(IP):对64位明文进行固定比特重排。
- 16轮迭代:每轮使用不同的48位子密钥 K i K_i Ki
- 左右交换:第16轮输出后,交换左右两半。
- 逆初始置换(IP⁻¹):得到64位密文。
2 轮函数F的细节
轮函数 F ( R , K ) F(R,K) F(R,K) 是DES安全性的核心,它将32位右半部分 R R R 和48位子密钥 K K K 映射为32位输出。步骤如下:
2.1 扩展置换(E)
将32位 R R R 扩展为48位。这个置换不仅复制了16个Byte(其中一些Byte出现在两个位置上),还让输出Byte与输入Byte产生依赖关系,便于后续S-box压缩后仍能影响多个比特。
2.2 与子密钥异或
扩展后的48位与当前轮的48位子密钥 K i K_i Ki 进行XOR。
2.3 S-box压缩
48位结果分成8个6位块,每块送入一个S-box(S₁ 到 S₈)。每个S-box将6位输入映射为4位输出。S-box是非线性的------它是DES唯一的非线性组件,提供了密码强度。
每个S-box是一个 4 × 16 4×16 4×16 的查找表。6位输入:首位和末位组成行号(0-3),中间4位组成列号(0-15),输出对应单元格的4位值。
例如,S₁的查找表(十六进制):
bash
行0: 0xE,0x4,0xD,0x1,0x2,0xF,0xB,0x8,0x3,0xA,0x6,0xC,0x5,0x9,0x0,0x7
行1: 0x0,0xF,0x7,0x4,0xE,0x2,0xD,0x1,0xA,0x6,0xC,0xB,0x9,0x5,0x3,0x8
行2: 0x4,0x1,0xE,0x8,0xD,0x6,0x2,0xB,0xF,0xC,0x9,0x7,0x3,0xA,0x5,0x0
行3: 0xF,0xC,0x8,0x2,0x4,0x9,0x1,0x7,0x5,0xB,0x3,0xE,0xA,0x0,0x6,0xD
2.4 P置换(P)
8个S-box输出的32位比特经过一个固定的P置换,将比特打乱,确保每个S-box的输出在下一轮扩散到多个S-box的输入。
3 密钥调度
DES从56位有效密钥生成16个48位子密钥。过程如下:
- 初始64位密钥(含8位奇偶校验)经过置换选择PC-1,去掉校验位并重排,得到56位 C 0 C_0 C0 和 D 0 D_0 D0(各28位)。
- 对 i = 1 i=1 i=1 到 16 16 16:
- 将 C i − 1 C_{i-1} Ci−1 和 D i − 1 D_{i-1} Di−1 循环左移1或2位(轮次1,2,9,16左移1位,其他左移2位)。
- 将移位后的 C i C_i Ci 和 D i D_i Di 合并,经过置换选择PC-2(选择48位)得到子密钥 K i K_i Ki。
PC-1和PC-2的置换表在标准中固定。
二、AES加密算法
AES 全称Advanced Encryption Standard(高级加密标准),它是目前全球使用最广泛的对称加密算法,其设计融合了代换-置换网络(SPN)结构与有限域代数。
1 AES的代数结构
1.1 有限域 G F ( 2 8 ) GF(2^8) GF(28)
AES的所有操作都定义在有限域 G F ( 2 8 ) GF(2^8) GF(28) 上,具体采用不可约多项式:
m ( x ) = x 8 + x 4 + x 3 + x + 1 m(x) = x^8 + x^4 + x^3 + x + 1 m(x)=x8+x4+x3+x+1
每个字节可以视为一个系数在 { 0 , 1 } \{0, 1\} {0,1} 上的多项式,例如字节0x57=01010111对应多项
式 x 6 + x 4 + x 3 + x + 1 x^6 + x^4 + x^3 + x + 1 x6+x4+x3+x+1
加法和乘法都是模 m ( x ) m(x) m(x) 下的域运算:
- 加法:按位 X O R XOR XOR(相同多项式次数系数相加模2)。
- 乘法:多项式乘法后模 m ( x ) m(x) m(x)。
1.1 状态矩阵
AES处理固定128位(16字节)的数据块,将其组织为 4 × 4 4×4 4×4 字节矩阵(列优先):
S t a t e = s 0 , 0 s 0 , 1 s 0 , 2 s 0 , 3 s 1 , 0 s 1 , 1 s 1 , 2 s 1 , 3 s 2 , 0 s 2 , 1 s 2 , 2 s 2 , 3 s 3 , 0 s 3 , 1 s 3 , 2 s 3 , 3 \mathrm { S t a t e } = \left \\begin{array} { l l l l } { s _ { 0 , 0 } } \& { s _ { 0 , 1 } } \& { s _ { 0 , 2 } } \& { s _ { 0 , 3 } } \\\\ { s _ { 1 , 0 } } \& { s _ { 1 , 1 } } \& { s _ { 1 , 2 } } \& { s _ { 1 , 3 } } \\\\ { s _ { 2 , 0 } } \& { s _ { 2 , 1 } } \& { s _ { 2 , 2 } } \& { s _ { 2 , 3 } } \\\\ { s _ { 3 , 0 } } \& { s _ { 3 , 1 } } \& { s _ { 3 , 2 } } \& { s _ { 3 , 3 } } \\end{array} \\right State= s0,0s1,0s2,0s3,0s0,1s1,1s2,1s3,1s0,2s1,2s2,2s3,2s0,3s1,3s2,3s3,3
输入明文按字节填充:前4字节为第一列,次4字节为第二列,以此类推。
2 AES的轮函数结构
AES是一个迭代分组密码,轮数 N r N_r Nr 取决于密钥长度:
- AES-128: N r = 10 N_r=10 Nr=10,密钥长度128位
- AES-192: N r = 12 N_r=12 Nr=12,密钥长度192位
- AES-256: N r = 14 N_r=14 Nr=14,密钥长度256位
每一轮(除最后一轮外)包含四个可逆变换:
| 密钥长度 | 分组长度 | 迭代轮数 |
|---|---|---|
| 128bit | 128bit | 10 轮 |
| 192bit | 128bit | 12 轮 |
| 256bit | 128bit | 14 轮 |
不同轮数的AES密钥逻辑框架完全一致,仅循环轮数不同。
2.1 SubBytes(字节代换)
独立对状态矩阵的每个字节应用S-box (代换盒)。S-box是一个 16 × 16 16×16 16×16 的查找表,其构造具有强代数性质:
- 计算字节在 G F ( 2 8 ) GF(2^8) GF(28) 上的乘法逆元(
0x00映射到自身)。 - 对逆元应用仿射变换: b i ′ = b i ⊕ b ( i + 4 ) m o d 8 ⊕ b ( i + 5 ) m o d 8 ⊕ b ( i + 6 ) m o d 8 ⊕ b ( i + 7 ) m o d 8 ⊕ c i b'i = b_i \oplus b{(i+4) \bmod 8} \oplus b_{(i+5) \bmod 8} \oplus b_{(i+6) \bmod 8} \oplus b_{(i+7) \bmod 8} \oplus c_i bi′=bi⊕b(i+4)mod8⊕b(i+5)mod8⊕b(i+6)mod8⊕b(i+7)mod8⊕ci其中 c i c_i ci 是常数
0x63的第 i i i 位。
2.2 ShiftRows(行移位)
将状态矩阵的每一行循环左移不同字节数:
- 第0行:不移位
- 第1行:左移1字节
- 第2行:左移2字节
- 第3行:左移3字节
作用是将列的扩散到其他列。
2.3 MixColumns(列混合)
对每一列独立进行线性变换。将列视为 G F ( 2 8 ) GF(2^8) GF(28) 上的4次多项式,并乘以固定多项式: c ( x ) = 0 x 03 ⋅ x 3 + 0 x 01 ⋅ x 2 + 0 x 01 ⋅ x + 0 x 02 c(x) = 0\mathrm{x}03 \cdot x^3 + 0\mathrm{x}01 \cdot x^2 + 0\mathrm{x}01 \cdot x + 0\mathrm{x}02 c(x)=0x03⋅x3+0x01⋅x2+0x01⋅x+0x02模 x 4 + 1 x^4+1 x4+1 。矩阵表示如下:
s 0 , j ′ s 1 , j ′ s 2 , j ′ s 3 , j ′ = 02 03 01 01 01 02 03 01 01 01 02 03 03 01 01 02 ⋅ s 0 , j s 1 , j s 2 , j s 3 , j \begin{bmatrix}s _ { 0 , j } ^ { \prime } \\ s _ { 1 , j } ^ { \prime } \\ s _ { 2 , j } ^ { \prime } \\ s _ { 3 , j } ^ { \prime } \\ \end{bmatrix}= \begin{bmatrix} 0 2 & 0 3 & 0 1 & 0 1 \\ 0 1 & 0 2 & 0 3 & 0 1 \\ 0 1 & 0 1 & 0 2 & 0 3 \\ 0 3 & 0 1 & 0 1 & 0 2 \end{bmatrix} \cdot \begin{bmatrix} s _ { 0 , j } \\ s _ { 1 , j } \\ s _ { 2 , j } \\ s _ { 3 , j } \end{bmatrix} s0,j′s1,j′s2,j′s3,j′ = 02010103030201010103020101010302 ⋅ s0,js1,js2,js3,j
其中乘法与加法均在 G F ( 2 8 ) GF(2^8) GF(28) 中进行。
注意:最后一轮没有MixColumns,以保证加解密结构对称。
2.4 AddRoundKey(轮密钥加)
将状态矩阵与当前轮的轮密钥 (128位)逐字节进行 X O R XOR XOR 运算。轮密钥由原始密钥通过密钥扩展算法生成。
3 密钥扩展(Key Schedule)
对于AES-128,原始密钥16字节被扩展为 11 × 128 11×128 11×128 位的轮密钥(第0轮到第10轮)。扩展过程使用字(Word,4字节)为单位:
- 将原始密钥分为4个字: W 0 , W 1 , W 2 , W 3 W0,W1,W2,W3 W0,W1,W2,W3。
- 对于 i = 4 i=4 i=4 到 43 43 43
- 若 i m o d 4 ≠ 0 : W i = W i − 4 ⊕ W i − 1 i \mod 4 \neq 0: Wi = Wi - 4 \oplus Wi - 1 imod4=0:Wi=Wi−4⊕Wi−1
- 若 i m o d 4 = 0 : i \mod 4 = 0: imod4=0:
- 循环左移 W i − 1 Wi−1 Wi−1 的4个字节
- 对每个字节应用S-box(SubWord)
- 与轮常数
Rcon[i/4]异或(轮常数是 G F ( 2 8 ) GF(2 ^8) GF(28) 中 x i / 4 − 1 x^{i/4-1} xi/4−1 的值,如0x01, 0x02, 0x04, 0x08, 0x10, ...) - 最后与 W i − 4 Wi−4 Wi−4 异或得到 W i Wi Wi
AES-192和AES-256的扩展类似,但轮常数和更新规则略有不同。
4 加解密流程
4.1加密
1. 初始 AddRoundKey(State, RoundKey[0])
2. 对 round = 1 到 N_r - 1:
SubBytes(State)
ShiftRows(State)
MixColumns(State)
AddRoundKey(State, RoundKey[round])
3. 最后一轮:
SubBytes(State)
ShiftRows(State)
AddRoundKey(State, RoundKey[N_r])
4.2 解密
所有操作都是逆变换,注意顺序相反:
InvSubBytes(使用逆S-box)
InvShiftRows(循环右移)
InvMixColumns(乘矩阵的逆)
AddRoundKey(因为XOR是对合,所以相同)
5 分组密码工作模式
| 模式 | 并行性 | 错误传播 | 特点 |
|---|---|---|---|
| ECB | 完全并行 | 块内 | 不安全,相同明文块产生相同密文块 |
| CBC | 解密并行,加密串行 | 影响两个块 | 需要随机IV,经典但不可并行加密 |
| CTR | 完全并行 | 无 | 将块密码变为流密码,简单高效 |
| GCM | 完全并行 | 无 | 认证加密(AEAD),同时提供机密性和完整性 |
三、RSA加密算法
1977年,三位麻省理工学院的科学家 Ron R ivest、Adi S hamir 和 Len Adleman 发表了一篇论文《A Method for Obtaining Digital Signatures and Public-Key Cryptosystems》,提出了基于大整数因数分解困难性的公钥加密算法。RSA之名取自他们姓氏的首字母。RSA的核心理念是:加密密钥(公钥)可以公开,解密密钥(私钥)只能由接收方掌握。RSA的安全依赖于一个数学事实:
两个大素数的乘积很容易计算,但反过来分解该乘积极其困难。
1 数学基础
1.1 预备知识
- 模运算: a ≡ b ( m o d n ) a \equiv b \pmod{n} a≡b(modn) 表示 n n n 整除 a − b a - b a−b。
- 欧拉函数 φ ( n ) \varphi(n) φ(n):小于等于 n n n 且与 n n n 互质的正整数的个数。对两个不同素数 p p p 和 q q q, φ ( p q ) = ( p − 1 ) ( q − 1 ) \varphi(pq)=(p-1)(q-1) φ(pq)=(p−1)(q−1)。
- 欧拉定理: 若 gcd ( a , n ) = 1 \gcd(a,n)=1 gcd(a,n)=1, 则 a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1 \pmod{n} aφ(n)≡1(modn)。
1.2 密钥生成
- 随机选择两个大素数 p p p 和 q q q (例如512位以上,实际推荐2048位)。
- 计算 n = p × q n = p \times q n=p×q, n n n 的二进制长度就是密钥长度。
- 计算 φ ( n ) = ( p − 1 ) ( q − 1 ) \varphi(n) = (p - 1)(q - 1) φ(n)=(p−1)(q−1)。
- 选一个整数 e e e,满足 1 < e < φ ( n ) 1 < e < \varphi(n) 1<e<φ(n) 且 gcd ( e , φ ( n ) ) = 1 \gcd(e, \varphi(n)) = 1 gcd(e,φ(n))=1。常用的 e e e 是 65537 ( 2 16 + 1 ) (2^{16}+1) (216+1),因其为素数且二进制表示只有两个1,加密运算速度快。
- 计算 e e e 模 φ ( n ) \varphi(n) φ(n) 的模逆 d d d,即 e × d ≡ 1 ( m o d φ ( n ) ) e \times d \equiv 1 \pmod{\varphi(n)} e×d≡1(modφ(n))。可用扩展欧几里得算法求解。
公钥: ( n , e ) (n, e) (n,e)
私钥: ( n , d ) (n, d) (n,d)
1.3 加密与解密
- 加密:对明文 m m m(视为整数,且 0 ≤ m < n 0 \le m < n 0≤m<n),计算密文: c = m e m o d n c = m^e \bmod n c=memodn
- 解密:对密文 c c c,计算: m = c d m o d n m = c^d \bmod n m=cdmodn
为什么解密能恢复明文?因为:
c d ≡ ( m e ) d = m e d ≡ m k φ ( n ) + 1 ≡ m ⋅ ( m φ ( n ) ) k ≡ m ⋅ 1 k = m ( m o d n ) c^d \equiv (m^e)^d = m^{ed} \equiv m^{k\varphi(n)+1} \equiv m \cdot (m^{\varphi(n)})^k \equiv m \cdot 1^k = m \pmod n cd≡(me)d=med≡mkφ(n)+1≡m⋅(mφ(n))k≡m⋅1k=m(modn)中间用到了欧拉定理(当 gcd ( m , n ) = 1 \gcd(m,n) = 1 gcd(m,n)=1 时)。对于 m m m 与 n n n 不互质的极罕见情况,由 p p p、 q q q 为素数也可证明成立。
1.4 数值示例
- 选 p = 61 p=61 p=61, q = 53 q=53 q=53
则 n = 61 × 53 = 3233 n=61 \times 53=3233 n=61×53=3233
φ ( n ) = ( p − 1 ) × ( q − 1 ) = 60 × 52 = 3120 \varphi(n)=(p-1) \times (q-1) = 60 \times 52=3120 φ(n)=(p−1)×(q−1)=60×52=3120 - 选 e = 17 e=17 e=17 (与3120互质)
计算 d = e − 1 m o d φ ( n ) = 17 − 1 m o d 3120 = 2753 d=e^{-1} \bmod \varphi(n)=17^{-1}\bmod3120=2753 d=e−1modφ(n)=17−1mod3120=2753
(因为 17 × 2753 = 46801 = 15 × 3120 + 1 17 \times 2753=46801=15 \times 3120+1 17×2753=46801=15×3120+1 ) - 公钥 ( n , e ) = ( 3233 , 17 ) (n,e)=(3233,17) (n,e)=(3233,17)
私钥 ( n , d ) = ( 3233 , 2753 ) (n,d)=(3233,2753) (n,d)=(3233,2753) - 加密明文 m = 65 m=65 m=65: c = m e m o d n = 65 17 m o d 3233 = 2790 c=m^e\bmod n=65^{17} \bmod 3233=2790 c=memodn=6517mod3233=2790
- 解密: c m o d n = 2790 2753 m o d 3233 = 65 c \bmod n = 2790^{2753} \bmod 3233=65 cmodn=27902753mod3233=65
1.5 中国剩余定理 (CRT) 加速
解密时,私钥持有者知道 p p p 和 q q q,可以分别计算 c d m o d p c^d \bmod p cdmodp 和 c d m o d q c^d \bmod q cdmodq,再用 CRT 组合结果。这样速度提升约4倍。存储私钥时通常包含
p , q p, q p,q,
d P = d m o d ( p − 1 ) dP = d \bmod (p - 1) dP=dmod(p−1),
d Q = d m o d ( q − 1 ) dQ = d \bmod (q - 1) dQ=dmod(q−1),
q I n v = q − 1 m o d p qInv = q^{-1} \bmod p qInv=q−1modp。
攻击方式
1 破解模数n(已知 n, e, c,分解 n 求 p, q)
按照上述数值示例解题即可
python
import gmpy2
from Crypto.Util.number import long_to_bytes
n_hex = "0x...";
e_hex = "0x10001"; #65537
c_hex = "0x..."
n = int(n_hex, 16);
e = int(e_hex, 16);
c = int(c_hex, 16)
# 方式1: 使用 factordb 或 sympy(需安装)
from sympy import factorint
factors = factorint(n)
p, q = sorted(factors.keys()) # p, q 为素数
# 方式2: 手动试除(仅当 n 很小)
# for i in range(2, 100000):
# if n % i == 0:
# p, q = i, n // i
# break
phi = (p-1)*(q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
2 共模攻击(相同 n,不同 e1, e2)
已知e1,e2,c1,c2,n,求解m(不需要知道对应的d1,d2)
原理:
同一明文 m m m,用两个互质的公钥指数 e 1 , e 2 e_1, e_2 e1,e2 加密得 c 1 , c 2 c_1, c_2 c1,c2。若 g c d ( e 1 , e 2 ) = 1 gcd(e_1, e_2)=1 gcd(e1,e2)=1,则可利用扩展欧几里得算法找到 x , y x, y x,y 使得 e 1 x + e 2 y = 1 e_1x + e_2y = 1 e1x+e2y=1,进而:
m = ( c 1 x × c 2 y ) m o d n m = (c_1^x \times c_2^y) \bmod n m=(c1x×c2y)modn(注意 x , y x, y x,y 可能为负,用模逆处理)。
适用条件: e 1 , e 2 e_1, e_2 e1,e2 互质,且 n n n 相同。
步骤:
- 计算 gcd(e1, e2) 应为 1。
- 扩展欧几里得求 s, t 使 e1s + e2t = 1。
- 若 s < 0,则 c1 = gmpy2.invert(c1, n),取 s = -s;同理处理 t。
- m = pow(c1, s, n) * pow(c2, t, n) % n。
python
import gmpy2
n_hex = "0x...";
e1_hex = "0x...";
e2_hex = "0x..."
c1_hex = "0x...";
c2_hex = "0x..."
n = int(n_hex, 16);
e1 = int(e1_hex, 16);
e2 = int(e2_hex, 16)
c1 = int(c1_hex, 16);
c2 = int(c2_hex, 16)
g, s, t = gmpy2.gcdext(e1, e2) # g = e1*s + e2*t
assert g == 1
if s < 0:
c1 = gmpy2.invert(c1, n)
s = -s
if t < 0:
c2 = gmpy2.invert(c2, n)
t = -t
m = pow(c1, s, n) * pow(c2, t, n) % n
print(long_to_bytes(m))
3 模不互素(多个 n 共享素数)
原理:
若两个模数 n 1 , n 2 n_1, n_2 n1,n2 有公共素数因子(即 g c d ( n 1 , n 2 ) > 1 gcd(n_1, n_2) > 1 gcd(n1,n2)>1),则可分解它们。通常用于给定多个 n n n 中某两个不互素。
适用条件:至少两个 n n n,计算 g = g c d ( n 1 , n 2 ) g = gcd(n_1, n_2) g=gcd(n1,n2),若 1 < g < n 1 1 < g < n_1 1<g<n1,则 g g g 为素数因子。
步骤:
- 对每一对 ( n i , n j ) (n_i, n_j) (ni,nj) 计算 g c d gcd gcd,找到公共因子 p p p。
- 则 q i = n i / / p q_i = n_i // p qi=ni//p, q j = n j / / p q_j = n_j // p qj=nj//p。
- 解密对应的密文(需知道对应 e e e 和 c c c)。
python
from math import gcd
n1_hex = "0x...";
n2_hex = "0x..."
n1 = int(n1_hex, 16);
n2 = int(n2_hex, 16)
p = gcd(n1, n2)
assert p > 1 and p < n1
q1 = n1 // p
q2 = n2 // p
print(f"p = {p}, q1 = {q1}, q2 = {q2}")
4 e = 2, 4, 8 ...(低加密指数,但 e 为偶数时的 Rabin 密码)
适用条件: e = 2 k e = 2^k e=2k,且 n n n 为两个素数乘积。
步骤 (以 e = 2 e=2 e=2为例):
求 c c c 模 n n n 的平方根,即解 x 2 ≡ c m o d n x^2 ≡ c \bmod n x2≡cmodn。
利用 p , q p,q p,q 分别求平方根后 C R T CRT CRT 组合得到四个根。
选择可读的那一个。
python
import gmpy2
c = int(c_hex, 16)
# 假设已分解得到 p, q
p, q = ...
n = p * q
# 模 p 平方根
def sqrt_mod(a, p):
return gmpy2.powmod(a, (p+1)//4, p) # p ≡ 3 mod 4 时成立
# 若 p ≡ 3 mod 4
rp = sqrt_mod(c, p)
rq = sqrt_mod(c, q)
# 中国剩余定理组合四个根
from Crypto.Util.number import long_to_bytes
for sign_p in (rp, p - rp):
for sign_q in (rq, q - rq):
m = gmpy2.crt([sign_p, sign_q], [p, q])[0]
# 尝试转为字符串
try:
print(long_to_bytes(m))
except:
pass
若 p ≡ 1 m o d 4 p ≡ 1 \bmod 4 p≡1mod4,需用
Tonelli-Shanks算法求平方根(使用gmpy2.sqrtmod或sympy.ntheory.sqrt_mod)。
5 e = 3, 5, 7 ...(低加密指数小明文攻击)
原理:
若 m e < n m^e < n me<n,则 c = m e c = m^e c=me 直接开 e e e 次方即可得 m m m。即使 m e m^e me 略大于 n n n,也可通过添加 k × n k \times n k×n 并开方爆破 k k k(Coppersmith 攻击)。
适用条件:e 很小(3,5,7 常见),且 m 足够小(或知道部分明文格式)。
步骤:
计算 m = gmpy2.iroot(c, e),若能开整数根则直接得到。
否则,枚举 k = 0,1,2,... 计算 (c + k*n) 的 e 次根,直到得到整数。
python
import gmpy2
e = 3
c = int(c_hex, 16)
n = int(n_hex, 16)
for k in range(100000):
m, exact = gmpy2.iroot(c + k * n, e)
if exact:
print(long_to_bytes(m))
break
6 d泄漏攻击(已知 d, n, e, c)
一般是已知私钥d的16进制字符串,需要处理
python
n_hex = "0x...";
d_hex = "0x...";
c_hex = "0x..."
n = int(n_hex, 16);
d = int(d_hex, 16);
c = int(c_hex, 16)
m = pow(c, d, n)
print(long_to_bytes(m))
7 dp和dq泄漏(已知 p, q, dp, dq, c,求解 mp,mq,InvQ,m)
原理:
d p = d m o d ( p − 1 ) dp = d \bmod (p-1) dp=dmod(p−1)
d q = d m o d ( q − 1 ) dq = d \bmod (q-1) dq=dmod(q−1)
利用它们可以避免直接求 d,而通过 CRT 计算 m m o d p m \bmod p mmodp 和 m m o d q m \bmod q mmodq 再组合。
步骤:
1. 计算 mp = pow(c, dp, p),mq = pow(c, dq, q)。
2. 计算 q_inv = gmpy2.invert(q, p)(或 p_inv)。
3. 利用 CRT:m = mp + p * ((mq - mp) * q_inv % q)。
python
import gmpy2
from Crypto.Util.number import long_to_bytes
p_hex = "0x...";
q_hex = "0x..."
dp_hex = "0x...";
dq_hex = "0x...";
c_hex = "0x..."
p = int(p_hex, 16);
q = int(q_hex, 16)
dp = int(dp_hex, 16);
dq = int(dq_hex, 16)
c = int(c_hex, 16)
mp = pow(c, dp, p)
mq = pow(c, dq, q)
q_inv = gmpy2.invert(q, p) # 实际上标准 CRT 用 m = mp + p * ((mq - mp) * q_inv % q)
# 更稳健的公式:
m = (mp + p * ((mq - mp) * gmpy2.invert(p, q) % q)) % (p * q)
# 或者使用 gmpy2.crt
# m = gmpy2.crt([mp, mq], [p, q])[0]
print(long_to_bytes(m))