cryptopals解密之旅 (三)

0x00前言

本系列文章将带来cryptocals 这套密码学挑战的write-up.不同于通过上课或者看书的方式学习密码学,这些题目来自于现在生活中一些软件系统和密码构造中的缺陷。

本系列每一个题的wp基本是采用如下结构:题目解释、相关知识点讲解、代码实现及解释,运行测试。代码均采用python3实现,代码实现部分是参考国外大佬ricpacca的,结合自己的理解及成文需要进行部分修改。

第二套一共有八关。

 

第二套题目

cryptopals解密之旅 (三)_第1张图片

主要是和分组密码相关的

 

  • 0x01

  • 先来看第9题

 

cryptopals解密之旅 (三)_第2张图片

对于分组密码而言,通过会将整数的块的明文转为密文,但是我们一般碰到的消息长度不会是块的整数倍的,这时候就需要将其填充(padding)成块的整数倍大小。最流行的一种填充模式是PKCS#7

题目要求我们用代码实现PKCS#7

 

在分组加密算法中,进行分组时,划分后最后一组如果不够块大小时,需要填充,常见的填充模式有PKCS#5,PKCS#7。对于PKCS#5而言,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间。

填充字符串由一个字节序列组成,填充的字节都是一个相同的字节,该字节的值就是要填充的字节的个数。

比如要填充7个字节,则需要填充7个0x7

 

 

实现一个函数,用于进行PKCS#7填充。如果消息长度等于块大小的话,无需填充,直接返回;否则先计算需要填充的长度,然后将其附加在原消息之后

cryptopals解密之旅 (三)_第3张图片

实现一个函数,用于判断数据是否经过PKCS#7填充。假设是正常实现的填充,将所填充的字符串存入padding,然后根据“填充的字节都是一个相同的字节,该字节的值就是要填充的字节的个数“进行检查。如果检查通过,则是经过PKCS#7填充的。

可以对应实现一个函数,实现逆PKCS#7填充,也就是将被填充的数据还原,通过is_pkcs_padded函数检查,如果没被填充过则直接返回,如果被填充过,则直接截取被填充后的字符串的前一部分(即原始数据)返回

cryptopals解密之旅 (三)_第4张图片

完整代码及执行结果如下

cryptopals解密之旅 (三)_第5张图片

顺便使用断言测试pacs7_unpad是否可用

cryptopals解密之旅 (三)_第6张图片

 

没有报错,说明正常执行

  • 实验推荐

CTFCrypto练习之分组密码 

http://hetianlab.com/expc.do?ec=ECID172.19.104.182015011915475800001(通过本实验的学习,你能够了解CTF竞赛中的密码学题型,掌握分组密码以及AES加密算法,学会分组密码ECB模式的攻击方法)

 

  • 0x02

第10题

 

cryptopals解密之旅 (三)_第7张图片

要求我们实现CBC模式,并对给出的文本文件进行解密。并提示我们复用之前写过的EBC代码(不过此时是写加密的函数)和XOR代码。还给出了密钥和IV

 

这里涉及的知识点是CBC模式

其中文全称是密码分组链接模式(Cipher Block Chaining (CBC))

这种模式是先将明文切分成若干小段,然后每一小段与初始块(IV)或者上一段的密文段进行异或运算后,再与密钥进行加密。如下所示

cryptopals解密之旅 (三)_第8张图片

实现ASES-ECB加密函数。数据加密前常需要PKCS#7填充。

 

异或函数

 

实现AES-CBC加密函数,其接收的参数就是明文、密钥、IV

分块进行处理,分块后先进行填充padding,再进行与IV或上一个密文块进行异或,然后AES-ECB加密(即前面将CBC实现图中的加密器部分),接着处理下一块

cryptopals解密之旅 (三)_第9张图片

实现AES-CBC解密函数,可以返回填充或未填充的明文。同样需要分块进行,和加密函数倒着来就行,先AES-ECB解密,然后XOR。

cryptopals解密之旅 (三)_第10张图片

cryptopals解密之旅 (三)_第11张图片

 完整代码及执行后得到的明文如下

 

cryptopals解密之旅 (三)_第12张图片

  • 实验推荐

CBC字节翻转攻击 

http://hetianlab.com/expc.do?ec=ECIDf328-1dc9-464c-918b-543b4a2d6590 

(通过该实验了解CBC模式实现流程、异或运算的高级应用、python中crypto库的使用以及cbc字节翻转攻击的原理与代码实现)

  • 0x03

第11题

 

cryptopals解密之旅 (三)_第13张图片

要求写一个函数实现生成随机的16字节AES 密钥

写一个函数根据随机密钥进行加密,在加密前在明文的前后各添加5到10字节随机值,随机选取加密方式为ECB或CBC,如果是CBC,还需要选择随机的IV

要求我们能够写一个函数,能够判断某个被加密的块是使用CBC还是ECB模式

 

