0930作业
1.Many Time Pad (Coursera W1PA)
题目
Let us see what goes wrong when a stream cipher key is used more than once. Below are eleven hex-encoded ciphertexts that are the result of encrypting eleven plaintexts with a stream cipher, all with the same stream cipher key. Your goal is to decrypt the last ciphertext, and submit the secret message within it as solution.
Hint: XOR the ciphertexts together, and consider what happens when a space is XORed with a character in [a-zA-Z].
ciphertext #1:
315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e
ciphertext #2:
234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f
ciphertext #3:
32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb
ciphertext #4:
32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa
ciphertext #5:
3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070
ciphertext #6:
32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4
ciphertext #7:
32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce
ciphertext #8:
315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3
ciphertext #9:
271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027
ciphertext #10:
466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83
target ciphertext (decrypt this one):
32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904
问题描述
多次使用同一个流密码密钥加密了十一组明文,要求解密最后一个密文,提交对应明文
思路
流密码应用多次一密不满足CPA安全,可用CPA攻击
流密码加密原理:mi ⊕ ki = ci
多次一密时满足:mi ⊕ mj = ci ⊕ cj
这里每两个16进制字符代表明文的一个字符。
我们把10段密文的每一段进行两个两个划分,
然后与剩余9个密文的相同位置进行异或,如果异或出来结果大部分都是字母,
则说明了这个位置极有可能是个空格。在我的算法中,规定了每个位置与剩余9个位置异或,
如果异或结果为字母的个数大于5个,则标记为这个位置是空格。最后把标记的位置,
与目标密文中相同的位置进行异或,就可以得到目标密文这个位置的明文了
代码
#密文为十六进制字符串,应该先将其处理
ciphertexts = [
"315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e",
"234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f",
"32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb",
"32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa",
"3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba764896cf606ef40c04afe1ac0aa81dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce",
"315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3",
"271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027",
"466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83",
"32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904"
]
NUM_CIPHER = len(ciphertexts)#NUM_CIPHER=11
THRESHOLD_VALUE = 7#如果两两异或的结果为字母数大于7次,就认为该字符为空格,该值更改会影响最终结果
def strxor(a, b):
#两个字符串的异或
if len(a) > len(b):
# 形成二元组,异或,返回新字符串
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
else:
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])
def letter_position(s):
#返回给定字符串中给定字母的位置
position = []
for idx in range(len(s)):
#考虑到空格异或为0的情况可能较多
if (s[idx] >= 'A' and s[idx] <= 'Z') or (s[idx] >= 'a' and s[idx] <= 'z') or s[idx] == chr(0):
position.append(idx)
return position
def find_space(cipher):
#寻找空字符
space_position = {}
space_possible = {}
#双重循环,每一条密文均与其他密文异或
for cipher_idx_1 in range(NUM_CIPHER):
space_xor = []#用于保存可能空格符对应的位置
c = ''.join([chr(int(d, 16)) for d in [cipher[cipher_idx_1][i:i + 2] for i in range(0, len(cipher[cipher_idx_1]), 2)]])
for cipher_idx_2 in range(NUM_CIPHER):
#将十六进制字符串处理成对应ascii字符(每两个字符代表一个ascii符号)
e = ''.join([chr(int(d, 16)) for d in [cipher[cipher_idx_2][i:i+2] for i in range(0, len(cipher[cipher_idx_2]), 2)]])
plain_xor = strxor(c, e)
if cipher_idx_2 != cipher_idx_1:
# 记录明文中可能空格符的位置
space_xor.append(letter_position(plain_xor))
space_possible[cipher_idx_1] = space_xor #形成三维列表,新列表为11*10*n
#进一步判断已记录的位置是否为空字符,其准确性受到文本数量的影响
for cipher_idx_1 in range(NUM_CIPHER):
spa = []
for position in range(400):
count = 0
for cipher_idx_2 in range(NUM_CIPHER - 1):
if position in space_possible[cipher_idx_1][cipher_idx_2]:
count += 1
if count > THRESHOLD_VALUE: # 如果异或后字母出现次数大于7次,认为明文中此处为空格
spa.append(position)
space_position[cipher_idx_1] = spa #构成二维列表,11 * n
return space_position
#计算获得对应密钥Key
def calculate_key(cipher):
key = [0] * 200 #存放key
space = find_space(cipher)
#print(space)
for cipher_idx_1 in range(NUM_CIPHER):
for position in range(len(space[cipher_idx_1])):
idx = space[cipher_idx_1][position] * 2 #十六进制,用2位表示
a = cipher[cipher_idx_1][idx] + cipher[cipher_idx_1][idx + 1]
key[space[cipher_idx_1][position]] = int(a ,16) ^ ord(' ') # 计算密钥,获得结果十进制(ascii码)
key_str = ""#空串用于存放密钥
for k in key:
key_str += chr(k)#转化为
return key_str #获得密钥串
result = ""
key = calculate_key(ciphertexts)
key_hex = ''.join([hex(ord(c)).replace('0x', '') for c in key])#十六进制key
print("key=",key)
print("key_hex=",key_hex)
f = ''.join([chr(int(d, 16)) for d in [ciphertexts[0][i:i+2] for i in range(0, len(ciphertexts[0]), 2)]])
for letter in strxor(f,key):
if (letter>=' ' and letter<='~ '):#打印从32-126的可见字符
result+=letter
else:
result+='0'#不可打印字符用0代替,以区别空格符
print(result)
2.Vigenere逐字节异或加密
题目
Write a program that allows you to “crack” ciphertexts generated using a Vigenere-like cipher, where byte-wise XOR is used instead of addition modulo 26.
Specifically, the ciphertext:
F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794
问题描述
编写一个程序来破解Vigenere逐字节异或加密生成的密文,密文已给出
思路
猜测密钥长度为x,由于密文c给出,则将间隔x的字符分组取出,生成多个列表c1…cx,每个列表相当于与对应的密钥中的字符x[0]…
x[len(x)-1]异或,所以可以遍历密钥的每一个字符的每一个ASCII码可能值,直到恢复的明文列表都是可见ASCII字符为止
代码
#类维吉尼亚密码的逐字节异或加密
def findindexkey(subarr): # 该函数可以找出将密文subarr解密成可见字符的所有可能值
visiable_chars = [] # 可见字符
for x in range(32, 126):
visiable_chars.append(chr(x))
#print("可见字符")
#print(visiable_chars)
test_keys = [] # 用于测试密钥
ans_keys = [] # 用于结果的返回
for x in range(0x00, 0xFF): # 枚举密钥里所有的值
test_keys.append(x)
ans_keys.append(x)
for i in test_keys: # 对于0x00~0xFF里的每一个数i和subarr里的每个值s异或
for s in subarr:
if chr(s ^ i) not in visiable_chars: # 用i解密s,如果解密后明文不是可见字符,说明i不是密钥
ans_keys.remove(i) # 去掉ans_keys里测试失败的密钥
break
# print(ans_keys)
return ans_keys
strmi = 'F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923C\
AB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF\
5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84C\
C931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D96\
3FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47E\
FD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5\
923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA\
36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63C\
ED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A8\
5A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250\
C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794'
arr = [] # 密文,每个元素为字符的ascii码
for x in range(0, len(strmi), 2):
arr.append(int(strmi[x:2 + x], 16))
for keylen in range(1, 14): # 枚举密钥的长度1~14
for index in range(0, keylen): # 对密钥里的第index个进行测试
subarr = arr[index::keylen] # 每隔keylen长度提取密文的内容,提取出来的内容都被密文的第index个加密
ans_keys = findindexkey(subarr) # 找出密钥中第index个的可能的值
print('keylen=', keylen, 'index=', index, 'keys=', ans_keys)
if ans_keys: # 如果密钥第index个有可能存在,尝试用密钥的index个去解密文
ch = []
for x in ans_keys:
ch.append(chr(x ^ subarr[0]))
print(ch)
# 运行到这里,观察输出可以发现,密钥长度为7时有解
print('###############')
import string
def findindexkey2(subarr): # 再造一个函数筛选密钥
test_chars = string.ascii_letters + string.digits + ',' + '.' + ' ' # 将检查的字符改为英文+数字+逗号+句号+空格
# print(test_chars)
test_keys = [] # 用于测试密钥
ans_keys = [] # 用于结果的返回
for x in range(0x00, 0xFF): # 枚举密钥里所有的值
test_keys.append(x)
ans_keys.append(x)
for i in test_keys: # 对于0x00~0xFF里的每一个数i和substr里的每个值s异或
for s in subarr:
if chr(s ^ i) not in test_chars: # 用i解密s,如果解密后不是英文、数字、逗号、句号、空格,说明i不是密钥
ans_keys.remove(i) # 去掉ans_keys里测试失败的密钥
break
# print(ans_keys)
return ans_keys
vigenerekeys = [] # 维基尼尔密码的密钥
for index in range(0, 7): # 密钥长度是7
subarr = arr[index::7]
vigenerekeys.append(findindexkey2(subarr))
print(vigenerekeys) # 输出的是[[186], [31], [145], [178], [83], [205], [62]].
print("#########")
ming = ''
for i in range(0, len(arr)):
ming = ming + chr(arr[i] ^ vigenerekeys[i % 7][0]) # assic码转字符串
print(ming)
3.Break repeating-key XOR
题目
题目链接:
https://cryptopals.com/sets/1/challenges/6
问题描述
给出一段在Vigenere逐字节异或后进行base64加密得到的密文,要求解密
思路
猜测密钥长度,题解中建议猜测范围在2~40位。按照可能的keysize对密文进行分块,取前4个进行两两求汉明距离,若分块的长度等于keysize,
则应具有最小的汉明距离,(字母之间的汉明距离小),得到keysize之后,对分块的第一位、第二位分别进行匹配,最终得到密钥。
然后将密文分成 KEYSIZE 长度的块。对每块进行对应的异或操作还原明文。
代码
#set1_6
import base64
def English_Scoring(t):
latter_frequency = {
'a': .08167, 'b': .01492, 'c': .02782, 'd': .04253,
'e': .12702, 'f': .02228, 'g': .02015, 'h': .06094,
'i': .06094, 'j': .00153, 'k': .00772, 'l': .04025,
'm': .02406, 'n': .06749, 'o': .07507, 'p': .01929,
'q': .00095, 'r': .05987, 's': .06327, 't': .09056,
'u': .02758, 'v': .00978, 'w': .02360, 'x': .00150,
'y': .01974, 'z': .00074, ' ': .15000
}
return sum([latter_frequency.get(chr(i), 0) for i in t.lower()])
def Single_XOR(s, single_character):
t = b''
# print(s,single_character)
# s = bytes.fromhex(s)
# t: the XOR'd result
for i in s:
t = t + bytes([i ^ single_character])
# t = re.sub(r'[\x00-\x1F]+','', t)
# remove the ascii control characters
return t
def ciphertext_XOR(s):
_data = []
# s = bytes.fromhex(s)
# key = ord (single_character)
# ciphertext = b''
# for i in s :
# ciphertext = ciphertext + bytes([i ^ key])
for single_character in range(256):
ciphertext = Single_XOR(s, single_character)
# print(ciphertext)
score = English_Scoring(ciphertext)
data = {
'Single character': single_character,
'ciphertext': ciphertext,
'score': score
}
_data.append(data)
score = sorted(_data, key=lambda score: score['score'], reverse=True)[0]
# print(score['ciphertext'])
return score
def Repeating_key_XOR(_message, _key):
cipher = b''
length = len(_key)
for i in range(0, len(_message)):
cipher = cipher + bytes([_message[i] ^ _key[i % length]])
# print(cipher.hex())
return cipher
"""
if __name__ == '__main__':
_data = []
s = open('cryptopals_set1_4.txt').read().splitlines()
for i in s :
# print(i)
data = ciphertext_XOR(i)
_data.append(data)
best_score = sorted(_data, key = lambda score:score['score'], reverse=True)[0]
print(best_score)
for i in best_score :
print("{}: {}".format(i.title(), best_score[i]))
# print(f'{j}:{t},{score}')
"""
def hamming_distance(a, b):
distance = 0
for i, j in zip(a, b):
byte = i ^ j
distance = distance + sum(k == '1' for k in bin(byte))
return distance
def Get_the_keysize(ciphertext):
data = []
for keysize in range(2, 41):
block = [ciphertext[i:i + keysize] for i in range(0, len(ciphertext), keysize)]
distances = []
for i in range(0, len(block), 2):
try:
block1 = block[i]
block2 = block[i + 1]
distance = hamming_distance(block1, block2)
distances.append(distance / keysize)
except:
break
_distance = sum(distances) / len(distances)
_data = {
'keysize': keysize,
'distance': _distance
}
data.append(_data)
_keysize = sorted(data, key=lambda distance: distance['distance'])[0]
# print("123456789456123",_keysize)
# _keysize = min(data,key = lambda distance:distance['diatance'])
return _keysize
def Break_repeating_key_XOR(ciphertext):
# Guess the length of the key
_keysize = Get_the_keysize(ciphertext)
keysize = _keysize['keysize']
print(keysize)
key = b''
cipher = b''
block = [ciphertext[i:i + keysize] for i in range(0, len(ciphertext), keysize)]
for i in range(0, keysize):
new_block = []
t = b''
for j in range(0, len(block) - 1):
s = block[j]
t = t + bytes([s[i]])
socre = ciphertext_XOR(t)
key = key + bytes([socre['Single character']])
# cipher = cipher + socre['ciphertext']
# print(cipher)
for k in range(0, len(block)):
cipher = cipher + Repeating_key_XOR(block[k], key)
# print(key)
return cipher, key
# sorted(data, key = lambda distance:distance['distance'])[0]
if __name__ == '__main__':
with open('cryptopals_set1_6.txt') as of:
ciphertext = of.read()
ciphertext = base64.b64decode(ciphertext)
cipher, key = Break_repeating_key_XOR(ciphertext)
print("cipher:", cipher, "\nkey:", key)
参考链接
https://en.wikipedia.org/wiki/Hamming_distance
https://docs.python.org/zh-cn/3/library/functions.html#zip
https://blog.csdn.net/pangyuanzi/article/details/114763139
4.CRACKING SHA1-HASHED PASSWORDS
题目&问题描述
给出了一段泄露的 SHA1 值: 67ae1a64661ac8b4494666f58c4822408dd0a3e4 并给出了管理员输入密码时留下的指纹分布。
键盘示意图如下(绿色部分为被按过的键):
要求还原出密码,并且还原时间不超过 10s
思路
确定存在的字符集合:Q,q,W,w,%,5,8,(,=,0,I,i,*,+,n,N
若无法得出密码,则再加上数字小键盘的2468
题中未给出key长度,根据前人经验猜测为8
之后的工作即为正常爆破
代码
#coding:utf-8
import re
from Crypto.Hash import SHA
import hashlib
import itertools
import datetime
starttime = datetime.datetime.now()
hash1="67ae1a64661ac8b4494666f58c4822408dd0a3e4"
str1="QqWw%58(=0Ii*+nN"
str2=[['Q', 'q'],[ 'W', 'w'],[ '%', '5'], ['8', '('],[ '=', '0'], ['I', 'i'], ['*', '+'], ['n', 'N']]
def get_md5(s):
m = hashlib.md5()
m.update(str(s).encode('utf-8'))
return m.hexdigest()
def sha_encrypt(str):
sha = hashlib.sha1(str.encode('utf-8'))
encrypts = sha.hexdigest()
return encrypts
st3="0"*8
str4=""
str3=list(st3)
for a in range(0,2):
str3[0]=str2[0][a]
for b in range(0,2):
str3[1]=str2[1][b]
for c in range(0,2):
str3[2]=str2[2][c]
for d in range(0,2):
str3[3] = str2[3][d]
for e in range(0,2):
str3[4] = str2[4][e]
for f in range(0,2):
str3[5] = str2[5][f]
for g in range(0,2):
str3[6] = str2[6][g]
for h in range(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))
endtime = datetime.datetime.now()
time = ((endtime - starttime).seconds)
print(time)
exit(0)
参考链接
https://www.tr0y.wang/2017/10/11/Crypto3/