本文主要是介绍the cryptopals crypto challenges set 1 part 2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
今天写了剩下的几题:
- Implement repeating-key XOR
- Break repeating-key XOR
- AES in ECB mode
- 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 = 0if (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)]))
这篇关于the cryptopals crypto challenges set 1 part 2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!