lcg(线性同余生成器)原理加各种题目(第一部分)

补充:

 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] #逆元计算

·“A”是输入的整数。 n’是模数。 ·“s’是一个累加器,默认为1。 ·“t”是另一个累加器,默认为0. ·“N’也是一个累加器,默认为0.

原理及相关推导

由于打出来稍显困难,决定将就一下。

01

题目

 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 = 33477128523140105764301644224721378964069
 print("seed = ",seed)
 for i in range(10):
     seed = (a*seed+b)%n  #进行了十次循环
 ciphertext = seed^plaintext  #一次异或
 print("a = ",a)
 print("b = ",b)
 print("n = ",n)
 print("c = ",ciphertext)
 ​
 # seed =  33477128523140105764301644224721378964069
 # a =  216636540518719887613942270143367229109002078444183475587474655399326769391
 # b =  186914533399403414430047931765983818420963789311681346652500920904075344361
 # n =  155908129777160236018105193822448288416284495517789603884888599242193844951
 # c =  209481865531297761516458182436122824479565806914713408748457524641378381493
 ​

exp:

按题目中过程进行

 from Crypto.Util.number import *
 seed = 33477128523140105764301644224721378964069
 a = 216636540518719887613942270143367229109002078444183475587474655399326769391
 b = 186914533399403414430047931765983818420963789311681346652500920904075344361
 n = 155908129777160236018105193822448288416284495517789603884888599242193844951
 c = 209481865531297761516458182436122824479565806914713408748457524641378381493
 ​
 for i in range(10):
     seed = (a * seed + b) % n
 print(seed)
 m = seed ^ c
 print(m)
 print(long_to_bytes(m))
 # 66922225691609264283867072422037270235122544465805107339080357133935022024
 # 147424144810829416246263598495658483373775464141840154829404726417260880253
 # b'Spirit{0ops!___you_know__LCG!!}'

02(已知后项求前项)

题目:

 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
 ​
 for i in range(10):
     seed = (a*seed+b)%n
 ciphertext = seed
 ​
 print("a = ",a)
 print("b = ",b)
 print("n = ",n)
 print("c = ",ciphertext)
 ​
 # a =  59398519837969938359106832224056187683937568250770488082448642852427682484407513407602969
 # b =  32787000674666987602016858366912565306237308217749461581158833948068732710645816477126137
 # n =  43520375935212094874930431059580037292338304730539718469760580887565958566208139467751467
 # c =  8594514452808046357337682911504074858048299513743867887936794439125949418153561841842276

只需要将题中过程逆向推回去,应用公式1

 import gmpy2
 from Crypto.Util.number import *
 a = 59398519837969938359106832224056187683937568250770488082448642852427682484407513407602969
 b = 32787000674666987602016858366912565306237308217749461581158833948068732710645816477126137
 n = 43520375935212094874930431059580037292338304730539718469760580887565958566208139467751467
 c = 8594514452808046357337682911504074858048299513743867887936794439125949418153561841842276
 t = gmpy2.invert(a, n)
 seed = c
 for i in range(10):
     seed = t * (seed - b) % n
 print(long_to_bytes(seed))
 #b'Spirit{Orzzz__number_the0ry_master!!}'

03(求增量b)

 from Crypto.Util.number import *
 flag = b'Spirit{*********************}'
 plaintext = bytes_to_long(flag)
 length = plaintext.bit_length()
 ​
 a = getPrime(length)
 seed = getPrime(length)
 n = getPrime(length)
 ​
 b = plaintext
 ​
 output = []
 for i in range(10):
     seed = (a*seed+b)%n
     output.append(seed)
 ciphertext = seed
 ​
 print("a = ",a)
 print("n = ",n)
 print("output1 = ",output[6])
 print("output2 = ",output[7])
 ​
 # a =  3227817955364471534349157142678648291258297398767210469734127072571531
 # n =  2731559135349690299261470294200742325021575620377673492747570362484359
 # output1 =  56589787378668192618096432693925935599152815634076528548991768641673
 # output2 =  2551791066380515596393984193995180671839531603273409907026871637002460

exp:

 from Crypto.Util.number import *
 ​
 a = 3227817955364471534349157142678648291258297398767210469734127072571531
 n = 2731559135349690299261470294200742325021575620377673492747570362484359
 output1 = 56589787378668192618096432693925935599152815634076528548991768641673
 output2 = 2551791066380515596393984193995180671839531603273409907026871637002460
 b = (output2 - a * output1) % n
 print(long_to_bytes(b))
 #b'Spirit{Y0u_@r3_g00d_at__math}'

