2024SHCTF_week3_Crypto

Lattice

题目:

import gmpy2
from Crypto.Util.number import *
from enc import flag

m = bytes_to_long(flag)
n = getPrime(1024)
x = getPrime(200)
hint = (x*gmpy2.invert(m,n)) % n
print(f'n = {n}')
print(f'hint = {hint}')
'''
n = 135468605513880715606160882767765787154992546140468650057512573698684612475952478442814762328886660927143257644564134230892428444605363739481966015067533502387771994796933314650597759164542382096028864516989227078865314961731612554274030804378847341544941485447330710625751160113655721360522825842304325648661
hint = 4535444892439469356191795531860980185017935336250370459110841353738315673311973758532357439742440370098258890761750332474316301902006965178488232784675254754714945846956685367697549284904368943678089682352903895702618452358063454221008706189296038769220252217025015109037299722951003889830047605895164204665
'''

最标准的格
做之前最好先判断是否满足hermite定理
脚本:

#sage
import gmpy2
from Crypto.Util.number import *

n = 135468605513880715606160882767765787154992546140468650057512573698684612475952478442814762328886660927143257644564134230892428444605363739481966015067533502387771994796933314650597759164542382096028864516989227078865314961731612554274030804378847341544941485447330710625751160113655721360522825842304325648661
hint = 4535444892439469356191795531860980185017935336250370459110841353738315673311973758532357439742440370098258890761750332474316301902006965178488232784675254754714945846956685367697549284904368943678089682352903895702618452358063454221008706189296038769220252217025015109037299722951003889830047605895164204665

# hint*m=x%n
# hint*m=x+kn
# x=hint*m-kn

# [m,-k][1,hint]=[m,x]
#       [0,n]
m=getPrime(37*8)
x = getPrime(200)
length1=gmpy2.iroot(2*n,2)[0]
length2=gmpy2.iroot(x**2+m**2,2)[0]
print(length1.bit_length())
print(length2.bit_length())

Ge=Matrix(ZZ,[[1,hint],
              [0,n]])
m=abs(Ge.LLL()[0][0])
print(long_to_bytes(int(m)))

这里的m位数也是根据常识预估一下

babylcg

题目:

from Crypto.Util.number import *
from enc import flag

seed = bytes_to_long(flag)

a = getPrime(400)
b = getPrime(400)
p = getPrime(400)
c = []
for i in range(3):
    seed = (seed*a+b)%p
    c.append(seed>>80)
print(f'a = {a}')
print(f'b = {b}')
print(f'p = {p}')
print(f'c = {c}')

'''
a = 2480723693416197023777639119379107915577379442319446556514537465902730221165988032585937040968036882125810398538496323351
b = 1904193709124547126225055171380429984044969427702757019616077686519603583212249311116383727431445401398594522230612229733
p = 1532358535804235132496312416063170109053232217889240979567714057566239469579822887828122819499504563106464882747447051359
c = [813530482014456574209632986607111359200629085246367954186877618366451174001463654876753005264098, 1054295430131833360658465071066491055652904289373961069213308535490435549697560050854110548843919, 374976866832751055109605198170602358027434683548463528601734580123896818157824411065383601884240]
'''

非常规lcg,因为这里的see>>80,高位泄露了

c[0]=813530482014456574209632986607111359200629085246367954186877618366451174001463654876753005264098
print(c[0].bit_length())
#319>>80

这里用c0,c1套一下

H1+L1=((H0+L0)*a+b)%p
#H1,L1是c1的高位和低位,c0同理

构建多项式环:

f=(H0+L0)*a+b)-(H1+L1)
其中L0和L1未知,令其为x和y
即f=(H0+x)*a+b)-(H1+y)
这样即可得到x,即得到c0
而从根据a的逆元反推seed

这里最难的点感觉就是求小根那个函数
这里用的其他师傅的脚本,没实力啊~

import itertools
def small_roots(f, bounds, m=1, d=None):
    if not d:
        d = f.degree()
    R = f.base_ring()
    N = R.cardinality()
    f /= f.coefficients().pop(0)
    f = f.change_ring(ZZ)
    G = Sequence([], f.parent())
    for i in range(m+1):
        base = N^(m-i) * f^i
        for shifts in itertools.product(range(d), repeat=f.nvariables()):
            g = base * prod(map(power, f.variables(), shifts))
            G.append(g)
    B, monomials = G.coefficient_matrix()
    monomials = vector(monomials)
    factors = [monomial(*bounds) for monomial in monomials]
    for i, factor in enumerate(factors):
        B.rescale_col(i, factor)
    B = B.dense_matrix().LLL()
    B = B.change_ring(QQ)
    for i, factor in enumerate(factors):
        B.rescale_col(i, 1/factor)
    H = Sequence([], f.parent().change_ring(QQ))
    for h in filter(None, B*monomials):
        H.append(h)
        I = H.ideal()
        if I.dimension() == -1:
            H.pop()
        elif I.dimension() == 0:
            roots = []
            for root in I.variety(ring=ZZ):
                root = tuple(R(root[var]) for var in f.variables())
                roots.append(root)
            return roots
    return []
