def aes_cbc(input_data, key, iv, operation='encrypt'): key_bits = len(key) * 8 if key_bits not in [128, 192, 256]: raise ValueError('Wrong size key. Must be either 128, 192 or 256 bits') key_schedule = expand_key(key) input_data = bytearray(input_data) output_data = bytearray(len(input_data)) for i in range(0, len(input_data), 16): if operation == 'encrypt': if i == 0: block = xor_buffers(input_data[i:i + 16], iv) else: block = xor_buffers(input_data[i:i + 16], output_data[i - 16:i]) aes_encrypt_block(block, key_schedule) output_data[i:i + 16] = block elif operation == 'decrypt': block = input_data[i:i + 16] aes_decrypt_block(block, key_schedule[::-1]) if i == 0: output_data[i:i + 16] = xor_buffers(block, iv) else: output_data[i:i + 16] = xor_buffers(block, input_data[i - 16:i]) return output_data
def expand_key(key): N = len(key) // 4 R = N + 7 rcon = generate_round_constants(R) key_schedule = [] W = [] for i in range(4 * R): if i < N: Wi = key[i * N:(i + 1) * N] elif i >= N and i % N == 0: Wi = xor_buffers( xor_buffers(W[i - N], rot_word(sub_word(W[i - 1]))), rcon[i // N]) elif 6 < N <= i and i % N == 4: Wi = xor_buffers(W[i - N], sub_word(W[i - 1])) else: Wi = xor_buffers(W[i - N], W[i - 1]) W.append(Wi) # This is incredibly hacky if (i + 1) % N == 0: K = b''.join(W[i - 4 + 1:i + 1]) key_schedule.append(K) return key_schedule
def aes_ctr(input_data, key, nonce, format='little'): key_bits = len(key) * 8 if key_bits not in [128, 192, 256]: raise ValueError('Wrong size key. Must be either 128, 192 or 256 bits') key_schedule = expand_key(key) input_data = bytearray(input_data) output_data = bytearray(len(input_data)) counter = 0 for i in range(0, len(input_data), 16): data_block = input_data[i:i + 16] counter_block = bytearray( nonce.to_bytes(8, format) + counter.to_bytes(8, format)) aes_encrypt_block(counter_block, key_schedule) output_data[i:i + 16] = xor_buffers(data_block, counter_block) counter += 1 return output_data
def repeating_key_xor(data, key): key_data = bytes([key[i % len(key)] for i in range(len(data))]) return xor_buffers(data, key_data)
def single_byte_repeating_xor(data, key): return xor_buffers(data, key*len(data))
def hamming_distance(buff1, buff2): return sum(bin(ch).count('1') for ch in xor_buffers(buff1, buff2))