cryptopals解密之旅3-2

0x00前言
本系列文章将带来cryptocals 这套密码学挑战的write-up.不同于通过上课或者看书的方式学习密码学,这些题目来自于现在生活中一些软件系统和密码构造中的缺陷。
本系列每一个题的wp基本是采用如下结构:题目解释、相关知识点讲解、代码实现及解释,运行测试。代码均采用python3实现,代码实现部分是参考国外大佬ricpacca的,结合自己的理解及成文需要进行部分修改。
第三套一共有八关。上篇文章我们解决了前四关,接下来我们来解答后四关。

0x01
第21题
在这里插入图片描述

题目要求我们实现MT19937,它是Mersenne Twister的一种变体,可以产生32位整数序列
梅森旋转算法(Mersenne twister)是一个伪随机数发生算法。由松本真和西村拓士在1997年开发,基于有限二进制字段上的矩阵线性递归F。可以快速产生高质量的伪随机数,修正了古典随机数发生算法的很多缺陷。
Mersenne Twister这个名字来自周期长度取自梅森素数的这样一个事实。这个算法通常使用两个相近的变体,不同之处在于使用了不同的梅森素数。一个更新的和更常用的是MT19937, 32位字长。还有一个变种是64位版的MT19937-64。对于一个k位的长度,Mersenne Twister会在 [0,2^{k}-1]的区间之间生成离散型均匀分布的随机数。
MT19937的优点包括:
1.周期非常长,达到219937−1。尽管如此长的周期并不必然意味着高质量的伪随机数,但短周期(比如许多旧版本软件包提供的232)确实会带来许多问题。
2. 在1 ≤ k ≤ 623的维度之间都可以均等分布。
3.除了在统计学意义上的不正确的随机数生成器以外,在所有伪随机数生成器法中是最快的(就算法提出时而言)

后面几题都是与随机数相关的题目,所以这里关于随机数再说明一下:
随机数在许多领域中都有着大量应用,例如密码学,游戏,数学统计。随机数主要分两类,分别是确定性随机数和非确定性随机数。非确定性随机数也可称为真随机数(True Random Number Generator, TRNG),主要来源于不可预测的物理或者化学熵源,例如电路噪声。真随机数发生器产生的随机数质量十分高,是最理想的随机数来源,但是由于产生的速度太慢,无法满足目前的信息的传输速度,因此目前确定性随机数依然被广泛使用。确定性随机数发生器也称作伪随机数发生器(Pseudorandom Number Generator,PRNG),它一般是一个随机数生成算法,由于算法是固定的,因此生成的随机数存在许多诸如可预测,质量不高的缺点。

;回到题目,题目提示我们可以在维基百科上找到伪代码,如下图所示
在这里插入图片描述

另外,题目告诉我们使用python,ruby,php等语言,已经内置实现了MT19937,而题目要求我们手动实现。

在实现时会用到一些数据,我们先给出
在这里插入图片描述

梅森旋转算法实际使用的是旋转的广义反馈移位寄存器(Twisted Generalized Feedback Shift Register,GFSR),它主要分初始化,旋转生成随机数以及Xorshift后期处理三个步骤。由于MT19937的梅森算法中生成的随机数为32位,因此算法需要624个32位长的状态。在初始化阶段,即下图的init,工作是将我们获得的随机种子经处理填充到所有的624个状态中
在这里插入图片描述

函数将输入的随机种子赋值给第0个状态,剩余的623个状态则用前一状态值的一系列操作进行赋值更新。当执行完这一算法后,全部的624个状态已经填充完毕,之后梅森算法便可以不断地生成伪随机数。
接着是旋转生成随机数
在这里插入图片描述

MT19937标准中定义A的值为0x9908B0DF。这部分是进行旋转操作。每生成624个伪随机数后,将执行一次上面的函数,重新更新624个状态,为生成下一批624个伪随机数做准备。
之后是第三步后期处理,每个状态都需要经过Xorshift操作以后才能成为最终输出的伪随机数,由于其中几乎都是移位,因此对CPU来说处理起来非常快。
在这里插入图片描述

