现代密码学解题报告(一)

0x00 前言

该系列主要用于记录密码学实验过程中遇到的题目及相关分析方法.

0x01 Cryptopals部分题目

该部分题目参考Cryptopals系列博客Set1部分,链接如下:
Cryptopals-Set1

0x02 Many Time Pad

题目链接

Coursera-Cryptography-Week1-PA

题目描述

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].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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

题目分析

该题目提供了十条使用同一密钥(有意义的英文语句)加密后的密文结果,要求根据所给的密文解密最终的target ciphertext.由提示,空格space与大写字母异或结果为小写字母,与小写字母异或结果为大写字母.而任意两个字母异或的结果不在字母范围内.又由于对于使用同一密钥进行异或加密的两对密文,其进行异或的结果等于对应明文进行异或的结果,如果结果的某个位置出现字母,则说明对应的两个明文位置的其中之一可能为空格.故对十一条密文进行两两异或,对于第一条密文,寻找可能为空格的位置,将该位置与其余密文对应位置的字符进行异或,设定阈值为6,当结果中有超过该阈值数量的字母时,可以确定该位置明文为空格,从而确定该位置的密钥.获取足够多密钥信息后,可以对目标密文进行解密.得到的结果有部分未还原部分,根据常识还原出最终明文,并根据结果还原密钥.代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# -*- coding:utf-8 -*-

import sys
import binascii

def strxor(a, b):
"""xor two strings of different lengths"""
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):
""" Return the position of letters in the given string """
position=[]
for idx in range(len(s)):
if (s[idx]>='A' and s[idx]<='Z') or (s[idx]>='a' and s[idx]<='z'):
position.append(idx)
return position

def find_space(cipher):
"""Find the position of space"""
space_position={}
space_possible={}
# 进行两两异或,得到每一条消息对应的空格的可能位置
for cipher_idx_1 in range(NUM_CIPHER):
space_xor=[]
for cipher_idx_2 in range(NUM_CIPHER):
plain_xor=strxor(cipher[cipher_idx_1].decode('hex'),cipher[cipher_idx_2].decode('hex'))
if cipher_idx_2!=cipher_idx_1:
space_xor.append(letter_position(plain_xor)) # record the possible value of space
space_possible[cipher_idx_1]=space_xor

for cipher_idx_1 in range(NUM_CIPHER):
spa=[]
for position in range(KEY_SIZE):
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: # if possible position value appear more than THRESHOLD_VALUE times,
# we consider it as a space position
spa.append(position)
space_position[cipher_idx_1]=spa
return space_position


def calculate_key(cipher):
key=[0]*KEY_SIZE
space=find_space(cipher)
for cipher_idx_1 in range(NUM_CIPHER):
for position in range(len(space[cipher_idx_1])):
idx=space[cipher_idx_1][position]*2 # ciphertext is hex-encoded, so its scale times two
key[space[cipher_idx_1][position]]=ord((ciphertexts[cipher_idx_1][idx]+ciphertexts[cipher_idx_1][idx+1]).decode('hex'))^ord(' ') #derive key
key_str=""
for k in key:
key_str+=chr(k)
return key_str


if __name__ == "__main__":
ciphertexts=[
"315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e",
"234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f",
"32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb",
"32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa",
"3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce",
"315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3",
"271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027",
"466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83",
"32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904"
]

KEY_SIZE=100
NUM_CIPHER=len(ciphertexts)
# 设定阈值
THRESHOLD_VALUE=6
result=""
key=calculate_key(ciphertexts)
print key
for letter in strxor(ciphertexts[10].decode('hex'),key): # decrypt the target cipher
if (letter>='a' and letter<='z') or (letter>='A' and letter<='Z'):
result+=letter
elif letter==' ':
result+=letter
else:
result+='0'
print result
result = binascii.a2b_hex(b'The secret message is When using a stream cipher never use the key more than once')
key = strxor(result, ciphertexts[10].decode('hex'))
print key

0x03 Vigenere-like cipher

题目描述

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

1
F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794

was generated by encrypting English-language text using the following C program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#define KEY_LENGTH 2 // Can be anything from 1 to 13

main(){
unsigned char ch;
FILE *fpIn, *fpOut;
int i;
unsigned char key[KEY_LENGTH] = {0x00, 0x00};
/* of course, I did not use the all-0s key to encrypt */

fpIn = fopen("ptext.txt", "r");
fpOut = fopen("ctext.txt", "w");

i=0;
while (fscanf(fpIn, "%c", &ch) != EOF) {
/* avoid encrypting newline characters */
/* In a "real-world" implementation of the Vigenere cipher,
every ASCII character in the plaintext would be encrypted.
However, I want to avoid encrypting newlines here because
it makes recovering the plaintext slightly more difficult... */
/* ...and my goal is not to create "production-quality" code =) */
if (ch!='\n') {
fprintf(fpOut, "%02X", ch ^ key[i % KEY_LENGTH]); // ^ is logical XOR
i++;
}
}

fclose(fpIn);
fclose(fpOut);
return;
}

(Of course, when encrypting I used a random key length and chose each byte of the key at random.) The plaintext contains upper- and lower-case letters, punctuation, and spaces, but no numbers.
Recovered the original plaintext.

题目分析

