CTF-Crypto培训笔记-现代密码

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 加解密流程)
    • [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结构如下:

  1. 初始置换(IP):对64位明文进行固定比特重排。
  2. 16轮迭代:每轮使用不同的48位子密钥 K i K_i Ki
  3. 左右交换:第16轮输出后,交换左右两半。
  4. 逆初始置换(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位子密钥。过程如下:

  1. 初始64位密钥(含8位奇偶校验)经过置换选择PC-1,去掉校验位并重排,得到56位 C 0 C_0 C0 和 D 0 D_0 D0(各28位)。
  2. 对 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 密钥生成

  1. 随机选择两个大素数 p p p 和 q q q (例如512位以上,实际推荐2048位)。
  2. 计算 n = p × q n = p \times q n=p×q, n n n 的二进制长度就是密钥长度。
  3. 计算 φ ( n ) = ( p − 1 ) ( q − 1 ) \varphi(n) = (p - 1)(q - 1) φ(n)=(p−1)(q−1)。
  4. 选一个整数 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,加密运算速度快。
  5. 计算 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 数值示例

  1. 选 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
  2. 选 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 )
  3. 公钥 ( n , e ) = ( 3233 , 17 ) (n,e)=(3233,17) (n,e)=(3233,17)
    私钥 ( n , d ) = ( 3233 , 2753 ) (n,d)=(3233,2753) (n,d)=(3233,2753)
  4. 加密明文 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
  5. 解密: 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 相同。

步骤:

  1. 计算 gcd(e1, e2) 应为 1。
  2. 扩展欧几里得求 s, t 使 e1s + e2t = 1。
  3. 若 s < 0,则 c1 = gmpy2.invert(c1, n),取 s = -s;同理处理 t。
  4. 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 为素数因子。

步骤:

  1. 对每一对 ( n i , n j ) (n_i, n_j) (ni,nj) 计算 g c d gcd gcd,找到公共因子 p p p。
  2. 则 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。
  3. 解密对应的密文(需知道对应 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.sqrtmodsympy.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))
相关推荐
IT技术学习1 小时前
打包系统为ISO
笔记
就叫飞六吧2 小时前
数学图形绘制在线网站
笔记
SHARK_pssm2 小时前
【数据结构——树与堆】
c语言·数据结构·经验分享·笔记
怪味&先森3 小时前
读书小结—《认知觉醒》
笔记
杨先生哦3 小时前
2026 热端攻防:AI 驱动 Web 前端安全全景透析
前端·笔记·安全·web安全
Cloud_Shy6184 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第七章 Item 48 - 50)
开发语言·人工智能·笔记·python·microsoft·学习方法
yang)5 小时前
jesd204B应用笔记
网络·笔记
三品吉他手会点灯5 小时前
STM32F103 学习笔记-24-I2C-读写EEPROM(第2节)-I2C协议层介绍
笔记·stm32·学习
三品吉他手会点灯6 小时前
STM32F103 学习笔记-24-I2C-读写EEPROM(第3节)-STM32的I2C框图详解
笔记·stm32·学习