使用求余运算解简单流密码

使用求余运算解简单流密码

k e y w o r d s : keywords: keywords: DASCTF 2022 三月春季赛 flower cipher流密码求余运算

P r o b l e m Problem Problem

# python3

from secret import flag
import random

# flag = b'flag{%s}' % md5(something).hexdigest()
# note that md5 only have characters 'abcdef' and digits

def Flower(x, key):
    flower = random.randint(0, 4096)
    return x * (key ** 3 + flower)

flag = flag[5:-1]
rounds = len(flag)

L, R = 1, 0
for i in range(rounds):
    L, R = R + Flower(L, flag[i]), L

print(L, R)
'''
15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
'''

A n a l y s i s Analysis Analysis

首先flag明文空间是由小写字母以及数字构成的,因为flag内容是一个md5值,当然我们不需要hash值的原始明文,求得hash值即可;也相当于给出了flag的长度为 32 32 32md5值均是 32 32 32位)

加密过程是将flag的每位字符传入一个类似流密码的加密过程中

def Flower(x, key):
    flower = random.randint(0, 4096)
    return x * (key ** 3 + flower)

L, R = 1, 0
for i in range(len(flag[5:-1])):
    L, R = R + Flower(L, flag[i]), L

加密过程中使用的Flower函数相当于Flower(L, flag[i]) = L * (flag[i] ** 3 + random),那么括号里面的东西才是我们想要知道的,如果能知道括号里面的总值,那么我们也能通过爆破random的大小范围random.randint(0,4096)生成的随机数大小范围是在 0 0 0 4096 4096 4096之间,很好爆破)并且判断总值减去random的值是否能开三次方根(因为key ** 3),如果能那么开三次方根之后就等于真实的flag[i]

那么我们现在需要知道Flower函数括号里的总值,姑且将其设为 k k k

查看加密过程中for循环的作用
L 0 = 1 ;   R 0 = 0 L 1 = R 0 + L 0 ⋅ k 0 ;   R 1 = L 0 L 2 = R 1 + L 1 ⋅ k 1 ;   R 2 = L 1 ⋯ L k = R k − 1 + L k − 1 ⋅ k l a s t ;   R k = L k − 1 L_0 = 1;~R_0=0\\ L_1 = R_0 + L_0\cdot k_0;~R_1=L_0\\ L_2 = R_1 + L_1 \cdot k_1;~R_2=L_1\\ \cdots\\ L_k = R_{k-1} + L_{k-1}\cdot k_{last};~R_{k} = L_{k-1} L0=1; R0=0L1=R0+L0k0; R1=L0L2=R1+L1k1; R2=L1Lk=Rk1+Lk1klast; Rk=Lk1
实际上这里的 R R R的作用相当于保存上一次计算的 L L L,所以我们可以这样来写
L 0 = 1 L 1 = L 0 ⋅ k 0 L 2 = L 0 + L 1 ⋅ k 1 L 3 = L 1 + L 2 ⋅ k 2 ⋯ L k = L k − 2 + L k − 1 ⋅ k l a s t L_0 = 1\\ L_1 = L_0\cdot k_0\\ L_2 = L_0 + L_1\cdot k_1\\ L_3 = L_1 + L_2\cdot k_2\\ \cdots\\ L_k = L_{k-2} + L_{k-1}\cdot k_{last} L0=1L1=L0k0L2=L0+L1k1L3=L1+L2k2Lk=Lk2+Lk1klast
这里 k k k的下标代表着flag[i]的位数i

我们可以清晰地发现每次加密需要的是 L i − 2 L_{i-2} Li2 L i − 1 L_{i-1} Li1;在解密过程中如果我们已知一个等式的 L i , L i − 1 , L i − 2 L_i,L_{i-1},L_{i-2} Li,Li1,Li2这三个数我们就可以求得 k i k_i ki

此时整个加密过程阶数之后我们已知的有 L k L_k Lk R k R_k Rk(相当于 L k − 1 L_{k-1} Lk1),也就是说最后一个加密过程的等式 L k = L k − 2 + L k − 1 ⋅ k l a s t L_k=L_{k-2}+L_{k-1}\cdot k_{last} Lk=Lk2+Lk1klast里面我们呢已知 L k , L k − 1 L_k,L_{k-1} Lk,Lk1,那就想办法知道 L k − 2 L_{k-2} Lk2的大小

求余运算,由于已知的只有两个值,分别在等式的两侧,如果我们计算 L k % L k − 1 L_k\% L_{k-1} Lk%Lk1,那么其结果是不是正好是 L k − 2 L_{k-2} Lk2呢?这个求余的方法可以应用在该加密过程的所有已知 L i L_i Li L i − 1 L_{i-1} Li1的等式中

当最后一个等式的 k k k值求解出来之后,再到倒数第二个等式中正好已知的就有 L i L_i Li L i − 1 L_{i-1} Li1,用同样的办法求解 L i − 2 L_{i-2} Li2即可,以此类推,就可以把所有的 k k k值求出

S o l v i n g   c o d e Solving~code Solving code

from Crypto.Util.number import *
import gmpy2

L_k = 15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899
R_k = 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
flag = ""
while L_k != 1:
    L_k1 = L_k % R_k
    temp = (L_k - L_k1) // R_k 
    for i in range(4096):
        if gmpy2.iroot(temp - i,3)[1]:
            flag += chr(gmpy2.iroot(temp - i,3)[0])
            break
    L_k = R_k
    R_k = L_k1
print(flag[::-1])
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

M3ng@L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值