密码学0930大作业

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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值