HZNUCTF2024 Crypto复现

初赛

ez_encode

赛博厨子直接解

base85-base64-base32

答案:HZNUCTF{this_is_real_ez_encode}

sign_in

看到了好几种解法,值得学习

一开始看到p>>500是想爆破的,但是用的不是费马分解是开方后另一个直接+1往后遍历的,没跑出来,以为是数据可能相差太大,于是想着推一下(看来费马分解对于这种问题的普适性更好一点的感觉)
简单的推导

p>>500即等于p/(2**500)

那么q=next_prime(p + p>>500)=p+p/(2**500)+r

n大约等于pq=p(p+p>>500+r)=p*(p+p*(1/2500))+rp=p2 *(1+1/2^500)+rp

两边同时乘上(1+1/2^500),凑个平方,rp比较小(这里我感觉可以忽略)

(1+1/2^500)*n = (p(1+1/2500))2 + rp(1+1/2^500) 小于q^2(总之开方后和q相近)

那么对(1+1/2^500)*n开根号,再往下取素数能够得到q,即可得到p,q,然后正常rsa解即可(其实这里再缩小一下范围就能够知道 根号(1+1/2**500)n往下取素数就是q)

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

e=0x10001
n= 12566670550037472299857950450003060170543220489916388216108225583064368322313899804227543199410966827815054158227594990460167944742865670575641390368325110501757177815240023094766378289637565567657130897900181098182493743124700034725694478105732966433589893047975249354370253300873663004210794844162122949861831889639652391219517545984669360480993893579226705266579746356691022559954498205977100626718703472959781277579633411710680518214072645890060091696596677005871169794651099630888477188908717174196927146741531268975111463546260970984916650217713571773967414868843498089570525035105444427219273563117921246804473
c= 4124624756019497985716853528084082801715336009122321144611208260743394500347979730096802843910414584127892037242967052613391189149745555464301106682220336094445291743913607113208572333466692690543238555216464948419114875183086195193063296003211213015928593592167433717598516244635364208977388314062522329260854816785931896124692965607665688555874771010513517238105683326015230127982290701518048033192554799179965513164276929053041064167818711631412974446463873856951641611547970769034038478710696476593301560763875141191494692433617954869188473092441104714849891612692614501415736545219466763702237015017246607888479
# q=iroot(n+(n>>500),2)[0]
# while True:
#     if isPrime(q)!=True:
#         q=next_prime(q)
#     p=n//q
#     if isPrime(p):
#         print(p)
#         print(q)
#         break
#     q=next_prime(q)
p=112101162126168309851861785514443001423655098851906562581778106594118891941184566721804363415992148782974903298609095043468529078206206340996671006899198025323295818931142772058032844947884812472207356462258549712807805749427443301473418930380160836756251640482734877665071455862447560358496039308458847867543
q=112101162126168309851861785514443001423655098851906562581778106594118891941184566721804363415992148782974903298609095043468529078206206340996671006899232271514952798554051412600485450455060705163623195494450571388257535658327920826985477438542173650414426236932285037827396311979360044691954935978755801430511
phi=(p-1)*(q-1)
d=invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
#另一种解法:费马分解
from Crypto.Util.number import *
from gmpy2 import *

e=0x10001
n= 12566670550037472299857950450003060170543220489916388216108225583064368322313899804227543199410966827815054158227594990460167944742865670575641390368325110501757177815240023094766378289637565567657130897900181098182493743124700034725694478105732966433589893047975249354370253300873663004210794844162122949861831889639652391219517545984669360480993893579226705266579746356691022559954498205977100626718703472959781277579633411710680518214072645890060091696596677005871169794651099630888477188908717174196927146741531268975111463546260970984916650217713571773967414868843498089570525035105444427219273563117921246804473
c= 4124624756019497985716853528084082801715336009122321144611208260743394500347979730096802843910414584127892037242967052613391189149745555464301106682220336094445291743913607113208572333466692690543238555216464948419114875183086195193063296003211213015928593592167433717598516244635364208977388314062522329260854816785931896124692965607665688555874771010513517238105683326015230127982290701518048033192554799179965513164276929053041064167818711631412974446463873856951641611547970769034038478710696476593301560763875141191494692433617954869188473092441104714849891612692614501415736545219466763702237015017246607888479

a=iroot(n,2)[0]
while True:
    B2=a**2-n
    if is_square(B2):
        b=iroot(B2,2)[0]
        p=a+b
        q=a-b
        break
    a+=1

