def attack_single_byte_xor(ciphertext): # a variable to keep track of the best candidate so far best = None for i in range(2**8): # for every possible key # converting the key from a number to a byte candidate_key = i.to_bytes(1, byteorder='big') # the byte string we will XOR the message against is usually called the "keystream" keystream = candidate_key * len(ciphertext) candidate_message = xor(ciphertext, keystream) ascii_text_chars = list(range(97, 122)) + [32] nb_letters = sum([x in ascii_text_chars for x in candidate_message]) # if the obtained message has more letters than any other candidate before if best == None or nb_letters > best['nb_letters']: # store the current key and message as our best candidate so far best = { "message": candidate_message, 'nb_letters': nb_letters, 'key': candidate_key } # if the best message is too low quality if best['nb_letters'] > 0.7 * len(ciphertext): return best else: raise InvalidMessageException('best candidate message is: %s' % best['message'])
def decrypt_aes_128_cbc(ctxt, iv, key): result = b'' previous_ctxt_block = iv blocks = split_bytes_in_blocks(ctxt, blocksize=16) for block in blocks: to_xor = decrypt_aes_128_block(block, key) result += xor(to_xor, previous_ctxt_block) assert len(result) != 0 # for the next iteration previous_ctxt_block = block return pkcs7_strip(result)
def encrypt_aes_128_cbc(msg, iv, key): result = b'' previous_ctxt_block = iv padded_ptxt = pkcs7_padding(msg, block_size=16) blocks = split_bytes_in_blocks(padded_ptxt, blocksize=16) for block in blocks: to_encrypt = xor(block, previous_ctxt_block) new_ctxt_block = encrypt_aes_128_block(to_encrypt, key) result += new_ctxt_block # for the next iteration previous_ctxt_block = new_ctxt_block return result
def hamming_distance(a, b): #humming distance is between two strings of equal length is the number of positions at which the corresponding #symbols are different. In other words, it measures the minimum number of substitutions required to change one #string into the other, or the minimum number of errors that could have transformed one string into the other return sum(bin(byte).count('1') for byte in xor(a, b))
def xor_with_key(message, key): #form keystream, repeat as many times as needed keystream = key * (len(message) // len(key) + 1) #XOR ciphertext = xor(message, keystream) return hexlify(ciphertext)