[Crypto学习笔记] 格基规约类问题
发布时间:
目录
符号
向量长度
例如符号$$ | a | $$表示向量a的向量长度, 我们可以按以下方式进行求解: |
前置概念
rsa原理
从最基本的rsa开始, 标准题目中可以分解n为p, q构造phin获取私钥:
lll
定理11:
一组基B存在: \(B=(b_1, b_2, ..., b_n) \\ B\in R_{m \times n}\) 如果满足以下条件, 称基B是带有参数δ的LLL约简基:
- \[|\mu_{i,j}| \leq \frac{1}{2} (i > j)\]
- 对任意一组向量基$b_i$, $b_{i+1}$存在: \(\delta||\pi(b_i)||^2 \leq ||\pi(b_{i+1})||^2\)
定理21:
一组基B存在: \(B=(b_1, b_2, ..., b_n) \\ B\in R_{m \times n}\) 如果基B是带有参数δ的LLL约简基, 且存在1/4<δ<1, 则有结论:
- \[||b_1|| \leq \alpha^{(n-1)/2}\lambda_1\]
- \(||b_1|| \leq \alpha^{(n-1)/4}det(B)^{1/n}\) 其中有: \(\alpha=1/(\delta-1/4) \geq 4/3\)
Hermite定理32:
一组基B存在: \(B=(b_1, b_2, ..., b_n) \\ B\in R_{m \times n}\) 如果基B是LLL约简基, 对于n维的格L, 满足 \(||b_1|| \leq \sqrt{n}det(B)^{1/n}\)
最近题目比较多, 以后慢慢补.
sictfround3
easylattice
很久以前做的, 感觉很适合用来给LLL开头.
题目
from Crypto.Util.number import *
from secret import flag
import gmpy2
assert len(flag) == 47
f = bytes_to_long(flag)
p = getPrime(512)
g = getPrime(128)
h = gmpy2.invert(f, p) * g % p
print('h =', h)
print('p =', p)
"""
h = 9848463356094730516607732957888686710609147955724620108704251779566910519170690198684628685762596232124613115691882688827918489297122319416081019121038443
p = 11403618200995593428747663693860532026261161211931726381922677499906885834766955987247477478421850280928508004160386000301268285541073474589048412962888947
"""
解析
考察格基规约的原理, 可以构造数学表达式如下:
\[h = f^{-1} * g \mod{p}\]其中f为flag, 已知h与p, 可以将取模运算重新构造为多项式:
\[h * f + n * p = g\]可以写成代数形式:
\[\begin{bmatrix} f & n \end{bmatrix} \begin{bmatrix} h \\ p \end{bmatrix} = g\]我们期望求出f, 故我们可以从已知向量(h, p)为基础, 继续构造出满足(f, n)的向量基:
\[\begin{bmatrix} f & n \end{bmatrix} \begin{bmatrix} h & 1\\ p & 0 \end{bmatrix} = \begin{bmatrix} g & f \end{bmatrix}\]LLL中定理2具有一定的性质可供我们构造向量基求解, 当然直接使用调用LLL()
函数是无法拿到结果的:
from sage.all import *
from Crypto.Util.number import long_to_bytes
h = 9848463356094730516607732957888686710609147955724620108704251779566910519170690198684628685762596232124613115691882688827918489297122319416081019121038443
p = 11403618200995593428747663693860532026261161211931726381922677499906885834766955987247477478421850280928508004160386000301268285541073474589048412962888947
mat = matrix([
[h, 1],
[p, 0]
])
mat_LLL = mat.LLL()
print(long_to_bytes(abs(mat_LLL[0][1])))
# b'\xdc\xb3\x140+\x8c\x1d\x81\xbd\xb2NY\xa6q\xc3\x86C\xf2H\x01\xec]\xdc\xa7\xa4\x92\xdc\xd9\xb8\x15\xedo'
我们可以尝试使用LLL中Hermite定理3进行检验:
\[\begin{matrix} ||b_1|| = \sqrt{g_{<128>}^2+f_{<375>}^2} \approx g^3 \approx 2^{128*3}\\ n = 2 \\ det(B) = -p \\ 2^{128*3} \geq \sqrt{2p} \end{matrix}\]不满足Hermite定理3, 我们需要稍微修整, 使
\[2^{128*3} \leq \sqrt{2p'}\]由于p的比特长度为512, 我们可以计算比特长度的差值, 对向量基上的向量进行缩放, 因为SVP(最短向量问题)是一个范围, 可以使用以下公式模糊估计出向量缩放程度:
\[\delta = 2^{128*3}-\sqrt{2p}\]代入公式可以得到
\[\begin{bmatrix} f & n \end{bmatrix} \begin{bmatrix} h*\delta & 1 \\ p*\delta & 0 \end{bmatrix} = \begin{bmatrix} g*\delta & f \end{bmatrix}\]故可构造EXP(emmmm, 至于为什么要这样扩展长度, 肉眼可见的是g远小于f, 扩展以后可以尽量使得 $$ | b_1 | $$ 的改动尽可能小). |
EXP
from sage.all import *
from Crypto.Util.number import long_to_bytes
h = 9848463356094730516607732957888686710609147955724620108704251779566910519170690198684628685762596232124613115691882688827918489297122319416081019121038443
p = 11403618200995593428747663693860532026261161211931726381922677499906885834766955987247477478421850280928508004160386000301268285541073474589048412962888947
delta = 2 ** ((128*3*2) - (2*p).bit_length())
mat = matrix([
[h*delta, 1],
[p*delta, 0]
])
mat_LLL = mat.LLL()
print(long_to_bytes(abs(mat_LLL[0][1])))
# b'SICTF{e3fea01c-18f3-4638-9544-9201393940a9}A\xf0\x89\x84'
2024网鼎半决赛
RSA加密分析
题目
偷了dexterjie师傅的博客2:
# sagemath
import random
from Crypto.Util.number import *
flag = b''
k = 3
d = k/(2*(k+1))
ns = []
pqs = []
es = []
for i in range(3):
p = getPrime(512)
q = getPrime(512)
if p < q:
tmp = p
p = q
q = tmp
n = p*q
ns.append(n)
pqs.append((p,q))
n = min(ns)
x = random.randint(0,int(n^(d/2)))
x = next_prime(x)
for i in range(3):
p,q = pqs[i][0],pqs[i][1]
bound1 = int((p-q)/(3*(p+q)) * x * n ^ 0.25)
bound2 = int((p-q)/(3*(p+q)) * x^2 * n ^ 0.25)
z = random.randint(bound1,bound2)
f = (p-1)*(q-1)
e = inverse(x^2,f) * z % f
es.append(e)
e = 8462913
c = pow(bytes_to_long(flag),e,ns[0])
print(f'ns={ns}')
print(f'es={es}')
print(f'c={c}')
'''
ns=[58456238154727772714762362790039415372652580738847549549926175214592421074440425380491278175531057453959583518365006871715668115289674464868754600641087664868445977308497244134179400977293896807231964047365956545629327100737851868274388108150918741474301542596310528990700043925342513137054619092876834352167, 77621328849675766747673031143217563980503830449890233197117569566535170499356584333526498228802079135043121885950830320777642529199704224484173792215691924850086027618183393165197503325417741686635820334799489140360184827244176669486536901652827052817389390205607840551799799037689580359943641014734459153393, 112244920700186260026594736958318991062998987080230137582151100770199379608284829383065111800934933346946496041561749555085922429662611986339400029890877247514987095240380019377389184545006798594193383230298132838994539491402564579629017309643629910561998268286162916487705908044261914142200286678017692930877]
es=[46762963588977775648213636278524171408894671002158172701955774077187382885695296449518850546775920334764033057745226744111631183010556541467024035131602309988991836959736948179491431343087734419406823467043032520956443072556932946767546576469286010676651317873358203560021064830688914958086524112915123700678, 49605058941818136068558533413619424099600243928109466352604646203354430655695939177245076016870792265350960174089601299549033530643078866868937787258274475767441534991912769995268058506952466739575911255510940326565376471493045685544056383561868628029099619187607579109612157304977780126730283103824111801708, 35433601810279274137096137736120773703247868305827931187532982974242279082633517463016086358856291932337981126992048059591164336008738979183437333221010305682689432537562502148059203087673302900990705589870381203411821061168753251557946997898741497047442934600089950257888693394999451561437497637827070063398]
c=45042826649205831967869785980034342377048541926664036544108272069702081866501394370318117629151408517708467341069558466115205805860156690204194355692872459196902123082567148537856941845388225814307822482217762135547080677443326657146552580523747535577686386312386011950929734955156100305548239483424574706729
'''
解析
感觉程序完成得不是很优雅, 总共经历了两次3轮循环, 但是可以总结为一次结果, 暂时忽略掉z的界:
z = random.randint(bound1,bound2)
我们得到三组同余式:
\[\begin{matrix} e_1 * x^2 \equiv z_1 \mod{f_1} \\ e_2 * x^2 \equiv z_2 \mod{f_2} \\ e_3 * x^2 \equiv z_3 \mod{f_3} \end{matrix}\]其中x为定值, z为每轮随机生成的数值, f为p,q生成的phin, 其中有:
\[q < p\]现在已知三组的n, e与最终加密的e, 考虑欲获得flag需要尽量回复同余式获取对应的phin以计算私钥, 故需要尝试获取x与z的数值, 与ns, es相关的有f与e, 可以尝试构造格:
\[e_1 * x^2 = z_1 - k_1*f_1 \\ e_2 * x^2 = z_2 - k_2*f_2 \\ e_3 * x^2 = z_3 - k_3*f_3\]通过展开phin(即式中f)可以构造出包含n的关系式, 有:
\[phin = (p-1)(q-1) = n - p - q + 1\]设c有:
\[c = p + q - 1\]可以构造多项式:
\[e_1 * x^2 + k_1*n_1 = z_1 - k_1*c_1 \\ e_2 * x^2 + k_2*n_2 = z_2 - k_2*c_2 \\ e_3 * x^2 + k_3*n_3 = z_3 - k_3*c_3\]转换为矩阵形式有:
\[\begin{bmatrix} x^2 & n_1 & n_2 & n_3 \end{bmatrix} \begin{bmatrix} e_1 & e_2& e_3 \\ n_1 & 0 & 0 \\ 0 & n_2& 0 \\ 0 & 0 & n_3 \end{bmatrix} = \begin{bmatrix} z_1 - k_1*c_1 & z_2 - k_2*c_2 & z_3 - k_3*c_3 \end{bmatrix}\]欲求出x只需要再添加一个维度:
\[\begin{bmatrix} x^2 & n_1 & n_2 & n_3 \end{bmatrix} \begin{bmatrix} 1 & e_1 & e_2& e_3 \\ 0 & n_1 & 0 & 0 \\ 0 & 0 & n_2& 0 \\ 0 & 0 & 0 & n_3 \end{bmatrix} = \begin{bmatrix} x^2 & z_1 - k_1*c_1 & z_2 - k_2*c_2 & z_3 - k_3*c_3 \end{bmatrix}\]尝试使用LLL中Hermite定理3进行检验:
\[\begin{matrix} ||b_1|| \approx \sqrt{x^4+\sum_{i=1}^3(z_i-k_i*c_i)^2}\\ x^2_{<381>} \\ z_{i<632>} \\ n = 4 \\ det(B) = n_1*n_2*n_3 \\ 2^{316} \geq 2\sqrt[4]{n_1*n_2*n_3} \end{matrix}\]明显不满足Hermite定理3, 我们需要稍微修整配平, 这里可以考虑对x所在向量进行配平, 通过调试运行, 我们能大致感觉出x是最小的数:
\[||b_1|| \leq 2\sqrt[4]{n_1*n_2*n_3}\]同样对最简向量进行缩放, 可以考虑模糊估计出向量的缩放程度:
\[\delta = (\frac{||b_1||}{2\sqrt[4]{n_1*n_2*n_3}}) ^ 4\]实际上这里很麻烦, 因为我们无法几乎无法直接估计出delta(后来我想了一下其实也不是不行, 因为我们大致知道一定的值, 可能也可以极端地找出k与c的近似值, 通过复杂的近似也能找到大致的delta), 好在我们可以猜测出
\[\delta < 2^{1849}\]星盟在ACTF中提供了一种方法3, 可以通过判断是否整除找出对应的x:
for i in range(50, 1849):
delta = 2 ** i
mat = [
[delta,e1,e2,e3],
[0,-n1,0,0],
[0,0,-n2,0],
[0,0,0,-n3]
]
mat_lll = Matrix(mat).LLL()
x2_delta = abs(mat_lll[0][0])
x = iroot(x2_delta // delta, 2)
if x2_delta%delta == 0 and x[1]:
print('x is:', x[0])
break
# x is: 1696237025993008832375257492068228509280454088630659960513
未知量还剩z, k和f(计算中f被转换为n与c), 由于均为
参考文献
Daniele Micciancio.Lecture 4: The LLL Algorithm[C].Lattice Algorithms and Applications.Spring-2007 ↩ ↩2
DexterJie.网鼎杯半决赛[EB/OL].https://dexterjie.github.io/2024/11/23/%E8%B5%9B%E9%A2%98%E5%A4%8D%E7%8E%B0/%E7%BD%91%E9%BC%8E%E6%9D%AF%E5%8D%8A%E5%86%B3%E8%B5%9B/.2024-11-23 ↩ ↩2
星盟安全团队.ACTF2023 Writeup[EB/OL]星盟安全团队.https://blog.xmcve.com/2023/10/31/ACTF-2023-Writeup/.2023.10.31 ↩