phi=(p-1)*(q-1)
d=invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
#b'HZNUCTF{easy_rsa_challenge_isnt_it}'
#另一种
from Crypto.Util.number import *
from gmpy2 import *

e=0x10001
n= 12566670550037472299857950450003060170543220489916388216108225583064368322313899804227543199410966827815054158227594990460167944742865670575641390368325110501757177815240023094766378289637565567657130897900181098182493743124700034725694478105732966433589893047975249354370253300873663004210794844162122949861831889639652391219517545984669360480993893579226705266579746356691022559954498205977100626718703472959781277579633411710680518214072645890060091696596677005871169794651099630888477188908717174196927146741531268975111463546260970984916650217713571773967414868843498089570525035105444427219273563117921246804473
c= 4124624756019497985716853528084082801715336009122321144611208260743394500347979730096802843910414584127892037242967052613391189149745555464301106682220336094445291743913607113208572333466692690543238555216464948419114875183086195193063296003211213015928593592167433717598516244635364208977388314062522329260854816785931896124692965607665688555874771010513517238105683326015230127982290701518048033192554799179965513164276929053041064167818711631412974446463873856951641611547970769034038478710696476593301560763875141191494692433617954869188473092441104714849891612692614501415736545219466763702237015017246607888479

p_high=iroot(n,2)[0]>>500  #忽略小部分数据
# print(type(p_high)) mpz
PR.<x> = PolynomialRing(RealField(1024))
#创建一个实数域精度为1024位的多项式环
f=x*(x+ int(p_high))-n #这里p_high要转整型
f=f.monic()
#f.monic()是一个多项式方法,用于将多项式的首项系数设置为1,即将多项式转化为首一形式
p=f.roots()
# print(p)
# [(-1.121011621261683098518617855144430014236550988519065625817781065941188919411845667218043634159921487829749032986090950434685290782062063409966710068992322715149527985540514126004854504550607051636231954944505713882575356583279208269854774385421736504144262369322850378273963119793600446919549359787558040454e308, 1), (1.121011621261683098518617855144430014236550988519065625817781065941188919411845667218043634159921487829749032986090950434685290782062063409966710068991980253232958189311427720580328449478848124722073564622585497128078057494274433014734189303801608367562516404827348776650714558624475603584960393084588452527e308, 1)]
p=int(p[1][0])

while True:  #遍历
    if n % p ==0:
        q=n//p
        print(p)
        print(q)
        break
    p+=1
# p=112101162126168309851861785514443001423655098851906562581778106594118891941184566721804363415992148782974903298609095043468529078206206340996671006899198025323295818931142772058032844947884812472207356462258549712807805749427443301473418930380160836756251640482734877665071455862447560358496039308458847867543
# q=112101162126168309851861785514443001423655098851906562581778106594118891941184566721804363415992148782974903298609095043468529078206206340996671006899232271514952798554051412600485450455060705163623195494450571388257535658327920826985477438542173650414426236932285037827396311979360044691954935978755801430511
#构建一个实数域对象RealField(1024),此对象具有精度为1024位的浮点数计算能力
#这个感觉很好用,记录一下

答案:HZNUCTF{easy_rsa_challenge_isnt_it}

你知道什么叫第二重要极限吗?

考的就是高数题,裂了,全忘了。查了一下概念,还好求出来了(其实可以直接夸克搜题的)
a = lim ⁡ x → 0 ( a 1 x + a 2 x + ⋯ + a n x n ) n x a = \lim_{x \to 0} (\frac{a_1^x+a_2^x+\cdots+a_n^x}{n})^{\frac{n}{x}} a=x0lim(na1x+a2x++anx)xn
在这里插入图片描述

经过化简a=a1a2…*an

然后md5加密即可,是32位小写

答案:HZNUCTF{a602e7c7a5b81d83c9e8b49657a0f213}

ez_rsa

看到p和q的时候感觉k的次数也不是很大,就想着可以试一下多项式求解,直接解出k就可以
但是python的库算不出来,试一下sage解出了k,剩下的直接计算就行(这种大计算量的扔给sage好用多了)
sage

var('k')
n = 434629751883495095590322184835294241713826996124724888574456689006002393371526151665914856648441777998913711962123653338248552669457411846853237739783050598017579775719691937934872919106352040902327116926790105784755926058764338785933556161606842096674927069945482244958540971324781

p = 3 * k ** 17 + 3 * k ** 11 - 53 * k ** 7 + 12 * k ** 5 - 114 * k + 27329
q = 5 * k ** 13 - 7 * k ** 11 + 43 * k ** 5 - 313 * k ** 3 - 14 * k + 18869
eq = p * q == n