完整的代码及测试如下
在这里插入图片描述

这样我们就手动实现了MT19937
这里参考了中科院信工所发表的《梅森旋转算法安全性分析及改进》,想进一步了解的同学可以看看这篇论文

0x06
第22题
在这里插入图片描述

要求我们实现以下操作:
在40到1000之间随机等待几秒钟
使用当前的Unix时间戳作为种子
再次等待随机秒数。
返回种子、随机数
题目要求我们能够从输出中破解得到种子
题目还提示我们可以模拟时间,从而避免真的要等待一段随机的时长
第一个函数要实现题目要求我们做的操作
在这里插入图片描述

我们就是要逆向破解得到这个函数返回的随机数。随机数在rng.extract_number()
将该值作为参数传入破解种子的函数
在这里插入图片描述

这里的破解其实很简单,就是不断地测试、改变可能作为种子的时间戳,判断其生成的随机数是否等于第一次生成的随机数,如果是,则说明找到了正确的种子,返回即可
完整的代码及测试如下
在这里插入图片描述

第一行是原种子,第二行是我们暴力破解得到的种子。在实际运行时,会发现过了一会儿才会打印出第二行的结果,这是因为程序正在跑crack_mt19937_seed

0x07
第23题
在这里插入图片描述

有三个关键的点需要把握住:
1.要知道MT 19337完整的内部状态由624个32位整数组成,如果可以克隆这些整数,则可以预测RNG之后生成的数
2.内部状态中的每个整数都按顺序直接与RNG的输出一一对应。
3.内部状态中的每个整数与输出的随机数的对应关系是可逆的关系。换句话说,给定了RNG的输出,我们可以逆向得到与之相关联的内部状态中的整数
综合以上三点,如果我们逆向得到了组成状态的624个整数,只需将这个状态复制到自己的MT 19937 RNG中,就可以得到原RNG的一个有效的克隆,可以预测之后的“随机数”
RNG的输出是容易拿到的,关键是怎么得到内部状态。题目提示我们生成随机数的temper函数是可逆的(就是我们在前面代码中写的extract_number函数,为了与题目相统一,接下来一律称为temper),我们写一个untemper函数,接收MT19937输出并将其转换回MT19937状态数组的相应元素即可。要逆向temper所做的事情,我们需要按照相反的顺序实现temper中的每个操作的逆操作。temper中有两种操作,每种操作应用了两次,一个是对右移值(right-shifted)的XOR,另一个是对左移(left-shifted)值的XOR,并与一个幻数进行与运算,我们只需要逆着实现就可以了
先写两个逆操作的函数
在这里插入图片描述

然后在untemper中调用即可
在这里插入图片描述

接下来就是克隆一个新的RNG
在这里插入图片描述

新的RNG克隆了与原RNG相同的状态
然后在main中分别使用两个RNG生成随机数,便于比较
在这里插入图片描述

完整代码及测试结果如下
在这里插入图片描述

可以看到两个RNG的输出是相同的,或者换句话说,攻击者通过本题介绍的攻击方法,可以克隆得到一个新的RNG用于预测原RNG生成的随机数

0x08
第24题
在这里插入图片描述

题目要求实现:使用16位的种子传入MT 19937 RNG,生成的随机数作为密钥流。以该密钥流对明文加密(明文可以任意,可以加前缀、后缀)。然后暴力测试可能的密钥(16位的种子),对密文解密
题目没有指定加解密的算法,为了简单起见,我们指定加密算法为将RNG生成的密钥流与明文异或,这样解密和加密就是同样的操作了
在这里插入图片描述

暴力测试可能的密钥的函数如下
在这里插入图片描述

在main中构造任意明文,加密得到密文,然后调用find_mt19937_stream_cipher_key,经过暴力测试得到密钥,最后用得到的密钥对密文进行解密
在这里插入图片描述

三个print语句分别是用于打印暴力测试得到的密钥,和原密钥,以及使用暴力破解得到的密钥解密出的明文。
完整代码及测试结果如下
在这里插入图片描述

可以看到,暴力破解得到的密钥和原密钥是相同的,并且密文也被成功解密了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值