根据填充后明文,随机生成的key,随机决定采用的模式(ECB或CBC)进行加密,如果是CBC的话,其IV也是随机的,所以用Random.new()

 

该数据填充上5到10字节随机数作为前缀和后缀

 

根据count_aes_ecb_repetitions返回的结果来判断是ECB还是CBC加密模式

cryptopals解密之旅 (三)_第14张图片

 

 

我们选择重复的输入数据,这样我们就可以结合ECB的特点来探测其是否为ECB模式,不是ECB则是CBC模式。

 

cryptopals解密之旅 (三)_第15张图片

 

完整代码及执行断言结果如下

cryptopals解密之旅 (三)_第16张图片

 没有报错,说明写的这些函数都能成功执行。

 

 

  • 0x04

第12题

cryptopals解密之旅 (三)_第17张图片

 该函数使用ECB模式,使用同一个但是未知的key

在加密前,在明文后附加给出的字符串(在附加之前先对该字符串base64解密我们有一个函数可以计算AES-128-ECB(your-string || unknown-string, random-key),而ECB Byte at a time技术可以让我们需要控制your-string,就可以在不知道random-key的情况下得到unkown-string。

基本流程如下:

1.将相同的字符串字节传入函数1,从传入1个字节(A)开始,然后AA,AAA。。。直到找到密文的块的大小

2.测试加密模式是否为ECB

3. 知道块的大小后,设计一个恰好少1字节的输入块(例如,如果块大小为8字节,则输入“ AAAAAAA”)。思考一下oracle函数将在最后一个字节位置放置什么。

4. 通过将不同的字符串输入到oracle中,为每个可能的最后一个字节创建字典;例如“ AAAAAAAA”,“ AAAAAAAB”,“ AAAAAAAC”,记住每个调用的第一个块。

5. 将one-byte-short输入的输出与字典中的一项匹配。 现在,我们就已经发现了unknown-string的第一个字节。

6.针对下一个字节继续重复

 

这里的原理还是基于ECB模式自身缺陷

假设我们有aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab,16字节分组后如下所示

cryptopals解密之旅 (三)_第18张图片

 

对于前两个块,他们的输入都是16个a,他们对应的输出是一样的。也就是说相同输入会有相同输出,我们就可以根据这一点进行攻击。

举个实际生活中的例子,假设找到一个网站,它的会话cookies是这么生成的:

AES_ECB(USERNAME + SECRET, KEY),我们作为攻击者可以任意改变username,得到不同的密文。作为攻击者,我们想要得到secret。来看看我们是怎么攻击的。

首先我们将15个a作为username,得到密文

cryptopals解密之旅 (三)_第19张图片

 

可知作为一个16字节大小的块,第16字节是来自secret的未知字符

接下来暴力测试第16个字节的可能值,将得到的相应密文与上图的密文对比

cryptopals解密之旅 (三)_第20张图片

 

如上所示,当第16字节为c时,生成的密文和之前得到的密文是相同的,所以我们就知道secret的第1个字节是c了。

接下来我们设置username为14个a,则在构造块时,第15字节是secret的第一个字节c,那么第16个字节自然是来自secret的第二个字节,暂时未知,同样可以得到密文

cryptopals解密之旅 (三)_第21张图片

然后暴力测试第16个字节的可能值

cryptopals解密之旅 (三)_第22张图片

 

第16个字节为o时,密文才是一样的,所以可知secret的第二个字节为o

以此类推,就可以得到secret的明文了

回到题目本身,我们来看看如何实现

填充后使用AES-128-ECB模式加密

该函数用于返回encryption_oracle使用的块密码的块长度。

要找到一个块的长度,我们将加密越来越长的明文,直到输出密文的大小也增加为止。发生这种情况时,我们可以轻松地计算出一个块的长度,其值等于新的密文长度与其初始长度之间的差。

cryptopals解密之旅 (三)_第23张图片

该函数用于获取依次获取unknown-string的下一个字节,这个函数是本题的关键。

首先计算要用作输入的字符数,以使unkown-string的第一个未知的字符置于块的末尾。接着计算我们从伪造的密文和实际密文得到的字节数,进行比较,这个值在后面的密文比较中用于截取数据。然后计算实际的密文。之后是暴力尝试,通过比较密文,来找到待求的字符

cryptopals解密之旅 (三)_第24张图片

获取块长度,通过判断密文中是否有重复的字符串来判断是否为ECB模式。然后获取要解密的字符数量,其值等于我们加密空信息时得到的密文长度。该值在最后的循环中会用到,在循环体里,一个字符一个字符地操作。

cryptopals解密之旅 (三)_第25张图片

完整代码及执行结果如下:

cryptopals解密之旅 (三)_第26张图片

可以看到成功拿到了unknown_string的明文

也可以使用断言测试

cryptopals解密之旅 (三)_第27张图片

  • 参考:

1. https://cryptopals.com/sets/1

2. https://github.com/ricpacca/cryptopals

你可能感兴趣的:(CTF)