# sage
a = 2480723693416197023777639119379107915577379442319446556514537465902730221165988032585937040968036882125810398538496323351
b = 1904193709124547126225055171380429984044969427702757019616077686519603583212249311116383727431445401398594522230612229733
p = 1532358535804235132496312416063170109053232217889240979567714057566239469579822887828122819499504563106464882747447051359
c = [
    813530482014456574209632986607111359200629085246367954186877618366451174001463654876753005264098,
    1054295430131833360658465071066491055652904289373961069213308535490435549697560050854110548843919,
    374976866832751055109605198170602358027434683548463528601734580123896818157824411065383601884240,
]

PR.<x,y> = PolynomialRing(Zmod(p))
f = ((c[0]<<80)+ x) * a + b - ((c[1]<<80) + y)
roots = small_roots(f,(2^80, 2^80), m=4, d=4)
s1 = (c[0]<<80) + roots[0][0]
m = (s1 - b) * inverse_mod(a, p) % p
print(bytes.fromhex(hex(m)[2:]))

大学×高中√

题目:

from Crypto.Util.number import *
from enc import flag

m = bytes_to_long(flag)
assert len(flag)==47
leak = cos(m).n(1000)
print(leak)
# 0.0998850707771875936255320441622758414273045504083276270807057373186889944319840434839754884311751169692981949171665523641780707944615961482956134641228858117430417240690757611709757603218395869292050704312456085723639395453639137813691195138264605914554001589394663177610703870989537946983548789434829

这道题思路也是构造格的形式

leak = cos(m).n(1000)
可以写成
m-arcos(leak)-2k π \pi π=0
其中arcos(leak)求的是一个周期(2 π \pi π)内的具体值
这样我们就构造出来了一个三维格

令x=arccos(leak)
如下所示

[ m − 1 2 ∗ k ] [ 1 0 1 0 1 x 0 0 π ] ⇒ [ m − 1 0 ] \begin{bmatrix} m&-1&2*k\\ \end{bmatrix} \begin{bmatrix} 1&0&1\\ 0&1&x\\ 0&0&\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} m&-1&0\\ \end{bmatrix} [m12k] 1000101xπ [m10]

经过计算发现不满足hermite定理

#Hermite定理判断
#初次判断长度
#iroot函数参数只能是整数,这里用3代替pi,其实大小而言根本不影响
length1=gmpy2.iroot(3,2)[0]*gmpy2.iroot(3,3)[0]
print(length1.bit_length())//1

length2=gmpy2.iroot(m**2+1,2)[0]
print(length2.bit_length())//377

我们只能给中间矩阵添加一些值
使目标矩阵的值小于行列式的值
正确的矩阵构造如下
[ m − 1 2 ∗ k ] [ 1 0 t ∗ 1 0 a t ∗ x 0 0 t ∗ π ] ⇒ [ m − a 0 ] \begin{bmatrix} m&-1&2*k\\ \end{bmatrix} \begin{bmatrix} 1&0&t*1\\ 0&a&t*x\\ 0&0&t*\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} m&-a&0\\ \end{bmatrix} [m12k] 1000a0t1txtπ [ma0]

因为这里的m比特长度是478,所以将将a的长度也设置位478(如果不这样设置会导致目标向量各个维度长度不均衡,不容易规约出来结果),然后找到合适的t

下面是两个错误构造的情况:

一: [ m − 1 2 ∗ k ] [ 1 0 t ∗ 1 0 1 t ∗ x 0 0 t ∗ π ] ⇒ [ m − a 0 ] \begin{bmatrix} m&-1&2*k\\ \end{bmatrix} \begin{bmatrix} 1&0&t*1\\ 0&1&t*x\\ 0&0&t*\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} m&-a&0\\ \end{bmatrix} [m12k] 100010t1txtπ [ma0]

*这就是我上面说的目标向量各个维度长度不均衡*

二:
[ t m − 2 ∗ k ] [ t 0 − x 0 1 1 0 0 π ] ⇒ [ t m 0 ] \begin{bmatrix} t&m&-2*k\\ \end{bmatrix} \begin{bmatrix} t&0&-x\\ 0&1&1\\ 0&0&\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} t&m&0\\ \end{bmatrix} [tm2k] t00010x1π [tm0]

*这样构造虽然行列式的值变大了,但目标矩阵的值也变大*
*依然不满足*

下面是脚本代码

import gmpy2
from Crypto.Util.number import *

#求出pi的小数点后1000位
RF = RealField(1000)
pi = RF(pi)

