已知output
题目:
from Crypto.Util.number import *
flag = b'Spirit{****************************************}'
plaintext = bytes_to_long(flag)
length = plaintext.bit_length()
a = getPrime(length)
b = getPrime(length)
n = getPrime(length)
seed = plaintext
output = []
for i in range(10):
seed = (a*seed+b)%n
output.append(seed)
print("output = ",output)
# output = [9997297986272510947766344959498975323136012075787120721424325775003840341552673589487134830298427997676238039214108, 4943092972488023184271739094993470430272327679424224016751930100362045115374960494124801675393555642497051610643836, 6774612894247319645272578624765063875876643849415903973872536662648051668240882405640569448229188596797636795502471, 9334780454901460926052785252362305555845335155501888087843525321238695716687151256717815518958670595053951084051571, 2615136943375677027346821049033296095071476608523371102901038444464314877549948107134114941301290458464611872942706, 11755491858586722647182265446253701221615594136571038555321378377363341368427070357031882725576677912630050307145062, 7752070270905673490804344757589080653234375679657568428025599872155387643476306575613147681330227562712490805492345, 8402957532602451691327737154745340793606649602871190615837661809359377788072256203797817090151599031273142680590748, 2802440081918604590502596146113670094262600952020687184659605307695151120589816943051322503094363578916773414004662, 5627226318035765837286789021891141596394835871645925685252241680021740265826179768429792645576780380635014113687982]
解题思路:
用公式4求m
解答:
法1:
from Crypto.Util.number import *
def gcd(a,b):
if(b==0):
return a
else:
return gcd(b,a%b)
s = [9997297986272510947766344959498975323136012075787120721424325775003840341552673589487134830298427997676238039214108, 4943092972488023184271739094993470430272327679424224016751930100362045115374960494124801675393555642497051610643836, 6774612894247319645272578624765063875876643849415903973872536662648051668240882405640569448229188596797636795502471, 9334780454901460926052785252362305555845335155501888087843525321238695716687151256717815518958670595053951084051571, 2615136943375677027346821049033296095071476608523371102901038444464314877549948107134114941301290458464611872942706, 11755491858586722647182265446253701221615594136571038555321378377363341368427070357031882725576677912630050307145062, 7752070270905673490804344757589080653234375679657568428025599872155387643476306575613147681330227562712490805492345, 8402957532602451691327737154745340793606649602871190615837661809359377788072256203797817090151599031273142680590748, 2802440081918604590502596146113670094262600952020687184659605307695151120589816943051322503094363578916773414004662, 5627226318035765837286789021891141596394835871645925685252241680021740265826179768429792645576780380635014113687982]
t = []
for i in range(9):
t.append(s[i]-s[i-1])
all_n = []
for i in range(7):
all_n.append(gcd((t[i+1]*t[i-1]-t[i]*t[i]), (t[i+2]*t[i]-t[i+1]*t[i+1])))
MMI = lambda A, n,s=1,t=0,N=0: (n < 2 and t%N or MMI(n, A%n, t, s-A//n*t, N or n),-1)[n<1] #逆元计算
for n in all_n:
n=abs(n)
if n==1:
continue
a=(s[2]-s[1])*MMI((s[1]-s[0]),n)%n
ani=MMI(a,n)
b=(s[1]-a*s[0])%n
seed = (ani*(s[0]-b))%n
plaintext=seed
print(long_to_bytes(plaintext))
'''
b'\x00'
b'\xd6\xce\xc7P)\xf9l\xc7\xc8{h\xf0\xc0\xdcX\xd7q\xc7\xd4\xd1L;\xb7hh*\xc2\xb4\xa3,\xbb\xa1}&\x94Z\xda\x19\x95\xbb\xa6\x93g\xec\xd7\xc6\x15c'
b'\xd6\xce\xc7P)\xf9l\xc7\xc8{h\xf0\xc0\xdcX\xd7q\xc7\xd4\xd1L;\xb7hh*\xc2\xb4\xa3,\xbb\xa1}&\x94Z\xda\x19\x95\xbb\xa6\x93g\xec\xd7\xc6\x15c'
b'Spirit{final__lcg__is__co0m1ing__are_you_ready?}'
b'\xeb\xf7.\xdc!\xe5O\xb4\x11\xed\xf1\xa5\xca\xa1\x9b\x15\xda\x85\xc1\x19\xebGd\n\x93\x04\xb2PW\x9c\xc0^\x8c\xf8\xdd5\xf9\xcf\x1c\xad\x8b\xdd\xde\x1a/\xa6H\x08'
b'\xeb\xf7.\xdc!\xe5O\xb4\x11\xed\xf1\xa5\xca\xa1\x9b\x15\xda\x85\xc1\x19\xebGd\n\x93\x04\xb2PW\x9c\xc0^\x8c\xf8\xdd5\xf9\xcf\x1c\xad\x8b\xdd\xde\x1a/\xa6H\x08'
'''
法2:Grobner基Groebner basis - Scholarpedia
import gmpy2
from sage.all import *
output = [9997297986272510947766344959498975323136012075787120721424325775003840341552673589487134830298427997676238039214108, 4943092972488023184271739094993470430272327679424224016751930100362045115374960494124801675393555642497051610643836, 6774612894247319645272578624765063875876643849415903973872536662648051668240882405640569448229188596797636795502471, 9334780454901460926052785252362305555845335155501888087843525321238695716687151256717815518958670595053951084051571, 2615136943375677027346821049033296095071476608523371102901038444464314877549948107134114941301290458464611872942706, 11755491858586722647182265446253701221615594136571038555321378377363341368427070357031882725576677912630050307145062, 7752070270905673490804344757589080653234375679657568428025599872155387643476306575613147681330227562712490805492345, 8402957532602451691327737154745340793606649602871190615837661809359377788072256203797817090151599031273142680590748, 2802440081918604590502596146113670094262600952020687184659605307695151120589816943051322503094363578916773414004662, 5627226318035765837286789021891141596394835871645925685252241680021740265826179768429792645576780380635014113687982]
R.<a,b> = PolynomialRing(ZZ)
f1 = output[0]*a + b - output[1]
f2 = output[1]*a + b - output[2]
f3 = output[2]*a + b - output[3]
f4 = output[3]*a + b - output[4]
f5 = output[4]*a + b - output[5]
F = [f1,f2,f3,f4,f5]
# 使用F构建一个理想的Ideal。
ideal = Ideal(F)
# 计算Ideal的Gröbner基I
I = ideal.groebner_basis()
a = ZZ(-I[0].univariate_polynomial()(0))
b = ZZ(-I[1].univariate_polynomial()(0))
n = ZZ(I[2])
print(a)
print(b)
print(n)
m = (output[0] - b) * gmpy2.invert(a,n) % n
print(hex(int(m)))
#0x5370697269747b66696e616c5f5f6c63675f5f69735f5f636f306d31696e675f5f6172655f796f755f72656164793f7d
#Spirit{final__lcg__is__co0m1ing__are_you_ready?}
法3:至少需要5个连续的LCG值求各参数
from math import gcd
from functools import reduce
from Crypto.Util.number import *
def crack_unknown_modulus(states):
# 计算差分
diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]
# 计算特定组合
zeroes = [t2 * t0 - t1 * t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]
# 计算 GCD
modulus = abs(reduce(gcd, zeroes))
return modulus
def crack_unknown_multiplier(states, modulus):
# 计算差分
diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]
# 计算乘数 a
a = (diffs[1] * pow(diffs[0], -1, modulus)) % modulus
# 计算增量 c
b = (states[1] - a * states[0]) % modulus
return a, b
# 示例数据
states = [9997297986272510947766344959498975323136012075787120721424325775003840341552673589487134830298427997676238039214108, 4943092972488023184271739094993470430272327679424224016751930100362045115374960494124801675393555642497051610643836, 6774612894247319645272578624765063875876643849415903973872536662648051668240882405640569448229188596797636795502471, 9334780454901460926052785252362305555845335155501888087843525321238695716687151256717815518958670595053951084051571, 2615136943375677027346821049033296095071476608523371102901038444464314877549948107134114941301290458464611872942706, 11755491858586722647182265446253701221615594136571038555321378377363341368427070357031882725576677912630050307145062, 7752070270905673490804344757589080653234375679657568428025599872155387643476306575613147681330227562712490805492345, 8402957532602451691327737154745340793606649602871190615837661809359377788072256203797817090151599031273142680590748, 2802440081918604590502596146113670094262600952020687184659605307695151120589816943051322503094363578916773414004662, 5627226318035765837286789021891141596394835871645925685252241680021740265826179768429792645576780380635014113687982]
# 恢复模数 n
n = crack_unknown_modulus(states)
print(f"Recovered modulus n: {n}")
# 恢复乘数 a 和增量 b
a, b = crack_unknown_multiplier(states, n)
print(f"Recovered multiplier a: {a}")
print(f"Recovered increment b: {b}")
# 恢复种子 seed
seed = (states[0] - b) * pow(a, -1, n) % n
print(f"Recovered seed: {seed}")
plaintext=seed
print(long_to_bytes(plaintext))
'''
Recovered modulus n: 15756647314623328166703743185062683999338522182906057851774027566229961399311096111735183330556202175961402609739909
Recovered multiplier a: 1421031764968400527762460898092137083742564633301039280991459091107942075801014756436528426924261706134389048251788
Recovered increment b: 11545938748867242620537115092757411052463250917387015436216035440161952627398745850382131607456750667325541719714933
Recovered seed: 12842454256006200840327330825396197845927483635849122825220513270564143733836993752723210090679333406611887619653501
b'Spirit{final__lcg__is__co0m1ing__are_you_ready?}'
'''