the cryptopals crypto challenges set 1 part 2

文章介绍了如何使用repeating-keyXOR算法,处理字符串编码问题,计算汉明距离来评估密钥长度,并检测AESinECB模式。作者还展示了手动实现ECB解密和ECB模式检测的方法。
摘要由CSDN通过智能技术生成

今天写了剩下的几题:

在这里插入图片描述

  1. Implement repeating-key XOR
  2. Break repeating-key XOR
  3. AES in ECB mode
  4. Detect AES in ECB mode

思路与代码

1

利用之前的fixedxor函数就好,但是落实到具体容易出一些编码的问题。
我遇到的问题是在字符串和二进制/十六进制转换的时候,直接使用bin()/hex()去掉前缀的结果进行拼接,这样的后果是长度不对齐,字符转换成二进制,长度应为8,不足需要补前导0,十六进制则长度应为2,不足需要补前导0。

def ascii2hex(raw: str):
    '''
    >>> ascii2hex('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
    61616161616161616161616161616161616161616161616161616161616161616161
    >>> ascii2hex('\n')
    0a
    '''
    return ''.join([hex(ord(i))[2:].zfill(2) for i in raw])

def repeatXor(raw: str, key: str):
    '''
    >>> repeatXor("Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal", 'ICE')
    0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f
    '''
    key = (key * (int(len(raw) / len(key)) + 1))[:len(raw)]
    return fixedXor(ascii2hex((raw)), ascii2hex(key))

def fixedXor(str1: str, str2: str) -> str:
    '''
    >>> fixedXor('1c0111001f010100061a024b53535009181c', '686974207468652062756c6c277320657965')
    746865206b696420646f6e277420706c6179
    '''
    dec1 = [int(str1[i:i+2], 16) for i in range(0, len(str1), 2)]
    dec2 = [int(str2[i:i+2], 16) for i in range(0, len(str2), 2)]
    return ''.join([hex(i ^ j)[2:].zfill(2) for i,j in zip(dec1, dec2)])

2

首先写一个计算汉明距离的函数,稍后利用汉明距离作为评分标准。

def hamming(raw1: str, raw2: str):
    '''
    >>> hamming('this is a test', 'wokka wokka!!!')
    37
    '''
    bias = 0
    if (len(raw1) > len(raw2)):
        bias = len(raw1) - len((raw2))
        raw1 = raw1[:len(raw2)]
    elif (len(raw1) < len(raw2)):
        bias = len(raw2) - len((raw1))
        raw2 = raw2[:len(raw1)]
    raw1 = ascii2bin(raw1)
    raw2 = ascii2bin(raw2)
    return sum([raw1[i] != raw2[i] for i in range(len(raw1))])+bias

然后读取文件,解码base64,得到raw string。注意要去掉每一行的换行符,还要注意文件最后应以换行作为最后一行防止最后一个字符串缺一个字符。

cipherFile = ''
with open('6.txt', 'r') as file:
    # 读取每一行
    lines = file.readlines()
for line in lines:
    cipherFile += line[0:-1]	
strCipherFile = base64.b64decode(cipherFile).decode()

用题目所给的两种方法计算汉明距离得分。得分的对应的keysize大概率就是keysize。

candidate = []
strCipherFile = base64.b64decode(cipherFile).decode()
for KeySize in range(2, 40):
    ss1 = strCipherFile[:KeySize]
    ss2 = strCipherFile[KeySize: 2 * KeySize]
    candidate.append((hamming(ss1, ss2)/KeySize, KeySize))
print(sorted(candidate))

candidate = []
strCipherFile = base64.b64decode(cipherFile).decode()
for KeySize in range(1, 40):
    ss1 = strCipherFile[:KeySize]
    ss2 = strCipherFile[KeySize: 2 * KeySize]
    ss3 = strCipherFile[2 * KeySize: 3 * KeySize]
    ss4 = strCipherFile[3 * KeySize: 4 * KeySize]
    # 计算所有可能的汉明距离
    hamming_distances = [hamming(ss1, ss2), hamming(ss1, ss3), hamming(ss1, ss4), 
                    hamming(ss2, ss3), hamming(ss2, ss4), 
                    hamming(ss3, ss4)]
    # 计算平均汉明距离
    average_hamming_distance = sum(hamming_distances) / len(hamming_distances)

    candidate.append(((average_hamming_distance/KeySize), KeySize))
print(sorted(candidate))

第二种方法似乎更靠谱一点,因为真正的 keysize 没有出现在前一种里。。。最终 keysize 为 29。

然后基于 keysize 分块,按列划分字符串进行单个字符异或的破解(Detect single-character XOR),依次得到密钥的每一位,接着就可以用密钥进行解密(Implement repeating-key XOR)。
ps(这里思路我当时没缕清,以为 findSingleXor 的结果应该是有特征的。。。但是它是又一列的字符构成的字符串,当然不会有规律了。。。重点是猜出这一位的 key,然后拼起来,最后用来解密密文,这时的结果才是有规律的。。。)

KeySize = 29
strCipherFile = strCipherFile.zfill(2871+29)
breakCipher = [strCipherFile[i:i + KeySize] for i in range(0, len(strCipherFile), KeySize)]
transBreakCipher = [None for _ in range(len(breakCipher[0]))]
for i in range(KeySize):
    transBreakCipher[i] = ''.join([ss[i] for ss in breakCipher])

key = ''
for i in transBreakCipher:
    key += findSingleXor(ascii2hex(i))[2]
print(key)	# nator X: Bring the noiseTermi
print(hex2ascii(repeatXor(strCipherFile, key)))

看到明文时还是很感动的

在这里插入图片描述

3

不知道题目是不是想让我们手动实现ecb的解密?说是不建议用openssl命令行,那我用python写代码应该没问题吧)

from Crypto.Cipher import AES
with open('7.txt', 'r') as file:
    lines = file.readlines()

cipherText = ''.join([i[:-1] for i in lines]) + 'H' # 原来的文件最后没有换行
cipherText = base64.b64decode(cipherText)	# 题目说到结果使用了base64编码
key = 'YELLOW SUBMARINE'

cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
cipher.decrypt(cipherText.encode())

在这里插入图片描述

4

检测 ECB 模式。使用 ECB 会导致重复的密文加密后出现重复的结果,以此为依据,分析每个分组的出现频次即可。这里我先用 set 记录每个字符串对应的分组的集合的大小,如果有重复集合就会比较小,结果证明这样就足以检测 ECB 了。

with open('8.txt', 'r') as file:
    lines = file.readlines()

lines = [i[:-1] for i in lines]
# 16 bytes == 16 hex values -> length of 32
splitLines = [set([ss[i:i+32] for i in range(0, len(ss), 32)]) for ss in lines]
print(sorted([(len(hh), i) for i, hh in enumerate(splitLines)]))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值