solu=solve(eq, [k])
print(solu)

解出k

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

# print(2**32)
e = 65537
n = 434629751883495095590322184835294241713826996124724888574456689006002393371526151665914856648441777998913711962123653338248552669457411846853237739783050598017579775719691937934872919106352040902327116926790105784755926058764338785933556161606842096674927069945482244958540971324781
enc = 12698694495692349269363576153078519111247359455557853801301945966110661300060428247980981025832474449284566651636612071026974332393320580585633615246812233266102584146373264369967669578537174446367567610553220268243715074041129093898065352593985427607547972686055285353476015645157


k=2232206010
p = 3 * k ** 17 + 3 * k ** 11 - 53 * k ** 7 + 12 * k ** 5 - 114 * k + 27329
q = 5 * k ** 13 - 7 * k ** 11 + 43 * k ** 5 - 313 * k ** 3 - 14 * k + 18869
# print(p)
# print(q)
phi=(p-1)*(q-1)
d=invert(e,phi)
m=pow(enc,d,n)
print(long_to_bytes(m))

#另一种解法,遍历
n = 434629751883495095590322184835294241713826996124724888574456689006002393371526151665914856648441777998913711962123653338248552669457411846853237739783050598017579775719691937934872919106352040902327116926790105784755926058764338785933556161606842096674927069945482244958540971324781
enc = 12698694495692349269363576153078519111247359455557853801301945966110661300060428247980981025832474449284566651636612071026974332393320580585633615246812233266102584146373264369967669578537174446367567610553220268243715074041129093898065352593985427607547972686055285353476015645157
e = 65537
from gmpy2 import *
from Crypto.Util.number import *