m=2**(47*8)
leak=0.0998850707771875936255320441622758414273045504083276270807057373186889944319840434839754884311751169692981949171665523641780707944615961482956134641228858117430417240690757611709757603218395869292050704312456085723639395453639137813691195138264605914554001589394663177610703870989537946983548789434829
x=arccos(leak)

#Hermite定理判断
#初次判断长度
#iroot函数参数只能是整数,这里用3代替pi,其实大小而言根本不影响
length1=gmpy2.iroot(3,2)[0]*gmpy2.iroot(3,3)[0]
print(length1.bit_length())

length2=gmpy2.iroot(m**2+1,2)[0]
print(length2.bit_length())

#添加常数再判断
#这样添加是为了让我们的目标向量数值变得均衡[m,a,0]
t=2**756
a=2**(47*8)
length1=gmpy2.iroot(3,2)[0]*gmpy2.iroot(t*3*a,3)[0]
print(length1.bit_length())

length2=gmpy2.iroot(m**2+1+a**2,2)[0]
print(length2.bit_length())

#m-arcos(leak)-2kpi=0
#格的形式
#            [1,0,t*1 ]
# [m,-1,-2*k][0,a,t*x ]=[m,-a,0]
#            [0,0,t*pi]

#这种构造随着行列式的增大,目标向量也变大,而且目标向量始终大于行列式
#所以不行
#            [t,0,-x]
# [t,m,-2*k] [0,1,1 ]=[t,m,0]
#            [0,0,pi]


#构造
Ge=Matrix(QQ,[[1,0,t],
              [0,a,t*x],
              [0,0,t*pi]])
m=Ge.LLL()[0][0]
m=abs(m)
print(long_to_bytes(int(m)))

Shamir

题目:

from Crypto.Util.number import getPrime,bytes_to_long
import random
from os import getenv

BANNER = """
 __          __  _                            _______       _____ _                     _      
 \ \        / / | |                          |__   __|     / ____| |                   (_)     
  \ \  /\  / /__| | ___ ___  _ __ ___   ___     | | ___   | (___ | |__   __ _ _ __ ___  _ _ __ 
   \ \/  \/ / _ \ |/ __/ _ \| '_ ` _ \ / _ \    | |/ _ \   \___ \| '_ \ / _` | '_ ` _ \| | '__|
    \  /\  /  __/ | (_| (_) | | | | | |  __/    | | (_) |  ____) | | | | (_| | | | | | | | |   
     \/  \/ \___|_|\___\___/|_| |_| |_|\___|    |_|\___/  |_____/|_| |_|\__,_|_| |_| |_|_|_|   
"""
print(BANNER)

flag = getenv("GZCTF_FLAG","GZCTF_NOT_DEFINE")
m = bytes_to_long(flag.encode())
n = getPrime(1024)
coefficients = [m] + [random.randrange(1,n-1) for i in range(100)]   
print(f"n = {n}")

def f(x):
    sum = 0
    for i in range(len(coefficients)):
        sum += coefficients[i]*pow(x,i,n) % n
        sum %= n
        
    return sum

while 1:
    x = int(input("Please Input x: "))
    if x == 0:
        print("Not Allowed!!!")
        exit()
    res = (x,f(x))
    print(res)

这里coefficients = [m] + [random.randrange(1,n-1) for i in range(100)] 是为了生成

f ( x ) = m + a 1 x + a 2 x 2 + ⋯ + a k − 1 x k − 1 f(x) = m + a_1 x + a_2 x^2 + \cdots + a_{k-1} x^{k-1} f(x)=m+a1x+a2x2++ak1xk1

其中包含100个系数 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an
f(x)是为了计算当输入x后的值

本人小菜,所以直接来分析脚本

from pwn import *
from Crypto.Util.number import *

ip_address = ""
port = 
sh = remote(ip,port)
sh.recvuntil(b"n = ")
n = int(sh.recvline().decode())
PT = []
for i in range(101):
    sh.sendlineafter(b"Please Input x:",str(i+1).encode())
    res = eval(sh.recvline().decode())
    PT.append(res)
    
R.<x> = PolynomialRing(Zmod(n))
recover_f = R.lagrange_polynomial(PT)
m = recover_f(0)
flag = long_to_bytes(int(m))
print(flag)

首先是先远程连接,然后等到服务器输出‘n=’时停止
接收n的值
然后循环101次,从1开始,依次得到f(x),因为源码禁止从0开始(从0开始可以直接得到m)
下面采用拉格朗日插值法:

PT = [(1, f(1)), (2, f(2)), (3, f(3)), …, 101, f(101))]
R.lagrange_polynomial(PT) 返回一个多项式,该多项式在给定的点对 PT后可以恢复f(x)
(这里不讨论拉格朗日插值法实现的原理,感兴趣可以自行查找资料)
下面我们就可以令x=0来计算
m = recover_f(0)

Approximate_n

baby_lock

这两道题目有空再分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值