题目描述:
from Crypto.Util.number import *
from gmpy2 import next_prime, iroot
from flag import flag
assert flag[0:4]==b'flag'
m = bytes_to_long(flag)
assert size(m)<500
p = getPrime(512)
q = next_prime(p)
n = p * q
print('n=', n>>520)
e = 0x10001
c = pow(m, e, n)
print('c=', c)
n= 28576274811010794362153160897556935178530640825011441539841241257190782139295561904323347128956873569754645071205043238985141474388531008367238218822591
c= 49502875285578675438052554215266678403659290915102322948363030271494959804587081871467110614683972929037615883922743651431683465100061968204901334627149795829429950385848753728500177164800064208215503246868631076011505268371936586645321659884527055007299822625570713613996139223348709621258028349513737798120
题目分析:
对n开方可得到p的高位,之后爆破得完整p
其实提示的很明显,size(m)<500<512说明只需求出p即可得到flag
高位攻击啥的也不用想,n都不知道,只能往简单点想
from Crypto.Util.number import *
from gmpy2 import *
e = 0x10001
n= 28576274811010794362153160897556935178530640825011441539841241257190782139295561904323347128956873569754645071205043238985141474388531008367238218822591
c= 49502875285578675438052554215266678403659290915102322948363030271494959804587081871467110614683972929037615883922743651431683465100061968204901334627149795829429950385848753728500177164800064208215503246868631076011505268371936586645321659884527055007299822625570713613996139223348709621258028349513737798120
n_high = n << 520
p_high = iroot(n_high,2)[0]
for i in range(1000):
p= p_high + i
phi = (p - 1)
d = invert(e, phi)
flag=long_to_bytes(pow(c,d,p))
if b'flag' in flag:
print(flag)
break
# flag{90b344ca-867d-002e-915c-4a897faf0bbe}
题目描述:
from Crypto.Util.number import *
import random
import base64
import os
flag = b'xxx'
flag = base64.b64encode(flag)
part_size = len(flag)//3
part1 = flag[:part_size]
part2 = flag[part_size:2 * part_size]
part3 = flag[2 * part_size:]
def gen_keys(bits):
while True:
p = getPrime(bits)
q = getPrime(bits)
n = p * q
k = random.randint(1, n)
if pow(q ** 2 * k, (p - 1) // 2, p) + pow(p ** 2 * k, (q - 1) // 2, q) == p + q - 2:
break
return p, q, n, k
def bit_enc(m,n):
enc = []
m = bin(bytes_to_long(m))[2:]
for x in m:
while True:
r = random.randint(1, n)
if GCD(r, k) == 1:
enc.append((k ** int(x) * r ** 2) % n)
break
return enc
if __name__ == '__main__':
f = open('stepbystep.txt','w')
f.write(f'part_size = {part_size}\n') # 32
p, q, n, k = gen_keys(1024)
y = p ^ (bytes_to_long(part1) << 0x100)
f.write(f'n = {n}\n')
f.write(f'y = {y}\n')
enc1 = bit_enc(part2,n)
f.write(f'enc1 = {enc1}\n')
e = 3
r = getPrime(1024)
m = bytes_to_long(part3 + os.urandom(128))
M = m % r
f.write(f'r = {r}\n')
f.write(f'M = {M}\n')
enc2 = pow(m, e, n)
f.write(f'enc2 = {enc2}\n')
题目分析:
每个part长度为32
part1:
bytes_to_long(part1)为32 * 8 = 256bit,故通过y可以得到p的高512位和低256位,高位攻击得完整p,之后和y对应位异或即可得到part1
n = 28170615394813994128829444311922294768047711140557403853945487107089509134737767942656361548230221829951460844271639575394883663959935517401286468610803533794281322932272016151070004303694003064267127894498582758474889399072435632149814773794006700377495059535551601562497404157228212268055301420382159240876926718366155907065534007141933306379265213201601388196980959461243178574169497366868119687674891554278269534759630337252574501733517956676373291013127781435489132751470026441547613876124640645867844110455115246109355929378020562498143759261535211073747144498765678339037517382156239422037334011910477313579931
y = 159220553107177193400023378107257900962478698517628796905876914005522464561698874246291191230998317763194901894991385290134307075261722076436131488895536910117912445041560442858379826501161163372467275224931272546634069502187842680578039864204499755434023932362315829340273816781101788682876410192428287564079
p_ = ((y >> 512) << 512) + (y & (2 ^ 256 - 1))
PR.<x> = PolynomialRing(Zmod(n))
f = p_ + (x * 2 ** 256)
f = f.monic()
p0 = f.small_roots(2 ^ 256,0.4)
print(p_ + p0[0] * 2 ** 256)
p = 159220553107177193400023378107257900962478698517628796905876914005522464561698874246291191230998317763194901894991385290134307075261722076436131488895536914601862873373189346623370102585921882621795643375613240095719969918295959844527488766867194677670844144950629130942802580496956921624007957883073349196079
part1 = ((y // 2 ** 256) % 2 ** 256) ^^ ((p // 2 ** 256) % 2 ** 256)
print(long_to_bytes(part1))
# ZmxhZ3s4ZjYzNzc3MTMyZWRkNmJlNmM2
part2:
二次剩余,又是二次剩余
二次剩余知识导入:
- 设m是正整数,若同余式:
x 2 ≡ a m o d p a ≡ x 2 m o d p 其中 , ( a , p ) = 1 x^{2} \equiv a \mod p \\ a \equiv x^{2} \mod p \\ \\ 其中,(a,p) = 1 x2≡amodpa≡x2modp其中,(a,p)=1
有解,则a叫做模p的二次剩余(或平方剩余),否则为二次非剩余(平方非剩余)- 勒让得符号之运算性质(欧拉判别法则):
( a p ) = a p − 1 2 = { 1 , a 是模 p 的二次剩余, x 有解 − 1 , a 是模 p 的二次非剩余, x 无解 0 , p ∣ a ( a 比 p 大 ) \left ( \frac{a}{p} \right ) = a^{\frac{p-1}{2}} = \begin{cases} \quad1,a是模p的二次剩余,x有解\\ -1,a是模p的二次非剩余,x无解\\ \quad0,p|a (a比p大) \end{cases} (pa)=a2p−1=⎩ ⎨ ⎧1,a是模p的二次剩余,x有解−1,a是模p的二次非剩余,x无解0,p∣a(a比p大)
pow(p ** 2 * k, (p - 1) // 2, p) + pow(q ** 2 * k, (q - 1) // 2, q) == p + q - 2
从这串中可以得出:
( k ∗ q 2 ) p − 1 2 % p + ( k ∗ p 2 ) q − 1 2 % q = p + q − 2 ⇒ (费马小定理) ( k ∗ q 2 ) p − 1 2 ≡ k p − 1 2 ≡ − 1 m o d p = p − 1 ( k ∗ p 2 ) q − 1 2 ≡ k q − 1 2 ≡ − 1 m o d q = q − 1 故 k 是模 p 和 q 的二次剩余 (k * q^{2}) ^ {\frac{p - 1}{2}} \%p + (k * p^{2}) ^ {\frac{q - 1}{2}}\%q= p + q - 2\\ \Rightarrow (费马小定理)\\ (k * q^{2}) ^ {\frac{p - 1}{2}} \equiv k ^ {\frac{p-1}{2}} \equiv -1 \mod p = p - 1\\ (k * p^{2}) ^ {\frac{q - 1}{2}} \equiv k ^ {\frac{q-1}{2}} \equiv -1 \mod q = q - 1\\ 故k是模p和q的二次剩余\\ (k∗q2)2p−1%p+(k∗p2)2q−1%q=p+q−2⇒(费马小定理)(k∗q2)2p−1≡k2p−1≡−1modp=p−1(k∗p2)2q−1≡k2q−1≡−1modq=q−1故k是模p和q的二次剩余
enc.append((k ** int(x) * r ** 2) % n)
从这串我们可以得出:
k x ∗ r 2 = { k ∗ r 2 , x = 1 r 2 , x = 0 ⇒ (费马小定理) ( k ∗ r 2 ) p − 1 2 ≡ − 1 m o d p ( r 2 ) p − 1 2 ≡ 1 m o d p 若 p o w ( i , ( p − 1 ) / / 2 , p ) = − 1 , 则 x = 1 若 p o w ( i , ( p − 1 ) / / 2 , p ) = 1 , 则 x = 0 其中 i 为 e n c 1 中的元素,由此可得到 p a r t 2 k^x * r^2 = \begin{cases} k * r^2 , \ x = 1\\ \ \ \ \ \ \ r^2, \ x = 0 \end{cases}\\ \Rightarrow(费马小定理)\\ (k * r^2)^\frac{p-1}{2} \equiv -1 \mod p\\ \ \ \ \ (r^2)^\frac{p-1}{2} \equiv \ \ \ \ 1 \mod p\\ 若pow(i,(p-1)//2,p) = -1,则x = 1\\ 若pow(i,(p-1)//2,p) = \ \ \ 1, 则x = 0\\\\ 其中i为enc1中的元素,由此可得到part2 kx∗r2={k∗r2, x=1 r2, x=0⇒(费马小定理)(k∗r2)2p−1≡−1modp (r2)2p−1≡ 1modp若pow(i,(p−1)//2,p)=−1,则x=1若pow(i,(p−1)//2,p)= 1,则x=0其中i为enc1中的元素,由此可得到part2
with open('stepbystep.txt') as f:
exec(f.read())
part2 = ''
for i in enc1:
if pow(i,(p-1)//2,p) == 1:
part2 += '0'
else:
part2 += '1'
part2 = int(part2,2)
print(long_to_bytes(part2))
# Yjg4NGQyMTEyMjI5YWI2OWEwYjNkOTgz
part3:
普普通通的RSA求解,p,q,n第一部分已求出
enc2 = 3308959603655783037626701651449897306691054491531277011007239956503226856416291050447522118208505181328835654445067869891209022570372449235908057926971720202776819863989791528582562270047426782371075056370483172178853004208276586218043687123444373535519007051969960162889822736022485151723842157816601130568321361182105375979062860034971261145125640309251608819317332361754077108485716298746870151841624987872455719817354570871513465617937552265477428311051737704837212011740627884815342732601532604444076319807464313504969470749988374578293008881546119868431456512406342629832650219747911308702089872865087547016692
phi = (p - 1) * (q - 1)
d = invert(3,phi)
print(long_to_bytes(pow(enc2,d,n)))
# Yzc4NDZjYWMwYjA2NjQ2OGJhNmIwfQ==
唉,这M,r也没用到啊,出题人应该是想要我们用下面这种解法。这种解法挺不错,不过我并有没想到。
m = M + k ∗ r e n c 2 ≡ ( M + k ∗ r ) 3 m o d n 一个未知数,解方程 m = M + k * r\\ enc2 \equiv (M + k * r) ^ 3 \mod n\\ 一个未知数,解方程\\ m=M+k∗renc2≡(M+k∗r)3modn一个未知数,解方程
from Crypto.Util.number import *
r = 93549208091522943157523889855147971756339952408014900465237079549147321642184605352106076825075471647946551417457797445371594401297547607606554921501239662351004696055416766322360074764155873771691904894277891317076059387107629281872952247903070858893854519963946004933092428964179404235822710307390762443997
n = 28170615394813994128829444311922294768047711140557403853945487107089509134737767942656361548230221829951460844271639575394883663959935517401286468610803533794281322932272016151070004303694003064267127894498582758474889399072435632149814773794006700377495059535551601562497404157228212268055301420382159240876926718366155907065534007141933306379265213201601388196980959461243178574169497366868119687674891554278269534759630337252574501733517956676373291013127781435489132751470026441547613876124640645867844110455115246109355929378020562498143759261535211073747144498765678339037517382156239422037334011910477313579931
M = 41114562773057591509703798019081726715938195388792207483716010974789826658609043370184495922299754629166062481798971234172682345725464787827933687171665115253731281252387251668805119315677910253579731618701676377111463086179935234982471957816896707984220800374578967269143044956222576420557100741943571288295
enc2 = 3308959603655783037626701651449897306691054491531277011007239956503226856416291050447522118208505181328835654445067869891209022570372449235908057926971720202776819863989791528582562270047426782371075056370483172178853004208276586218043687123444373535519007051969960162889822736022485151723842157816601130568321361182105375979062860034971261145125640309251608819317332361754077108485716298746870151841624987872455719817354570871513465617937552265477428311051737704837212011740627884815342732601532604444076319807464313504969470749988374578293008881546119868431456512406342629832650219747911308702089872865087547016692
PR.<k> = PolynomialRing(Zmod(n))
f = (M + k * r) ** 3 - enc2
f = f.monic()
kk = f.small_roots(2 ** 256)[0]
m = M + kk * r
print(long_to_bytes(int(m)))
# Yzc4NDZjYWMwYjA2NjQ2OGJhNmIwfQ==
之后每一部分拼接base64解密得到flag
flag{8f63777132edd6be6c6b884d2112229ab69a0b3d983c7846cac0b066468ba6b0}
题目来源:https://blog.csdn.net/weixin_52640415/article/details/133466943?spm=1001.2014.3001.5502
(跟着别人博客学习是一种很好的提升方法,目前来说通常没有比赛我都是刷别人博客做题)
题目描述:
from Crypto.Util.number import*
from secret import flag
assert(flag[0:5]==b"flag{" )
assert(flag[-1:]==b"}" )
flag = flag[7:-1]
print(len(flag))
class LCG:
def __init__(self):
self.a = getRandomNBitInteger(32)
self.b = getRandomNBitInteger(32)
self.c = getRandomNBitInteger(32)
self.m = getPrime(32)
self.seed1 = getRandomNBitInteger(32)
self.seed2 = getRandomNBitInteger(32)
def next(self):
tmp = self.seed2
self.seed2 = (self.a*self.seed1+self.b*self.seed2 +self.c) % self.m
self.seed1 = tmp
#return self.seed2 >> 16
return self.seed2 #从给出的T来看,是32位的
def output(self):
print("m = {}".format(self.m))
print("self.seed1= {}".format(self.seed1))
print("self.seed2= {}".format(self.seed2))
L = LCG()
T = [0]
for k in range(random(10)):
T.append(L.next())
L.output()
enc = []
for i in range(9):
tmp = bytes_to_long(flag[i*4:i*4+4])
tt = L.next()
T.append(tt)
enc.append(tmp^(tt>>16))
print('T = ',T[:6])
print('enc = ',enc)
print("Have a good time!")
'''
m = 3533156827
self.seed1 = 2970464585
self.seed2 = 3350124366
enc = [909619317, 912378641, 761422938, 841844503, 1701111746, 1701194992, 959752815, 892545567, 1667598316]
T = [0,3180180532,86337434,1850726346,2970464585,3350124366]
'''
题目分析:
二元LCG
import gmpy2
from Crypto.Util.number import *
m = 3533156827
enc = [909619317, 912378641, 761422938, 841844503, 1701111746, 1701194992, 959752815, 892545567, 1667598316]
T = [0,3180180532,86337434,1850726346,2970464585,3350124366]
data = T[1:]
n = m
tmp = [0]
for i in range(1,5):
tmp.append(data[i] - data[i-1])
b = ((tmp[3] * tmp[2] - tmp[4] * tmp[1]) * gmpy2.invert(tmp[2] * tmp[2] - tmp[3] * tmp[1],n)) % n
a = ((tmp[3] - b * tmp[2]) * gmpy2.invert(tmp[1],n)) % n
c = (data[2] - b * data[1] - a * data[0]) % n
print(a)
print(b)
print(c)
# b = 2578155191
# a = 3222280379
# c = 3272724155
未知数都出来了,那之后就是简单的异或了
b = 2578155191
a = 3222280379
c = 3272724155
seed1 = 2970464585
seed2 = 3350124366
m = b''
for i in range(9):
tmp = seed2
seed2 = (a * seed1 + b * seed2 + c) % n
seed1 = tmp
m += long_to_bytes(enc[i] ^ (seed2 >> 16))
print(m)
# flag{67456ac9-b362-11ed-aef7-94085339ce84}
记录佬求未知数的方法:
groebner_basis()第二次遇到,下次多个式子解方程用它
m = 3533156827
seed1 = 2970464585
seed2 = 3350124366
enc = [909619317, 912378641, 761422938, 841844503, 1701111746, 1701194992, 959752815, 892545567, 1667598316]
T = [0,3180180532,86337434,1850726346,2970464585,3350124366]
T = T[1:]
P.<a,b,c,s1,s2> = PolynomialRing(Zmod(m))
G = []
for i in range(len(T)):
s1,s2 = s2,a * s1 + b * s2 + c
G.append(s2 - T[i])
B = Ideal(G).groebner_basis()
print(B)
res = [x.constant_coefficient() for x in B]
print(res)
a = -res[0] % m
b = -res[1] % m
c = -res[2] % m
print(a)
print(b)
print(c)
浅记一下:
考点:
高位,二次剩余,解方程,二元LCG,groebner_basis()求参
二次剩余,第二次遇到,更熟悉了,期待再一次和它相遇