我编写了一些Python 3脚本来利用一次性密钥,其中密钥已被多次使用。
当我将它应用于一些较短的测试用例时,它会产生正确的结果。 但是,当我尝试将它应用于更长的密码时,我感觉它不能正常工作,因为我无法扩展有希望的字符串。 这是PICNIC,还是代码中还有错误?
# -*- coding: UTF-8 -*-
import binascii
with open("ciphers.txt") as f:
ciphers = list(map(str.strip, f.readlines()))
# print(ciphers)
""" words which were already looked up """
occurred_words = []
xor_cipher_list = []
occurrence_count_list = [0] * 200
occurred_twoples = []
# print(ciphers)
def xor_ciphers(cipher_strings):
"""
:param cipher_strings: the cipher strings in hex to xor together
:return: the xord ciphers(hex, string)
xors the 10 cipher strings, two at a time
"""
cipher_hash_list = [int(ciphers[i], 16) ^ int(ciphers[i + 1], 16) for i in (range(0, len(ciphers) - 1, 2))]
# print([hex(hr)[2:] for hr in cipher_hash_list])
return [hex(hr)[2:] for hr in cipher_hash_list]
def crib_to_hex_string(try_word):
"""
:param try_word: ascii string
:return: hex string
turns the crib attempt word inta a hex string
"""
crib_hex = ''.join(format(ord(letter), '02x') for letter in try_word)
return crib_hex
def adjust_cipher_length(hex_crib_length):
"""
:param hex_crib_length: the length of the crib to adjust to
:return: a list of all the positions of the ciphers to check the crib against
"""
hex_list = [hash_cipher[i:i + min(hex_crib_length, len(hash_cipher))] for hash_cipher in xor_cipher_list for i in
range(0, len(hash_cipher) - min(hex_crib_length, len(hash_cipher)) + 1, 1)]
return hex_list
def attempt_to_decipher(hex_crib_string, hash_to_check_against):
"""
:param hex_crib_string: the hex crib string
:param hash_to_check_against: list of the xord, hex, in the right size ciphers
:return: byte stream of the decoded hex result of the xor
xors the crib with one hash of the list and returns the value
"""
smaller_length = min(len(hex_crib_string), len(hash_to_check_against))
decipher_attempt = int(hex_crib_string, 16) ^ int(hash_to_check_against, 16)
decipher_attempt = hex(decipher_attempt)[2:].zfill(smaller_length)
# print(decipher_attempt, end=": ")
return binascii.unhexlify(decipher_attempt)
def look_up(attempted_decoded_byte_stream):
"""
:param attempted_decoded_byte_stream: an ascii byte stream of the attempted decode
:return:nothing, recurses on success
looks the ascii string up, on success tries whole process again with new word
"""
global decoded_string
try:
decoded_string = str(attempted_decoded_byte_stream, "ASCII")
except UnicodeDecodeError:
"Not able to decode"
if decoded_string not in occurred_words:
occurred_words.append(decoded_string)
print(decoded_string)
def try_with(try_word):
"""
:param try_word: string of word to try with
:return: nothing
controller of the script, first turns everything into right format, then xors it and prints it
"""
""" turn the cribword to a hex string """
hex_crib_string = crib_to_hex_string(try_word)
# print(hex_crib_string)
hex_crib_length = len(hex_crib_string)
""" adjust the ciphers to right length """
cipher_adjusted_length_list = adjust_cipher_length(hex_crib_length)
# print(xor_cipher_list)
# print(cipher_adjusted_length_list)
""" xors and looks up """
for cipher in cipher_adjusted_length_list:
attempted_decoded_byte_stream = attempt_to_decipher(hex_crib_string, cipher)
look_up(attempted_decoded_byte_stream)
if __name__ == "__main__":
"""needs to be done only once"""
xor_cipher_list = xor_ciphers(ciphers)
""" start the whole process """
try_with(" have ")