def keys(key, num_rounds): """Yields the permuted key bitstring for i = 1..num_rounds""" C, D = key[:28], key[28:] # Rounds are 1-indexed, so shift array over by one left_shifts = [ None, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ] for i in range(1, num_rounds + 1): # Negate each rotation to rotate left. C, D = rotate(C, -left_shifts[i]), rotate(D, -left_shifts[i]) yield self.permute(C + D, self._CD_permutation)
def slow_hash(seed, tweak, rounds=1, output_size=32, tables=256): seed = bytearray(null_pad(seed, 256)) state = seed[0] _rows = [rotate(tweak, amount) for amount in xrange(tables)] for round in range(rounds): for i in reversed(range(1, 256)): for rows in slide(_rows, 256): for row in rows: j = state & (i - 1) row[i], row[j] = row[j], row[i] random_row = rows[j] row[j], random_row[j] = random_row[j], row[j] seed[i] ^= random_row[row[j]] ^ row[random_row[j]] state ^= seed[i] ^ seed[j] ^ row[i] ^ random_row[i] i = 0 for rows in slide(_rows, 256): for row in rows: seed[i] ^= random_row[row[j]] ^ row[random_row[j]] state ^= seed[i] ^ seed[j] ^ row[i] ^ random_row[i] output = [] for index in range(output_size): output.append(seed[rows[index][index]]) return bytearray(output)
def rotational_difference(input_one, input_two): if input_one == input_two: return 0 input_one_bits = cast(input_one, "binary") input_two_bits = cast(input_two, "binary") if input_one_bits.count('1') == input_two_bits.count('1'): for rotation_amount in range(1, 8): if rotate(input_one_bits, rotation_amount) == input_two_bits: return rotation_amount
def test_vigenere_coincidences(self): coincidences = [] # The book says [14, 14, 16, 14, 24, 12] actual_coincidences = [14, 14, 16, 15, 25, 12] for r in range(1, 7): coincidences.append( VigenereAttack.coincidences(vigenere_ciphertext, rotate(vigenere_ciphertext, -r))) self.assertListEqual(coincidences, actual_coincidences)
def compare_rotations(cls, text, num_rotations=15): """ Counts the coincidences of all rotations of the given text. Takes in an optional tweaking parameter `num_rotations` that sets the number of rotations to use when counting coincidences in order to determine the probable key length. The num_rotations parameter should be bigger than the believed key length. Returns a dictionary of rotation : coincidences pairs Example: >>> VigenereAttack.compare_rotations('abcddd') {1: 2, 2: 1, 3: 0, 4: 1, 5: 2} >>> VigenereAttack.compare_rotations('aaabbb') {1: 4, 2: 2, 3: 0, 4: 2, 5: 4} """ return { r: cls.coincidences(text, rotate(text, -r)) for r in range(1, min(num_rotations, len(text))) }
def bit_shuffle(data, key, indices): for index in indices: data = rotate(data[:index], key[index]) + data[index:] return data
def shuffle(data, key, indices): output = data[:] for index, place in indices: output = rotate(output[:index + 1], key[index]) + output[index + 1:] replacement_subroutine(data, output)