04(未知a,b求seed)

 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("n = ",n)
 print("output = ",output)
 # n =  714326667532888136341930300469812503108568533171958701229258381897431946521867367344505142446819
 # output =  [683884150135567569054700309393082274015273418755015984639210872641629102776137288905334345358223, 285126221039239401347664578761309935673889193236512702131697050766454881029340147180552409870425, 276893085775448203669487661735680485319995668779836512706851431217470824660349740546793492847822, 670041467944152108349892479463033808393249475608933110640580388877206700116661070302382578388629, 122640993538161410588195475312610802051543155060328971488277224112081166784263153107636108815824, 695403107966797625391061914491496301998976621394944936827202540832952594905520247784142392337171, 108297989103402878258100342544600235524390749601427490182149765480916965811652000881230504838949, 3348901603647903020607356217291999644800579775392251732059562193080862524671584235203807354488, 632094372828241320671255647451901056399237760301503199444470380543753167478243100611604222284853, 54758061879225024125896909645034267106973514243188358677311238070832154883782028437203621709276]

exp:

 import gmpy2
 from Crypto.Util.number import *
 n = 714326667532888136341930300469812503108568533171958701229258381897431946521867367344505142446819
 output = [683884150135567569054700309393082274015273418755015984639210872641629102776137288905334345358223, 285126221039239401347664578761309935673889193236512702131697050766454881029340147180552409870425, 276893085775448203669487661735680485319995668779836512706851431217470824660349740546793492847822, 670041467944152108349892479463033808393249475608933110640580388877206700116661070302382578388629, 122640993538161410588195475312610802051543155060328971488277224112081166784263153107636108815824, 695403107966797625391061914491496301998976621394944936827202540832952594905520247784142392337171, 108297989103402878258100342544600235524390749601427490182149765480916965811652000881230504838949, 3348901603647903020607356217291999644800579775392251732059562193080862524671584235203807354488, 632094372828241320671255647451901056399237760301503199444470380543753167478243100611604222284853, 54758061879225024125896909645034267106973514243188358677311238070832154883782028437203621709276]
 #公式二求a
 t = gmpy2.invert((output[2] - output[1]), n)
 a = t * (output[3] - output[2]) % n
 #公式三求b
 b = (output[2] - a * output[1]) % n
 #公式一求初始值
 aa = gmpy2.invert(a, n)
 seed = aa * (output[0] - b) % n#注意这里的应为第一个但是实际上output收录的第一个就是第二个故应写为output[0]
 print(seed)
 print(long_to_bytes(seed))
 #b'Spirit{Gr3at__J0b!_You_can_be___better!}'

05(未知a,b,n求seed)

 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]

exp:

只有seed的值了,明显只能使用公式4

这个题我只选取了其中的某个数直接求,发现中间的模逆运算无法将进行,

以下是我搜到的脚本:

 from Crypto.Util.number import *
 import gmpy2
 ​
 output =  [9997297986272510947766344959498975323136012075787120721424325775003840341552673589487134830298427997676238039214108, 4943092972488023184271739094993470430272327679424224016751930100362045115374960494124801675393555642497051610643836, 6774612894247319645272578624765063875876643849415903973872536662648051668240882405640569448229188596797636795502471, 9334780454901460926052785252362305555845335155501888087843525321238695716687151256717815518958670595053951084051571, 2615136943375677027346821049033296095071476608523371102901038444464314877549948107134114941301290458464611872942706, 11755491858586722647182265446253701221615594136571038555321378377363341368427070357031882725576677912630050307145062, 7752070270905673490804344757589080653234375679657568428025599872155387643476306575613147681330227562712490805492345, 8402957532602451691327737154745340793606649602871190615837661809359377788072256203797817090151599031273142680590748, 2802440081918604590502596146113670094262600952020687184659605307695151120589816943051322503094363578916773414004662, 5627226318035765837286789021891141596394835871645925685252241680021740265826179768429792645576780380635014113687982]
 ​
 t = []
 for i in range(1,len(output)):
     t.append(output[i]-output[i-1])#tn
 ​
 T = []
 for i in range(1,len(t)-1):
     T.append(t[i+1]*t[i-1] - t[i]**2)#Tn
 ​
 m = []
 for i in range(len(T)-1):
     mm = gmpy2.gcd(T[i],T[i+1])#这里是公式四进行的
     if isPrime(mm):
         m.append(int(mm))
     else:
         for i in range(1,100):#该处相当于除以最大公约数
             if isPrime(mm // i):
                 mm = mm // i
                 m.append(int(mm))
                 break
 print(m)
 ​
 for i in m:
     if isPrime(i):
         a = gmpy2.invert(t[0],i) * t[1] % i
         b = output[1] - a*output[0] % i
         a_ = gmpy2.invert(a,i)
 ​
         seed = a_ * (output[0]-b) % i
         flag = long_to_bytes(seed)
         if b'Spirit' in flag:
             print(flag)

官方wp:

 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))

参考:LCG | DexterJie'Blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值