一、简单的PRNG算法简介
先简单的介绍一下PRNG伪随机数生成算法,网上的教程好多都好复杂,其实对于我们做这道题来讲用不到那么多,只讲最核心的就行:
原理公式:注意那个和,这个其实表示上一次生成的随机数会作用到下一次的随机数生成过程中。
写一段很简单的python代码:
seed=***** #初始随机数种子 Randrom_Num=[] #生成的所有随机数 for i in range(0,n): #表示生成n个随机数 seed = (seed * a + b) % n #这个新的seed计算后就是生成的随机数 Randr_Num.append(seed)
这就给了我们破解这类题的思路。见下面。
Crypto题目如下。
from Crypto.Util.number import bytes_to_long, getPrime from flag import flag a = getPrime(400) b = getPrime(400) n = getPrime(400) flag = bytes_to_long(flag) seed = flag result = [] for i in range(3): seed = (seed * a + b) % n result.append(seed) print(result) print(n) """ [1633086272556604467630727869278140040711140555507257984778706962389364338237377391272504059109316040445365656669071569236, 1206389051656797336925675372412697477889689141174380289961348552709531162180853687116202278892215286522581909284859193494, 664238088423928246579566483655935746695807924062694495126404306361290788561253706421181510449476188038387172722467882193] 2482696698513566590184292572066254640333143735400366745928208268241117181592178071999744746850718587310205478604372055081 """
二、解密过程
想要解密的话必须有连续生成的三个随机数和模数才可以。
三个随机数分别是lcd0,lcd1,lcd2。然后根据生成算法可得下面的一个方程组。
lcg1=(a*lcg0+c)%m
lcg2=(a*lcg1+c)%m
两式相减左边为:lcg2-lcg1 右边为:(a*lcg1+c)-(a*lcg0+c)
化简为: [lcg2-lcg1=a*(lcg1-lcg0) ] %m
根据求余运算规则可知
[a=(lcg2-lcg1)*gmpy2.invert(lcg1-lcg0,m)]%m
此时代入lcg0,lcg1,lcg2之后可求得a
代入lcg1=(a*lcg0+c)%m,把c当作未知数放到等式左边后,式子为:
c=[lcg1-(a*lcg0)]%m
#如果怕自己解到的a,c是错的话可以带入第三个式子去试试。
# 类推lcg3_guess=(a*lcg2+c)%m
# 将求得地lcg3_guess与lcg3比较,如果相等,证明求得的a,c,m为正确值
# 否则,m=m+1,继续验证而一般情况下会把flag当作lcd0输入,所以还需要我们解一元同余式来求最后的flag。
求解一元同余式的方法:照着公式编程就行。下面找的是一次同余式的通解,但是在ctf比赛中实际上只有一个flag,所以只有一个解,因此(a,m)就是1,这样编程的时候公式可以简略好多。
扫描二维码关注公众号,回复:
13292616 查看本文章
三.写出解密脚本
import gmpy2
from Crypto.Util.number import bytes_to_long, getPrime, long_to_bytes
n=2482696698513566590184292572066254640333143735400366745928208268241117181592178071999744746850718587310205478604372055081
result=[1633086272556604467630727869278140040711140555507257984778706962389364338237377391272504059109316040445365656669071569236, 1206389051656797336925675372412697477889689141174380289961348552709531162180853687116202278892215286522581909284859193494, 664238088423928246579566483655935746695807924062694495126404306361290788561253706421181510449476188038387172722467882193]
a=((result[2]-result[1])*gmpy2.invert(result[1]-result[0],n))%n
b=(result[1]-(a*result[0]))%n
#求解一元同余式得到flag
flag=(((result[0]-b))*gmpy2.invert(a,n)+n)%n
print(long_to_bytes(flag))