该题目的本质依然为密钥重复使用问题,只是披上了维吉尼亚的外衣.假设加密者使用的密钥为v-key,长度为length,密文为字符串ciphertext.则字符串cipherset0 = ciphertext[0+k*length]是被v-key[0]加密的内容,字符串cipherset1 = ciphertext[1+k*length]是被v-key1加密的内容,依次类推.按照这种方法,可以将密文ciphertext分割成length份,每份都被密钥v-key的同一位解密还原明文.对每个加密密钥v-key[index],穷举其所有可能的值,并与对应的cipherset里的内容进行异或解密,找到能将该cipherset所有内容解为可见字符的所有可能密钥值.通过上述方法首先枚举得到密钥长度length,然后改变判定为明文的条件(假设明文只有字母、数字、空格和符号),再进行穷举,最终还原出密钥并进行解密.
爆破密钥长度代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# -*- coding:utf-8
import string

def findindexkey(subarr, visiable_chars):# 该函数可以找出将密文subarr解密成可见字符的所有可能值
test_keys=[]# 用于测试密钥
ans_keys=[] # 用于结果的返回
for x in range(0x00,0xFF):# 枚举密钥里所有的值
test_keys.append(x)
ans_keys.append(x)
for i in test_keys:
for s in subarr:
if chr(s^i) not in visiable_chars:# 如果解密后明文不是可见字符,说明i不是密钥
ans_keys.remove(i)
break
return ans_keys

def get_length():
test_chars = string.ascii_letters+string.digits+','+'.'+' '

ciphertext = 'F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794'
ci_array = []
for x in range(0,len(ciphertext),2):
ci_array.append(int(ciphertext[x:2+x],16))


for keylen in range(1,14):
for index in range(0,keylen):
subarr = ci_array[index::keylen]# 每隔keylen长度提取密文的内容,其均被同一密钥异或加密
ans_keys = findindexkey(subarr, test_chars)# 找出密钥中第index个的可能的值
print('keylen=',keylen,'index=',index,'keys=',ans_keys)
if ans_keys:
ch=[]
for x in ans_keys:
ch.append(chr(x^subarr[0]))
print(ch)

#运行到这里,观察输出可以发现,密钥长度为7时有解
print('###############')

输出结果如下图:

4.png-69.5kB

确定密钥长度为7后,直接进行穷举破解,得到最终密钥.

1
2
3
4
5
6
vigenerekeys=[]
for index in range(0,7):
subarr=ci_array[index::7]
vigenerekeys.append(findindexkey(subarr, test_chars))
print(vigenerekeys)
# 最终密钥为[[186], [31], [145], [178], [83], [205], [62]].

最后使用得到的唯一密钥进行解密即可.

1
2
3
4
plaintext = ''
for i in range(0,len(ci_array)):
plaintext = plaintext + chr(ci_array[i]^vigenerekeys[i%7][0])
print(plaintext)

解密结果:

1
Cryptography is the practice and study of techniques for, among other things, secure communication in the presence of attackers. Cryptography has been used for hundreds, if not thousands, of years, but traditional cryptosystems were designed and evaluated in a fairly ad hoc manner. For example, the Vigenere encryption scheme was thought to be secure for decades after it was invented, but we now know, and this exercise demonstrates, that it can be broken very easily.

当然此破解过程也可以使用字母频率分析的方法来完成.

0x04 MTC3 Cracking SHA1-Hashed Passwords

题目链接

Keyboard-Attack

题目描述

The Secure Hash Algorithmus 1 has been standardized by the National Institute of Standards and Technology in 1995 and is besides MD5 the most commonly used hash algorithm in practice. An example for its usage is password-based authentification. In that case, the server does not store the user password in plain text but instead the SHA1 hash value of it. Once the user enters his password and after its received at the server, its hash value is computed and compared to the value stored on the server in order to verify its correctness.

A vulnerability of a surveillance system’s webserver leaked the SHA1 hash value of the password of the administrator account. The password’s hash value is

67ae1a64661ac8b4494666f58c4822408dd0a3e4

Furthermore, the keyboard of the login terminal shows clear signs of the entered password since after a successful login navigation in the software is only done via arrow keys. What is the password?

Remark: Note the German keyboard layout!

5.png-317.4kB

题目分析

该题目是一个简单的键盘还原问题,可以直接使用爆破的方法解决问题,注意需要考虑到时间限制.根据键盘上的按键分布,可以看出右边数字键只有2468,很有可能是当作上下左右的功能,对剩余按键按照每个键出现一次的原则进行暴力破解,可以得出最终键盘密码.脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# -*- coding:utf-8 -*-

# 通过爆破的方法得出符合要求的密码
# 最后完成整个程序需要的时间为9s

import re
from Crypto.Hash import SHA
import hashlib
import itertools
import datetime
starttime = datetime.datetime.now()
hash1="67ae1a64661ac8b4494666f58c4822408dd0a3e4"
str2=[['Q', 'q'],[ 'W', 'w'],[ '%', '5'], ['8', '('],[ '=', '0'], ['I', 'i'], ['*', '+'], ['n', 'N']]
def sha_encrypt(str):
sha = hashlib.sha1(str)
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()
print (endtime - starttime).seconds
exit(0)

该程序破解用时11s,结果如下图:

6.png-18.7kB

请作者吃个小鱼饼干吧