[A-Z]用[0x41-0x5a]表示。相应地,[a-z]用[0x61-0x7a]表示。而空格,则用0x20表示,也就是表格中的SP。空格这个表示带来了一个很巧妙的转换:如果一个大写字母与空格与或,那么结果为一个对应的小写字母;如果一个小写字母与空格与或,那么结果为一个对应的大写字母!举两个例子: a ^ SP = 01100001 ^ 00100000 = 01000001 = A A ^ SP = a ^ SP ^ SP = a 同时,解密过程中也用到了xor的另一个性质:对于一个数,连续与或两次任意相同的数,其结果与原数相同。用公式表示就是,对于任意的x和y: x ^ y ^ y = x 根据提示,每一个ciphertext都是用相同的streamcipher加密的。因此,假设plaintext分别为m1、m2,那么c1 = m1 ^ k, c2 = m2 ^ k,于是c1 ^ c2= m1 ^ k ^ m2 ^ k = m1 ^ m2。这样我们就把k消去,只剩下了m1和m2。 那么,我们的解法就很显然了:随便找任意给定的m_i,m_j相与或,如果发现了有意义的英文字母,那么对应位上很可能一个是空格,另一个是英文字母
defgetHammingDistance(x, y): returnsum([bin(x[i] ^ y[i]).count('1') for i inrange(len(x))])
#检测汉明距离计算函数是否正确 x = b'this is a test' y = b'wokka wokka!!!' expectedD = 37 d = getHammingDistance(x, y) if d != expectedD: raise Exception(encodedD + ' != ' + encodedExpectedD)
先根据汉明距离,计算出汉明距离最小的keysize值
1 2 3 4 5 6 7
defnormalizedEditDistance(x, k): blocks = [x[i:i+k] for i inrange(0, len(x), k)][0:4] pairs = list(itertools.combinations(blocks, 2)) scores = [getHammingDistance(p[0], p[1])/float(k) for p in pairs][0:6] returnsum(scores) / len(scores)
k = min(range(2, 41), key=lambda k: normalizedEditDistance(x, k))
defbreakRepeatingKeyXor(x, k): blocks = [x[i:i+k] for i inrange(0, len(x), k)] transposedBlocks = list(itertools.zip_longest(*blocks, fillvalue=0)) key = [challenge3.breakSingleByteXOR(bytes(x))[0] for x in transposedBlocks] returnbytes(key)
key = breakRepeatingKeyXor(x, k) y = challenge5.encodeRepeatingKeyXor(x, key) print(key) #write the result to file to look result = y.decode() open('Dechallenge6.txt', 'w').write(result)
最后运行的结果为: key = erminator X: Bring the noise 明文写入了文件,部分如下图:
#coding:utf-8 import re from Crypto.Hash import SHA import hashlib import itertools hash1="67ae1a64661ac8b4494666f58c4822408dd0a3e4" str1="QqWw%58(=0Ii*+nN" str2=[['Q', 'q'],[ 'W', 'w'],[ '%', '5'], ['8', '('],[ '=', '0'], ['I', 'i'], ['*', '+'], ['n', 'N']] defsha_encrypt(str): sha = hashlib.sha1(str) encrypts = sha.hexdigest() return encrypts st3="0"*8 str4="" str3=list(st3) for a inrange(0,2): str3[0]=str2[0][a] for b inrange(0,2): str3[1]=str2[1][b] for c inrange(0,2): str3[2]=str2[2][c] for d inrange(0,2): str3[3] = str2[3][d] for e inrange(0,2): str3[4] = str2[4][e] for f inrange(0,2): str3[5] = str2[5][f] for g inrange(0,2): str3[6] = str2[6][g] for h inrange(0,2): str3[7] = str2[7][h] newS="".join(str3) for i in itertools.permutations(newS, 8): str4 = sha_encrypt("".join(i)) if str4==hash1: print"".join(i) exit(0)