k_prox = iroot(n // 15, 30)[0]
for k in range(k_prox - 2000, k_prox + 2000):
    p = 3 * k ** 17 + 3 * k ** 11 - 53 * k ** 7 + 12 * k ** 5 - 114 * k + 27329
    q = 5 * k ** 13 - 7 * k ** 11 + 43 * k ** 5 - 313 * k ** 3 - 14 * k + 18869
    if p * q == n:
        d = invert(e, (p - 1) * (q - 1))
        print(long_to_bytes(pow(enc, d, n)))
# # HZNUCTF{cdf7d315-4f57-4d3b-b7b9-8afdbcfccda9}

答案:HZNUCTF{cdf7d315-4f57-4d3b-b7b9-8afdbcfccda9}

ez_hash

题目:

print(sin(int.from_bytes(open(“flag.txt”, “rb”).read().strip(), “big”)).n(1024))
#0.9293072566360917156721319625113859414638614581752638175081621377181647077177905614201525663698026484356904149524948758114053950932573856913592620188629564842619113660708249485771619087909572007797061060693639948035909320176601470572889582595546521165948926724721219315095929084715884686268383018745103696402

这题是关于格密码的,但是还不太会,等我后面补上
首先我们看到打印的内容print(sin(int.from_bytes(open(“flag.txt”, “rb”).read().strip(), “big”)).n(1024))

int.from_bytes(open(“flag.txt”, “rb”).read().strip(), “big”)
这段代码是使用Python语言读取名为"flag.txt"的文件,将文件内容按照大端序的方式转换为整数。具体解释如下:
open(“flag.txt”, “rb”):打开名为"flag.txt"的文件,以二进制只读模式(“rb”)打开。这样可以确保以字节的形式读取文件内容。
.read():读取文件的全部内容,以字节的形式返回。
.strip():去除文件内容两端的空白符(包括空格、制表符、换行符等),以确保纯粹的文件内容。
int.from_bytes(data, “big”):将字节序列data按照大端序(big-endian)转换为整数。大端序是一种字节序,其中最高位字节排在最前面,最低位字节排在最后面。
sin().n(1024)这是对得到的整数求正弦值并输出前1024位

因此,这段代码的作用是读取"flag.txt"文件的内容,将其解释为一个大整数,然后计算该整数对应的角度的正弦值,并返回该正弦值的前1024位数字。
拿到手其实没有思路,主要是格还没接触多久,但是知道是格也没有构造出来,看了wp才理解点

对于sin(m)=sin( 2k * Π + m) = c
那么 m = arcsin( c ) + 2k * Π
这里进行构造格(格的构造有很多种的)
在这里插入图片描述
通过这个格,我们求到k,然后求m

from Crypto.Util.number import *
c=0.9293072566360917156721319625113859414638614581752638175081621377181647077177905614201525663698026484356904149524948758114053950932573856913592620188629564842619113660708249485771619087909572007797061060693639948035909320176601470572889582595546521165948926724721219315095929084715884686268383018745103696402
c=arcsin(c)
pie = pi.n(1024)#满足位数要求

M = matrix(QQ, [
    [  1, 0, 0], 
    [ c, 1,  0], 
    [pie, 0, 1]
    ]) 
#构造格,QQ是实数域,ZZ是整数域
M[:, 0] *= 2**1024 # 为了更好的规约出结果,但是不太清楚这个取值的问题

k=int(M.LLL()[0][-1])#求出k
print(long_to_bytes(int(k*pie+c)))

构造的另一个格,也能求出flag

from Crypto.Util.number import *
c=0.9293072566360917156721319625113859414638614581752638175081621377181647077177905614201525663698026484356904149524948758114053950932573856913592620188629564842619113660708249485771619087909572007797061060693639948035909320176601470572889582595546521165948926724721219315095929084715884686268383018745103696402
c=arcsin(c)
pie = pi.n(1024)#满足位数要求

M = matrix(QQ, [
    [c, 0, 0],
    [-1, 1, 0], 
    [pie, 0, 1]
    ])
#构造格,QQ是实数域,ZZ是整数域
M[:, 0] *= 2**1024# 为了更好的规约出结果

flag=int(M.LLL()[0][1])#求出m
print(long_to_bytes(abs(int(flag))))
print(M.LLL())

答案:HZNUCTF{sin_is_a_broken_hash_function}

总结

1.见识到了很多的解法,对于同一题可以多看看别人的解法,拓展思路
2.对于p,q相近的rsa,首选费马分解,它的通用性会更好一些
3.构建一个实数域对象RealField(1024),此对象具有精度为1024位的浮点数计算能力,这个记录一下
4.回忆了一下我的高数,忘了好多了啊
5.sage还是好用的,大计算量可以试试
6.格密码初略的了解了一些,还在学习中,主要是格的构造,这个要多练题


决赛

鸽了蛮久的,但是还是想复现完,有很多不知道的东西呢

ez_math

题目:

from hashlib import md5
from Crypto.Util.number import *
from secret import flag,a,b,c

n = getPrime(512)

assert n == a**2 + b**2 * c**2

assert flag == "HZNUCTF{"+ md5(str(a+b+c).encode()).hexdigest() + "}"
#n =10025528183022843297972893037004274434565776775894832972425335533530501283241358450613164144702044922014938018419602889154405001125828093273180244377985061

解题:看了wp才知道是sage直接解,这是真的不知道,在那里硬推(;´д`)ゞ,一开始还看错了题目

sage里有一个three_squares() 函数 ,用来求解n的三数平方组合的

from hashlib import md5
n =10025528183022843297972893037004274434565776775894832972425335533530501283241358450613164144702044922014938018419602889154405001125828093273180244377985061
a,b,c=three_squares(n)
flag = "HZNUCTF{"+ md5(str(a+b+c).encode()).hexdigest() + "}"
print(flag)
prime_pi(n)  #小于等于n的素数个数
divisors(n)  #n的因子
number_of_divisors(n)  #n的因子数
factor(n)  #n的因式分解
euler_phi(n)  #n的欧拉函数值
two_squares(n)   #n的两数平方组合
three_squares(n)  #n的三数平方组合
four_squares(n)  #n的四数平方组合

x.nth_root(n, truncate_mode=True) #x开n次方(不管是否完全开方,取整)
mod(x,p).nth_root(n) #x有限域开n次方

crypto常用工具 | Lazzaro (lazzzaro.github.io)

答案:HZNUCTF{55d1c6086bf65f7416ae547ca4adaaa0}

ez_GCD

题目:

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

assert flag == b"HZNUCTF{" + secret + b"}"

p = getPrime(512)
q = getPrime(512)
n = p*q
e = 13

c1 = pow(bytes_to_long(secret),e,n)
c2 = pow(bytes_to_long(flag),e,n)

print("n=",n)
print("c1=",c1)
print("c2=",c2)

'''
n= 51711881342079090046710339053185915196592193907765106374585058286166071319919030663920585727689511100225316280995504974390025031512931086762439305035320923676658006496757813107901542462561299039841048383714789684286745486830845022431309904891583468338938858416690551509404047885412631362845112556984334658193
c1= 44927403636140880528875267715570813243861340472540215272736393969726046899465585891003361404210195173841255389954591105855462956739092309051238783733150953983007179211308485370334344653631060233517749066990827356727102781527748833642957445242783037541048490849329290723450190991092218836965214306036774544922
c2= 27779044958100721851033198401901952224772827543379036072351031867140664172784782835184120579379055764845644500617579789253407456670008585005819147325398655666107774215656128946511502925543182821362769215961961661085449227850810705363950301308978417870203385528044936828106641970096899692115435601591731758964
'''

这道题是后面看的,前面一直在看前面两道,但是还是没啥思路,主要不太记得这个加密了(有写过吗(+_+)?,之前学过,但是忘了)

看了wp,考的是Franklin-Reiter相关消息攻击,然后还有bytes和long的转化:bytes转long型相当于256进制

我们已知
s e c r e t e m o d n = c 1 secret^e \quad mod\quad n = c1 secretemodn=c1

f l a g e m o d n = c 2 flag^e \quad mod\quad n = c2 flagemodn=c2

在这里插入图片描述

那么设secret的长度 = i , secret = x

c2 = x ^ 13 
c3 = (bytes_to_long(b'HZNUCTF{' + b'\00' * i + b'}' ) + 256 * x) ^ 13
(其中x = secret , i = len(secret))
#即找到flag与secret之间的关系,通过256进制

flag可以分为三部分:‘HZNUCTF{’ , secret , ‘}’

所以先把’HZNUCTF{‘和’}'转为bytes,中间用 ‘\00’ 进行填充,但是我们不知道secret的长度,这里需要进行爆破,再加上secret即可

然后Franklin-Reiter相关消息攻击求secret

在这里插入图片描述

简单来说:就是对于两个有某种线性关系的明文m1和m2,它们对于相同e,n进行RSA加密,就有可能求出m1,m2

m1 = bytes_to_long(flag)

m2 = a * m1 + b #某种线性关系即可

c1 = pow(m1,e,n)

c2 = pow(a * m1 + b,e,n)

其中c1,c2,e,n都已知,那么m1,m2可求

注意最后解的形式是x-M,我们需要的是后面的M,可以使用sage中的Q.coefficients()[0]函数,获取多项式Q的系数,或者取x为一个值,然后x-(x-M)=M

解密过程:首先根据m1和m2的关系,在sage中建立两个方程,求两个方程的最大公因子,再求系数

解密代码:

from Crypto.Util.number import *
from gmpy2 import *
n= 51711881342079090046710339053185915196592193907765106374585058286166071319919030663920585727689511100225316280995504974390025031512931086762439305035320923676658006496757813107901542462561299039841048383714789684286745486830845022431309904891583468338938858416690551509404047885412631362845112556984334658193
c1= 44927403636140880528875267715570813243861340472540215272736393969726046899465585891003361404210195173841255389954591105855462956739092309051238783733150953983007179211308485370334344653631060233517749066990827356727102781527748833642957445242783037541048490849329290723450190991092218836965214306036774544922
c2= 27779044958100721851033198401901952224772827543379036072351031867140664172784782835184120579379055764845644500617579789253407456670008585005819147325398655666107774215656128946511502925543182821362769215961961661085449227850810705363950301308978417870203385528044936828106641970096899692115435601591731758964
e=13
def GCD(a,b):#求最大公因子
    if b==0:
        return a.monic()
    else:
        return GCD(b,a%b)
PR.<x>=PolynomialRing(Zmod(n))
for i in range(50):
    g1=x^e-c1
    g2=(bytes_to_long(b'HZNUCTF{'+b'\00'*i+b'}')+256*x)^e-c2#通过256进制,把secret和flag进行转化
    if GCD(g1,g2)[0]!=1:
        print(long_to_bytes(int(n-GCD(g1,g2)[0])))#这个是取了x=n的情况
        #print(long_to_bytes(int(-GCD(g1,g2).coefficients()[0])))
#b'f872ed43-a77a-4964-b215-8cbef05a1334'

ez_rsa

题目:

from Crypto.Util.number import bytes_to_long, inverse, getPrime
from gmpy2 import gcd
from secret import flag

assert flag.startswith(b'HZNUCTF{') and flag.endswith(b'}')
m = bytes_to_long(flag)

p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x10001
phi = (p - 1) * (q - 1)
assert gcd(e, phi) == 1
d = inverse(e, phi)
hint = pow(2*e + d, 3076, phi)
c = pow(m, e, n)
print(f'{n = }')
print(f'{c = }')
print(f'{hint = }')

# n = 83312970175464153481341766199862672005843884032065729818348527305553537120321898334286778820857584007782243838290886667344499628939342255482077598932803060202743171294065297718653254243096080113955917798479875235479099008156460246096313785233809780625190144353952427715145993502938109965121525650629267636633
# c = 54922252484017745069496014860568159008125240774170934714628322133569281169045432175325275210347617669537758197717259611349697543721081934325449079340635504246232236541293093149944995066993503845178538812469017964114279195360759090467455743166522732538087938110470878536150916931323890793579533296737038109125
# hint = 68129191967893179827612871900416097308388907834366265926341679123402536261156224529073330624848279371825092696590928029143839271012556877760397316785628777904477907012359031050334429146371709956779213185605783109476303053850250184435018123614021171447233363836078279672500553479950647813364992182178499581909

这道题的wp真的看了很久,终于弄懂了,出这道题的师傅也是厉害,数学功底挺好的吧(给我转糊涂了都)

其实很简单,主要考的就是二项式定理,硬解(我觉得这个描述挺恰当的)

考的是RSA,给了一个hint,我们主要是靠这个来求解
h i n t ≡ ( 2 ∗ e + d ) 3076 ( m o d p h i ) hint \equiv (2*e+d)^{3076} \quad (mod \quad phi) hint(2e+d)3076(modphi)
咱们把它进行二项式展开:
g = 3076 g=3076 g=3076

h i n t ≡ ( ∑ i = 0 g C g i d g − i 2 i e i ) ( m o d p h i ) hint \equiv (\sum_{i=0}^g C_{g}^{i}d^{g-i}2^ie^i) \quad (mod \quad phi) hint(i=0gCgidgi2iei)(modphi)


c 0 ≡ c h i n t ≡ c ( ∑ i = 0 g C g i d g − i 2 i e i ) m o d ( p h i ) ( m o d n ) c_0\equiv c^{hint} \equiv c^{(\sum_{i=0}^g C_{g}^{i}d^{g-i}2^ie^i) mod(phi)} \quad (mod \quad n) c0chintc(i=0gCgidgi2iei)mod(phi)(modn)
正常rsa解密我们需要求到d,但是hint中有d,我们不好单独求出d,所以这里解密我们需要直接求到c^d mod n 的值,当然也是可以做到的

我们把hint展开,这里我以g=4为例简单说明一下:

在这里插入图片描述

这里根据
e ∗ d ≡ 1 ( m o d p h i ) e*d \equiv 1 \quad (mod \quad phi) ed1(modphi)
可以将hint进行化简,把能消掉的d都消掉,然后把c0乘以只剩e的项的逆,消去该项。


a ∗ a − 1 ≡ 1   ( m o d   n ) a*a^{-1} \equiv 1 \ (mod \ n) aa11 (mod n)
因为我们的目标是c^d,所以我们还需要再乘上e的次方,把d消去,只留下一个d即可,此时的c0就是我们的m

解密思路已经知道了,那么代码附上(主要是要注意一下细节)

from math import comb
import tqdm
from Crypto.Util.number import *
g = 3076
n = 83312970175464153481341766199862672005843884032065729818348527305553537120321898334286778820857584007782243838290886667344499628939342255482077598932803060202743171294065297718653254243096080113955917798479875235479099008156460246096313785233809780625190144353952427715145993502938109965121525650629267636633
c = 54922252484017745069496014860568159008125240774170934714628322133569281169045432175325275210347617669537758197717259611349697543721081934325449079340635504246232236541293093149944995066993503845178538812469017964114279195360759090467455743166522732538087938110470878536150916931323890793579533296737038109125
hint = 68129191967893179827612871900416097308388907834366265926341679123402536261156224529073330624848279371825092696590928029143839271012556877760397316785628777904477907012359031050334429146371709956779213185605783109476303053850250184435018123614021171447233363836078279672500553479950647813364992182178499581909

e = 65537
def attack(n, e, c, hint, g):
    h = hint
    es = [e]
    cs = [c]
    c0 = pow(c, h, n)
    for i in tqdm.tqdm(range(g + 1)):#计算e^n,c^(e^n)保存在列表中,为下面的计算作准备
        cs.append(pow(cs[i], e, n))
        es.append(es[i] * e)
    #cs,es各有g+2个元素
    #es=[e,e^2,...,e^(g+2)]
    #cs=[c,c^e % n,...,c^(g+1) % n]
    for i in tqdm.tqdm(range(g // 2 + 1,g+1)):#取中间右边区域的,因为右边的e比d要大,即右边的只有e而没有d,我们可以通过乘以逆来消掉
        c0 = c0 * inverse(pow(cs[2 * i - g], 2**i*comb(g, i), n), n) % n
    c0 = pow(c0, es[g - 2], n)
    for i in tqdm.tqdm(range(1, g // 2 + 1)):
        c0 = c0 * inverse(pow(cs[2 * i - 1], 2**i*comb(g, i), n), n) % n
    return c0
m = attack(n , e, c, hint, g)
print(long_to_bytes(m))

答案:HZNUCTF{c12044bb-56f4-4730-99ca-a48bd2e00fb8}

tqdm函数是用来显示进度条的,就是起到一个显示作用

在这里插入图片描述

官方wp代码:(这个取得是左边区域的,但是大差不差)

from math import comb
import tqdm
from Crypto.Util.number import *
g = 3076
 
n =
83312970175464153481341766199862672005843884032065729818348527305553537120321898
33428677882085758400778224383829088666734449962893934225548207759893280306020274
31712940652977186532542430960801139559177984798752354790990081564602460963137852
33809780625190144353952427715145993502938109965121525650629267636633
c =
54922252484017745069496014860568159008125240774170934714628322133569281169045432
17532527521034761766953775819771725961134969754372108193432544907934063550424623
22365412930931499449950669935038451785388124690179641142791953607590904674557431
66522732538087938110470878536150916931323890793579533296737038109125
hint =
68129191967893179827612871900416097308388907834366265926341679123402536261156224
52907333062484827937182509269659092802914383927101255687776039731678562877790447
79070123590310503344291463717099567792131856057831094763030538502501844350181236
14021171447233363836078279672500553479950647813364992182178499581909
e = 65537
def attack(n, e, c, hint, g):
   h = hint
   es = [1, e]
   cs = [1, c]
   c0 = pow(c, h, n)
   for i in tqdm.tqdm(range(g + 1)):
       cs.append(pow(cs[i + 1], e, n))
       es.append(es[i + 1] * e)
   for i in tqdm.tqdm(range(g // 2 + 1)):
       c0 = c0 * inverse(pow(cs[g - 2 * i + 1], 2**(g-i)*comb(g, i), n), n) % n
   c0 = pow(c0, es[g - 1], n)
   for i in tqdm.tqdm(range(1, g // 2 + g % 2)):
       c0 = c0 * inverse(pow(cs[2 * i], 2**i*comb(g, i), n), n) % n
   return c0
m = attack(n , e, c, hint, g)
print(long_to_bytes(m))
#HZNUCTF{c12044bb-56f4-4730-99ca-a48bd2e00fb8}

ez_ecdsa

题目:

import os
import ecdsa
import hashlib
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor as xor
import secret

p = getPrime(256)
gen = lambda: p + getPrime(16)
pad = lambda m: m + os.urandom(32 - len(m) % 32)#填充至32位的倍数

key = os.urandom(30)
sk = ecdsa.SigningKey.from_secret_exponent(
    secexp=bytes_to_long(key),
    curve=ecdsa.SECP256k1
)
#生成签名密钥
#这里创建了一个ECDSA签名密钥sk。key是一个字节串,通过bytes_to_long转换为长整型,作为ECDSA的秘密指数。
#curve=ecdsa.SECP256k1指定了使用的椭圆曲线为SECP256k1

sig1 = sk.sign(data=b'welcome to hznuctf2024.', k=gen()).hex()
sig2 = sk.sign(data=b'fuck mxx307.', k=gen()).hex()
#这里对两个不同的消息b'This is the first message.'和b'Here is another message.'进行了签名。
#sk.sign()方法用于生成签名,其中data参数是待签名的数据,k=gen()是一个随机数生成函数,用于生成每次签名所需的随机数。签名结果以十六进制字符串的形式返回。

enc = xor(hashlib.sha512(key).digest(), pad(secret.flag)).hex()#digest()方法会返回一个字节串

print(f"{sig1 = }\n{sig2 = }\n{enc = }")


'''
sig1 = '648e73852c0c95acdc0e1cf2986870f2badf1a73a32e4fa1d9a219f35785e7b758389748b738d0174485b6cbd296dd62a643abcb83d8d16aa3bf75fe54db4576'
sig2 = '70ea9500c595755a1c62d8334e61b97d308da5483f6a1fe8bdfa93212fc5052fb09fa69a31849b990b1d3b0df298d8c4f26541af27c842c2121a088d52a87365'
enc = '5195237c3bc560154cadaaec9f09000ceb465633b4f8e7cc38b7bf0d34cc0ca6e164cefd082eee0502b28abb6e45fcfa68a32e15718e4e51792d1f38add97bd0'
'''

解题分析:

考的是ecdsa签名算法,了解一下
在这里插入图片描述

在这里插入图片描述

其实简单来说就是:

私钥d,公钥Q

通过私钥d对输入的数据m进行签名,得到二元组(r,s)

注意m经常会进行哈希计算,保证一个安全性

公式:
s ≡ k − 1 ( H ( m ) + r ∗ d ) ( m o d n ) s \equiv k^{-1}(H(m)+r*d) \quad (mod \quad n) sk1(H(m)+rd)(modn)

那么看到这题,最后的密文enc是由flag和key哈希值异或的,所以变相的要求key

往上看,key是作为ecdsa签名算法的私钥的,即d,所以我们要根据ecdsa求私钥d

我们首先看一下这个ecdsa采用的是什么哈希算法,搜索一下使用的函数,可以看到是sha1

在这里插入图片描述

那么根据已知的sig1和sig2,有:
s 1 ≡ k 1 − 1 ( H ( m 1 ) + r 1 ∗ d ) ( m o d n ) s1 \equiv k_1^{-1}(H(m_1)+r1*d) \quad (mod \quad n) s1k11(H(m1)+r1d)(modn)

s 2 ≡ k 2 − 1 ( H ( m 2 ) + r 2 ∗ d ) ( m o d n ) s2 \equiv k_2^{-1}(H(m_2)+r2*d) \quad (mod \quad n) s2k21(H(m2)+r2d)(modn)

根据上面两个式子,可以得到:
d ≡ ( ( k 2 − k 1 + H ( m 1 ) ∗ s 1 − 1 − H ( m 2 ) ∗ s 2 − 1 ) ∗ ( r 2 ∗ s 2 − 1 − r 1 ∗ s 1 − 1 ) − 1 ) m o d n d \equiv ((k_2-k_1+H(m_1)*s1^{-1}-H(m_2)*s2^{-1})*(r2*s2^{-1}-r1*s1^{-1})^{-1}) \quad mod \quad n d((k2k1+H(m1)s11H(m2)s21)(r2s21r1s11)1)modn
其中k2和k1是不知道的,但是我们看到k生成的函数gen():p+getPrime(16)

p是固定的,所以k2和k1的差值一定在16位之内,那么做一个爆破即可

解密代码:

from Crypto.Util.number import *
from gmpy2 import *
from hashlib import *

sig1 = '648e73852c0c95acdc0e1cf2986870f2badf1a73a32e4fa1d9a219f35785e7b758389748b738d0174485b6cbd296dd62a643abcb83d8d16aa3bf75fe54db4576'
sig2 = '70ea9500c595755a1c62d8334e61b97d308da5483f6a1fe8bdfa93212fc5052fb09fa69a31849b990b1d3b0df298d8c4f26541af27c842c2121a088d52a87365'
enc = '5195237c3bc560154cadaaec9f09000ceb465633b4f8e7cc38b7bf0d34cc0ca6e164cefd082eee0502b28abb6e45fcfa68a32e15718e4e51792d1f38add97bd0'
p = 0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
n = 0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
m1=b'welcome to hznuctf2024.'
m2=b'fuck mxx307.'
h1=int(sha1(m1).hexdigest(),16)
h2=int(sha1(m2).hexdigest(),16)

# print(len(sig1)) 128
r1=int(sig1[:64],16)
s1=int(sig1[64:],16)
r2=int(sig2[:64],16)
s2=int(sig2[64:],16)

s1_1=invert(s1,n)
s2_2=invert(s2,n)

for i in range(-2**16,2**16):
    d=((i+h1*s1_1-h2*s2_2)*invert(r2*s2_2-r1*s1_1,n)) % n
    if d.bit_length()<=30*8:
        flag=int(sha512(bytes.fromhex(hex(d)[2:])).hexdigest(),16)^int(enc,16)
        if b'HZNUCTF' in long_to_bytes(flag):
            print(long_to_bytes(flag))
            break

p,n的值是根据题目选用的椭圆曲线算法来确定的

椭圆曲线算法(ECC)学习(二)之Secp256k1 - FreeBuf网络安全行业门户

答案:HZNUCTF{2b442c9f-8a28-44f2-9882-833f91f39be8}

ecdsa 笔记 | 独奏の小屋 (hasegawaazusa.github.io)

ECC椭圆曲线算法-3 - Netsharp - 博客园 (cnblogs.com)

307的美团外卖

这题附件忘下了,算了,看wp考的是mt19937,正好xyctf也有一道关于mt的,看那道题去

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值