ctf之lcg算法

本文介绍了如何使用线性同余(LCG)方法解决CTF挑战。详细阐述了线性同余法的数学原理,并通过四个不同类型的题目展示了解题过程,包括反推出初始种子、求解乘数、增量和模数等。解题过程中涉及到扩展欧几里得算法、模逆元计算和最大公约数等数学工具的应用。

线性同余方法(LCG)是一种产生伪随机数的方法。
在这里插入图片描述
线性同余法最重要的是定义了三个整数,乘数 a、增量 b和模数 m,其中a,b,m是产生器设定的常数。
为了方便理解,我打个比方
假设现在有随机数X1=1234,乘数a=2,增量b=3,模数m=1000
那么下一个随机数X2=(2*1234+3)%1000=2471%1000=471

解题用到的公式:

目的 公式
1.Xn+1反推出Xn Xn=(a-1 (Xn+1 - b))%m
2.求a a=((Xn+2-Xn+1)(Xn+1-Xn)-1)%m
3.求b b=(Xn+1 - aXn)%m
4.求m tn=Xn+1-Xnm=gcd((tn+1tn-1 - tntn) , (tntn-2 - tn-1tn-1))

下面是公式证明:
其实公式证明挺复杂的可以最后看,先看看例题也不错哦
公式1:
Xn+1 = aXn + b (mod m)
aXn = Xn+1 - b (mod m)
Xn = a-1 (Xn+1 - b) (mod m)

模逆运算用到扩展欧几里得算法

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

公式2
解先行方程组
Xn+2 = aXn+1 + b (mod m)
Xn+1 = aXn + b (mod m)
Xn+2 - Xn+1 = a(Xn+1-Xn) (mod m)
a = (Xn+2 - Xn+1)(Xn+1 - Xn)-1 (mod m)

公式3
Xn+1 = aXn + b (mod m)
b = Xn+1 - aXn (mod m)

公式4
设tn = Xn+1 - Xn
tn = (aXn+b) - (aXn-1+b) = atn-1(mod m)
tn+1tn-1 - tntn = (aatn-1tn-1 - atn-1atn-1) = 0 (mod m)
即Tn = tn+1tn-1 - tntn是m的倍数,求Tn , Tn-1最大公因数即为m
m = gcd((tn+1tn-1 - tntn) , (tntn-2 - tn-1tn-1))

好了,然后根据lcg算法有六种ctf题型

lcg-1

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

这道题的题意是:
他定义了一个变量叫plaintext,长字节字符串flag转换为整数得到的.
定义了一个整数seed = 33477128523140105764301644224721378964069
seed通过10次lcg转换之后再和plaintext二进制异或得到ciphertext
getPrime是根据输入length产生随机数的函数
思路:
想要得到flag就要知道plaintext
想要知道plaintext只能通过ciphertext = seed ^ plaintex这个表达式推出
而ciphertext==c我们知道,式子中的seed可以通过他给的初始seed,a,b,n运用算法lcg十次得到
然后根据异或的特性求解出plaintext,即plaintext = seed ^ ciphertext
(异或特性,c=a异或b,那么a=b异或c,或者b=a异或c)
解题代码如下

seed = 33477128523140105764301644224721378964069
a = 216636540518719887613942270143367229109002078444183475587474655399326769391
b = 186914533399403414430047931765983818420963789311681346652500920904075344361
n = 155908129777160236018105193822448288416284495517789603884888599242193844951
c = 209481865531297761516458182436122824479565806914713408748457524641378381493

for i in range(10):
    seed = (a*seed+b)%n
plaintext=seed^c
print(long_to_bytes(plaintext))
答案Spirit{0ops!___you_know__LCG!!}

lcg-2

from Crypto.Util.number import *
flag 
评论 19
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值