def ctr_transform(plain, key, nonce): plain_blocks = split_blocks(plain, 16) cipher_blocks = [] keystream = ctr_aes128_keystream_gen(key, nonce) for block in plain_blocks: ks_block = next(keystream) cipher_blocks.append(xor_bytes(ks_block, block)) return b''.join(cipher_blocks)
def char_xor(input_bytes, char_byte): """ xors each char of input with char_byte. Returns bytestring""" for x in [input_bytes, char_byte]: try: x = x.decode() except AttributeError: pass key = len(input_bytes) * char_byte return xor_bytes(input_bytes, key)
def cbc_decrypt_block(c_previous, pre_plain_current): """ in :c_previous -- the last cipherblock (or IV if first block) :pre_p_current -- the decrypted current cipherblock out :p _current """ return xor_bytes(c_previous, pre_plain_current)
def cbc_encrypt_block(c_previous, p_current, key): """ in :key -- key to encrypt the block :c_previous -- the last cipher_block :p_current -- the plain block to eb encrypted out :c_current -- the encrypted block """ return encrypt_ecb_aes(xor_bytes(c_previous, p_current), key, False)
def cbc_byteflip(func, target_plain, base_plain, blocksize, prefix_length=0): if max(len(target_plain), len(base_plain)) > blocksize: raise ValueError("Attack does not support targets larger than blocksize") elif len(target_plain) != len(base_plain): raise ValueError("target_plain and base_plain have to be of equal length") offset = 0 if prefix_length % blocksize != 0: offset = blocksize - prefix_length % blocksize padd_start = b'A' * offset + b'A' * blocksize base_cipher_blocks = tools.split_blocks(func(padd_start + base_plain), blocksize) target_index = (prefix_length + offset) // blocksize target_block = base_cipher_blocks[target_index] padd_block = bytes(blocksize - len(target_plain)) base_plain += padd_block target_plain += padd_block # generate modified cipher_block diff = tools.xor_bytes(target_plain, base_plain) new_block = tools.xor_bytes(diff, target_block) mod_cipher_blocks = base_cipher_blocks[:] mod_cipher_blocks[target_index] = new_block return b''.join(mod_cipher_blocks)
def cbc_po_block(oracle, prev_c_block, target_c_block): """ decrypts a block via cbc paddingcoracle """ blocksize = len(target_c_block) plain = b'' for i in range(1, blocksize+1): pre = prev_c_block[:-i] post = tools.xor_bytes(bytes([i]*(i-1)), prev_c_block[-i+1:]) post = tools.xor_bytes(post, plain[-i+1:]) for guess in range(0, 256): x = bytes([guess ^ prev_c_block[-i] ^ i]) # guess xor prev_cipher xor padding mod_block = pre + x + post # print("oracle: ", mod_block, target_c_block) if oracle(mod_block+target_c_block): # TODO maybe check for false pos by modifying last byte of pre if i < blocksize: mod_block = pre[:-1]+bytes([pre[-1]+1])+x+post if oracle(mod_block+target_c_block): plain = bytes([guess]) + plain else: plain = bytes([guess]) + plain return plain
def hamming(bytes_a, bytes_b): """takes 2 bytestrings and calculates the hamming distance""" for inp in [bytes_a, bytes_b]: try: inp = inp.encode() except AttributeError: pass dist = 0 diff = xor_bytes(bytes_a, bytes_b) for char in diff: dist += str(bin(char)).count('1') return dist
def main(): length = len(base_ciphertext) dummy = bytes(length) key_stream = edit(0, dummy) solution = xor_bytes(key_stream, base_ciphertext) print(solution.decode())