一、数论基础
1 欧拉定理
a^φ(n) ≡ 1 (mod n)
这个解释一下 ≡ 符号的含义
17≡5(mod12)
表明17和5除以12的余数相同
17 ÷ 12 = 1 余 5
5 ÷ 12 = 0 余 5
余数一样,所以同余
φ(n) 就是 1 到 n-1 中与 n 互质的整数个数
比如n =12 ,则 1 到 n-1 中与 n 互质的数有 1 5 7 11
所以 φ(n)=4
欧拉定理:
定理:若 gcd(a, n) = 1,则 a^φ(n) ≡ 1 (mod n)。
想了想还是觉得直接带入数容易理解
a=7 n=12
φ(12)=4
a^φ(n)=2401
a^φ(n) mod n = 1
所以欧拉定理验证:
7^4 mod 12 = 1 = 1
φ(12)=4
gcd(7,12)=1
定理成立
从欧拉定理到 RSA:完整的数学推导
RSA 的正确性就是一句话:加密后解密能还原明文
即
(m^e)^d ≡ m (mod n)
分析RSA:
n = p×q(p,q 为不同质数),
φ(n) = (p-1)(q-1),
ed ≡ 1 (mod φ(n))
即存在整数 k,使得 ed = 1 + k·φ(n)
对任意明文 m(gcd(m,n)=1),有 m^(ed) ≡ m (mod n),意味着加密后再解密,能完整还原原始信息
带入数分析
p=11 q=13 e=7
明文 m = 5
密钥生成
n = 11×13 = 143
φ(n) = (11-1)×(13-1) = 10×12 = 120
e = 7(公钥指数,gcd(7,120)=1 )
d = e⁻¹ mod φ(n) = 103(私钥,由扩展欧几里得求得)
验证:e×d = 7×103 = 721 = 1 + 6×120 ✓
这里补充一下模逆元知识,在rsa中经常用到
7⁻¹ mod 120
意思是可以设一个未知数下x 7x ≡ 1(mod120)
要求 7x+120y=1
由欧几里得算法得到
1=(−17)⋅7+1⋅120
7x+120y=1
所以x = -17
转成正数(模运算标准写法)
−17mod120=103
加密过程
c = m^e mod n = 5^7 mod 143 = 47
解密过程
m' = c^d mod n = 47^103 mod 143 = 5
2 费马小定理
费马小定理和 Miller-Rabin 是密码学里质数生成的核心工具------RSA 需要生成两个大质数,而验证一个 1024 位的数是否为质数,靠的就是 Miller-Rabin。
费马小定理
定理内容:若 p 是质数,且 gcd(a, p) = 1,则 a^(p-1) ≡ 1 (mod p)。
a=3 p=7
p=7 是质数,所有底数的 a^(p-1) ≡ 1 (mod p),定理完全成立。
费马测试的缺陷:Carmichael 数
费马测试的逻辑是:如果 a^(p-1) mod p ≠ 1,则 p 必然是合数,但反过来不成立
有极少数合数(Carmichael 数,如 561、1105、1729)对所有与它互质的底数都满足 a^(p-1) ≡ 1,费马测试完全看不穿它们。
Miller-Rabin 就是为了解决这个漏洞而设计的。
Miller-Rabin 算法
核心思路:把 p-1 写成 2^s × d(d 是奇数),然后不只检验最终结果,而是检验整个"平方根链"的行为。
若 p 是质数,则 x² ≡ 1 (mod p) 的解只有 x ≡ ±1。所以在反复平方的过程中,如果哪一步突然从"非 ±1"跳到了 1,那 p 必然是合数。
n=561
底数a = 2,3,5
第一步:将 n-1 分解为 2^s × d
n-1 = 560 = 2^4 × 35 s = 4,d = 35(d 是奇数) 检测链长度:4 步平方
逐轮检测(每个底数一轮)
底数 a = 2 合数!
263→166→67→1
平方后出现 1,但前一个值不是 ±1 → 合数
底数 a = 3 合数!
78→474→276→441
所有平方均未出现 n-1 → 合数
底数 a = 5 合数!
23→529→463→67
所有平方均未出现 n-1 → 合数
n = 561(Carmichael 数):费马测试的死穴,但 Miller-Rabin 用底数 2 仍能检出
在 RSA 密钥生成中的实际用法
RSA 需要生成两个大质数 p 和 q(各约 1024 位)。
实际流程是:随机生成一个奇数 → 用 Miller-Rabin 测试 → 通过则使用,否则换下一个候选数。
3 中国剩余定理(CRT)
CRT 是密码学里少见的"既有理论美感、又有工程价值"的定理。我们先从直觉出发,再走一遍完整的数学机制,最后看它如何让 RSA 解密快 4 倍。
直觉:用多个"余数指纹"唯一定位一个数
想象你要在 1 到 105 之间猜一个数,我只告诉你三个线索:它除以 3 余 2,除以 5 余 3,除以 7 余 2。CRT 说:这三条线索足以唯一确定这个数。
则 x = 23
CRT 的构造公式分四步。
1 计算乘积 N = n₁ × n₂ × n₃
N = 3 × 5 × 7 = 105
N 是解存在的范围,唯一解 x ∈ [0, 105)
2 计算各 Nᵢ = N / nᵢ(去掉第 i 个模数后的乘积)
3 35 105÷3=35,被 n₂n₃ 整除
5 21 105÷5=21,被 n₁n₃ 整除
7 15 105÷7=15,被 n₁n₂ 整除
3 用扩展欧几里得算法求各 yᵢ = Nᵢ⁻¹ mod nᵢ
35⁻¹ mod 3 2
21⁻¹ mod 5 1
15⁻¹ mod 7 1
4 合并:x = Σ rᵢ · Nᵢ · yᵢ (mod N)
x = 2×35×2 + 3×21×1 + 2×15×1 mod 105
= 140 + 63 + 30 mod 105
= 233 mod 105
= 23
唯一性:在 [0, 105) 内只有 x=23 同时满足三个方程,这是 CRT 的核心保证。
RSA-CRT 加速解密
标准 RSA 解密是一次 m = c^d mod n 的大模幂运算,n 是 2048 位。RSA-CRT 把它拆成两个 1024 位的小模幂,再用 CRT 拼回来。
p=61 q=53 e=17 明文m=65
密钥生成
n = 61 × 53 = 3233
φ(n) = (61-1)(53-1) = 3120
公钥 e = 17(gcd(17,3120)=1 )
私钥 d = 17⁻¹ mod 3120 = 2753(扩展欧几里得)
加密:c = 65^17 mod 3233 = 2790
原始解密
m = c^d mod n
m = 2790^2753 mod 3233
m = 65
CRT 加速解密
d_p = d mod(p-1) = 2753 mod 60 = 53
d_q = d mod(q-1) = 2753 mod 52 = 49
m_p = c^d_p mod p = 2790^53 mod 61 = 4
m_q = c^d_q mod q = 2790^49 mod 53 = 12
q⁻¹ mod p = 53⁻¹ mod 61 = 38
h = 38×(4-12) mod 61 = 1
m = 12 + 1×53 = 65
二、古典密码和基础密码学
1 base家族编码:
base16 / base32 / base64 / base58 / base85 / base 100
简述:
● Base16编码是将二进制文件转换成由16个字符组成的文本。
● base32的编码表是由(A-Z、2-7)32个可见字符构成,"="符号用作后缀填充。
● base64的编码表是由(A-Z、a-z、0-9、+、/)64个可见字符构成,"="符号用作后缀填充。
● base58的编码表相比base64少了数字0,大写字母I,O,小写字母 l (这个是L),以及符号'+'和'/'。
● base91的密文由91个字符(0-9,a-z,A-Z,!#$%&()*+,./:;<=>?@[]^_`{|}~")组成。
● Base100编码/解码工具(又名:Emoji表情符号编码/解码),可将文本内容编码为Emoji表情符号;同时也可以将编码后的Emoji表情符号内容解码为文本。
举例:
base32: NBSWY3DPFR3W64TMMQXDCMRTGQ3DK===
特征:大写字母(A-Z)和数字(2-7),不满5的倍数,用'='补齐。
base64: aGVsbG8sd29ybGQuMTIzNDY1
特征:大小写字母(A-Z,a-z)和数字(0-9)以及特殊字符'+','/',不满3的倍数,用'='补齐。
base58: 2smDFYXWKE8vc8XA8dadEYcSqcQb
特征:相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及"+"和"/"符号,最主要的是后面不会出现'='。
base85: BOu!rDst>tGAhM<A1fSl1GgsI
特征:特点是奇怪的字符比较多,但是很难出现等号。
base91: TPwJh>go2Tv!_,aRA2IbLmA
特征:由91个字符(0-9,a-z,A-Z,!#$%&()*+,./:;<=>?@[]^_`{|}~")组成 不支持中文。
base100: 👟👜👣👣👦📦💳💃👮👦👩👣👛🐥🐨🐩🐪🐫🐬🐭
特征:就是一堆Emoji表情
Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(38 = 46 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
例如:ABC
ASCII:
字符 ASCII 二进制
A 65 01000001
B 66 01000010
C 67 01000011
合并:
01000001 01000010 01000011
共 24 bit
每6位一组
010000 010100 001001 000011
得到 4组 × 6bit
6bit 最大值:2的6次方=64
所以需要64个字符
值 字符
0--25 A--Z
26--51 a--z
52--61 0--9
62 +
63 /
编码结果: ABC → QUJD
2 rabbit密码
Rabbit 是流密码,它不直接加密数据块,而是生成一条伪随机"密钥流",再与明文逐位 XOR 得到密文。解密时用同样的密钥流再 XOR 一次,就能还原明文------这正是流密码天然对称的特点。
由字母、数字和 +/= 构成,无规律可循
密文:U2FsdGVkX1/ATQxwhmM3vC9wXWeQlWDMPFMhGHE+eNE8a1r0AUKbUkjpbfHT3Td/
iD4Wl8wirAgGtw==
密钥:key
解密后 flag{3becfe0b-8b41-54e4-2b21-5d0d95b22845}
3 栅栏密码
栅栏密码是一种简单的移动字符位置的加密方法,规则简单,容易破解。栅栏密码的加密方式:把文本按照一定的字数分成多个组,取每组第一个字连起来得到密文1,再取每组第二个字连起来得到密文2......最后把密文1、密文2......连成整段密文.
举例:
helloworld 栏数:2
hloolelwrd
4 凯撒密码
通过把字母移动一定的位数来实现加密和解密。明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。
例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推X将变成A,Y变成B,Z变成C。由此可见,位数就是凯撒密码加密和解密的密钥
5 对称加密
AES算法原理
AES(Advanced Encryption Standard,高级加密标准)是一种对称加密算法,意思是加密和解密用的是同一把密钥。它是目前最广泛使用的加密标准,安全、高效。
比如你有一个保险柜,用钥匙锁上(加密),用同一把钥匙打开(解密)
核心概念:三个关键参数
● 明文:你要加密的原始数据
● 密钥:加密/解密用的"钥匙",长度可以是 128/192/256 位
● 密文:加密后的数据
加密过程
AES 以 16字节(128位)为一个"块" 来处理数据,这个块叫做State(状态矩阵)。

AES-128 会进行 10轮迭代,每轮包含四个操作:

四个核心操作详解
- SubBytes(字节替换)
每个字节通过查一张叫 S-Box 的固定替换表,换成另一个字节。这一步提供"混淆"效果,破坏字节之间的线性关系。 - ShiftRows(行移位)
矩阵的每一行向左循环移位:
● 第0行:不动
● 第1行:左移1字节
● 第2行:左移2字节
● 第3行:左移3字节
这一步让数据在矩阵的不同列之间"扩散"。

- MixColumns(列混淆)
每一列的4个字节与一个固定矩阵在有限域(GF(2⁸))中做乘法运算。这一步让一个字节的变化影响整列,提供最强的"扩散"效果。最终轮跳过这一步。 - AddRoundKey(轮密钥加)
State 矩阵与该轮的子密钥做按位 XOR。子密钥由初始密钥通过**密钥扩展算法(Key Expansion)**生成,AES-128 会生成 11 个子密钥(初始1个 + 每轮1个)。
解密过程
解密就是把加密每一步反过来做:
加密步骤 解密步骤
SubBytes InvSubBytes(逆S-Box查表)
ShiftRows InvShiftRows(循环右移)
MixColumns InvMixColumns(逆矩阵乘法)
AddRoundKey AddRoundKey(XOR自身可逆)
轮次顺序也是反过来执行的。
例题:
密文: 7a2f1b3c8e4d9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
key: MySuperSecretKey
python
from Crypto.Cipher import AES
key = b'MySuperSecretKey'
ciphertext = bytes.fromhex(
'7a2f1b3c8e4d9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4'
)
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
# 去除 PKCS#7 填充
pad_len = plaintext[-1]
flag = plaintext[:-pad_len]
print(flag.decode()) # flag{AES_ECB_1s_W3ak!}
6 非对称加密
RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。
RSA算法原理:
算法基础 - 数论知识
● 互质关系:如果两个正整数,除了 1 以外,没有其他公因数,那么这两个数是互质关系。例如,15 和 8 是互质的,因为 15 的因数是 1、3、5、15,8 的因数是 1、2、4、8,它们只有公因数 1。
● 欧拉函数:对于正整数n,欧拉函数φ(n)表示小于等于n且与n互质的正整数的个数。例如,当n = 6 时,与 6 互质的数有 1 和 5,所以φ(6) = 2。
● 如果n是质数p,那么φ§ = p -1,因为所有小于p的正整数都与p互质。
● 模运算:模运算即求余数的运算。例如,7 mod 3 = 1,表示 7 除以 3 的余数是 1。在 RSA 算法中,模运算起到了关键作用,许多运算都是在模某个数的环境下进行的。
● 费马小定理和欧拉定理
○ 费马小定理:假如p是质数,且a与p互质,那么a^p-1 mod p = 1。例如,当p = 5,a = 3时,3^4 mod 5 = 81 mod 5 = 1。
■ 欧拉定理:若a与n互质,则a^φ(n) mod n = 1。它是费马小定理的推广,当n为质数时, φ(n) = n - 1,就退化成费马小定理。
密钥生成过程
● 步骤一:选择两个大质数p和q
○ 这两个质数要足够大,例如可以选择p = 61,q = 53。大质数的选择是为了增加破解的难度,因为分解两个大质数的乘积是非常困难的计算问题。
● 步骤二:计算n = p × q和φ(n)
φ(n) = φ(p) × φ(q) = (p - 1) × (q - 1)
对于前面所选的p = 61和q = 53,n = 61 × 53 = 3233,φ(n) = (61 - 1) × (53 - 1) = 60 × 52 = 3120。
步骤三:选择一个整数e,使得1 < e < φ (n)且e与 φ(n)互质
通常选择一个较小的质数作为e,比如e = 17,因为17与3120互质,满足条件。这个e就是公钥的一部分。
步骤四:计算d,使得e × d mod φ(n),即d是e在模 φ(n)下的乘法逆元
可以使用扩展欧几里得算法来计算d。对于e = 17和φ(n) = 3120,通过计算得到d = 2753。这个就是私钥的一部分。
最终密钥:公钥是(e,n),即(17,3233);私钥是(d,n),即(2753,3233)。
加密过程
● 假设要加密的消息是m(必须是小于n的整数),例如m = 123。使用公钥(e,n)进行加密,加密公式为c = m^e mod n。
● 对于e = 17,n = 3233,m = 123,计算c = 123^17 mod 3233。通过计算得到c = 855,这就是加密后的密文。
解密过程
● 使用私钥(d,n)对密文c进行解密,解密公式为m = c^d mod n。
● 对于前面得到的c = 855,d = 2753,n = 3233,计算m = 855^2753 mod 3233,经过计算可以得到m = 123,即还原出了原始消息。
例题:
p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483
q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407
e = 65537
c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034
已知p、q、e、c 求m:解题流程如下:
- 计算φ(n)=(p-1)(q-1)
- 求d ≡ e⁻¹ mod φ(n)
- 解密m ≡ cᵈ mod n
python
from Crypto.Util.number import long_to_bytes
p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483
q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407
e = 65537
c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034
phi = (p-1)*(q-1)
d = pow(e, -1, phi)
m = pow(c, d, p*q)
print(long_to_bytes(m))
离散对数与 Diffie-Hellman (DH)
离散对数问题是许多加密协议(如 DH 密钥交换)的基础。它利用了幂运算在模运算下的"混乱"特性。
正向计算简单,逆向求解极难
想象一个公式:g^a mod p = A。其中g、p是公开的大素数,a是 Alice 自己选的秘密数。已知g、p、a 求公开值A(公钥)很容易(指数运算后取模)。但攻击者即使截获了公开的g、p、A,想反过来求出秘密数a,在现有计算能力下几乎不可能,这就是离散对数难题。
DH协议的安全就基于此:秘密(a, b)不传输,只交换公开计算结果(A, B),最终双方能独立算出相同的共享密钥 K = B^a mod p = A^b mod p,而旁观者无法算出K。
DH密钥交换就像两个人在公开场合通过"颜色混合"的比喻约定一个秘密颜色。其标准化操作分为四步:
1 协商公开参数:双方选定一个大素数 p 和一个生成元 g。这两个数公开传输,毫无保密必要。
2 生成各自密钥对:Alice随机选私钥 a,计算公钥 A = g^a mod p;Bob随机选私钥 b,计算公钥 B = g^b mod p。私钥a/b必须绝对保密。
3 交换公钥:Alice将A发送给Bob,Bob将B发送给Alice。这个过程可以被任何人监听。
4 计算共享密钥:Alice收到B后,用自己私钥a计算 K = B^a mod p;Bob收到A后,用自己私钥b计算 K = A^b mod p。根据模幂运算定律,双方计算出的K是相同的,即 g^(a*b) mod p。
核心要点:整个过程中,网络上只流动了 p, g, A, B 四个公开数,秘密的 a, b, K 从未出现。攻击者由公开信息推不出K。
椭圆曲线密码学 (ECC)
ECC 是目前主流的加密标准(如比特币、TLS 1.3)。它基于椭圆曲线离散对数问题 (ECDLP)。
核心原理
椭圆曲线通常表示为方程:y2=x3+ax+by^2 = x^3 + ax + by2=x3+ax+b。
在 ECC 中,我们不处理连续的曲线,而是处理有限域上的离散点。
1 点运算:在曲线上定义一种特殊的"加法"。给定点 P,计算 2P, 3P,...相当于在曲线上进行多次跳跃。
2 标量乘法:计算 Q = kP。
k 的特征它必须足够大:在 256 位加密中,kkk 的取值范围接近 22562^{256}2256(约等于宇宙中原子的数量)。如果 kkk 太小,别人很快就能暴力破解。
给定 k 和 P,计算 Q 很快。但给定 Q 和 P,想要反推 k 极其困难。
ECC在相同的安全强度下,ECC 所需的密钥长度远短于 RSA。256 位的 ECC 密钥安全性大致相当于 3072 位的 RSA 密钥。由于密钥短,计算量小,内存占用少,非常适合移动设备和物联网终端。
三、密码协议
密钥交换协议
在公开的互联网上,两个从未谋面的主体如何协商出一个只有他们知道的秘密?
1 Diffie-Hellman (DH):最经典的协议。双方交换公钥,结合各自的私钥,计算出相同的共享密钥。
2 完美前向安全性 (PFS):现代协议(如 TLS 1.3)强调 PFS。这意味着即使服务器的长期私钥在未来某天泄露,攻击者也无法解密过去已经结束的通信会话,因为每次会话的密钥都是临时生成的。
认证协议
认证协议用于确认"你确实是你所声称的那个人"。
挑战-响应机制:
1 服务器发送一个随机数。
2 用户用自己的私钥对该随机数签名并传回。
3 服务器用用户的公钥验签,成功则证明用户持有正确的私钥。
4 数字证书与 PKI:为了防止"中间人攻击",我们需要一个可信的第三方(CA)。CA 给用户的公钥签名。
零知识证明
它允许证明者在不向验证者透露任何有用信息的前提下,使验证者相信某个命题是正确的。
核心属性
完备性:如果是真的,证明者能说服验证者。
可靠性:如果是假的,证明者几乎不可能骗过验证者。
零知识性:验证者除了知道命题是真的以外,得不到任何其他信息。
在隐私币,区块链方面应用较多
安全多方计算
解决的是"协同计算但互不信任"的问题。它允许一组参与者共同计算一个函数的结果,同时保证各自的输入数据对他人不可见。
比如:两个富翁想知道谁更有钱,但谁都不想告诉对方自己到底有多少钱。
核心技术
1 秘密共享 (Secret Sharing):将数据拆成碎片,分给不同的人,只有凑齐足够多的碎片才能还原数据。
2 混淆电路 (Garbled Circuits):将计算逻辑加密,让参与者在看不见具体数值的情况下执行逻辑运算。
应用场景:隐私保护下的数据挖掘、多机构联合风控、分布式密钥管理。