def test_hash(data): output = bytearray(16) key = xor_sum(bytearray(data[:16])) for block in slide(bytearray(data), 16): prf(block, xor_sum(block)) xor_subroutine(output, block) return bytes(output)
def permute(state, rate_section=slice(0, 16), capacity_section=slice(16, 32), mask=255): for round in range(2): shuffle_bytes(state, capacity_section, offset=capacity_section.stop - capacity_section.start) half_size = len(state) / 2 capacity_xor = xor_sum(state[capacity_section]) # stir the capacity for index in range(half_size, half_size * 2): left, right = state[index - 1], state[index] left, right, capacity_xor = round_function(left, right, capacity_xor, index) state[index - 1], state[index] = left, right shuffle_bytes(state, rate_section) rate_xor = xor_sum(state[rate_section]) for index in range(half_size): rate_byte = index capacity_byte = index + half_size # mix the capacity and the rate left, right = state[rate_byte], state[capacity_byte] left, right, rate_xor = round_function( left, right, (rate_xor + capacity_xor) & mask, index) state[rate_byte], state[capacity_byte] = left, right # stir the rate left, right = state[rate_byte - 1], state[rate_byte] left, right, rate_xor = round_function(left, right, rate_xor, rate_byte) state[rate_byte - 1], state[rate_byte] = left, right
def permute(state, rate_section=slice(0, 16), capacity_section=slice(16, 32), mask=255): for round in range(2): shuffle_bytes(state, capacity_section, offset=capacity_section.stop - capacity_section.start) half_size = len(state) / 2 capacity_xor = xor_sum(state[capacity_section]) # stir the capacity for index in range(half_size, half_size * 2): left, right = state[index - 1], state[index] left, right, capacity_xor = round_function(left, right, capacity_xor, index) state[index - 1], state[index] = left, right shuffle_bytes(state, rate_section) rate_xor = xor_sum(state[rate_section]) for index in range(half_size): rate_byte = index capacity_byte = index + half_size # mix the capacity and the rate left, right = state[rate_byte], state[capacity_byte] left, right, rate_xor = round_function(left, right, (rate_xor + capacity_xor) & mask, index) state[rate_byte], state[capacity_byte] = left, right # stir the rate left, right = state[rate_byte - 1], state[rate_byte] left, right, rate_xor = round_function(left, right, rate_xor, rate_byte) state[rate_byte - 1], state[rate_byte] = left, right
def substitute_bytes(data, key, round_constants, counter, state): """ Substitution portion of the cipher. Classifies as an even, complete, consistent, homeogenous, source heavy unbalanced feistel network. (I think?) (https://www.schneier.com/cryptography/paperfiles/paper-unbalanced-feistel.pdf) The basic idea is that each byte of data is encrypted based off of every other byte of data around it. Each byte is substituted, then a byte at a random location substituted, then the current byte substituted again. At each substitution, the output is fed back into the state to modify future outputs. The ideas of time and spatial locality are introduced to modify how the random bytes are generated. Time is represented by the count of how many bytes have been enciphered so far. Space is indicated by the current index being operated upon. The S_BOX lookup could/should conceivably be replaced with a timing attack resistant non linear function. The default S_BOX is based off of modular exponentiation of 251 ^ x mod 257, which was basically selected at random and possesses a bad differential characteristic. The substitution steps are: - Remove the current byte from the state; If this is not done, the transformation is uninvertible - Generate an ephemeral byte to mix with the state; the ephemeral byte aims to preserve forward secrecy in the event the internal state is recovered (i.e. by differential attack) - Generate a psuedorandom byte from the state (everything but the current plaintext byte), then XOR that with current byte; then include current byte XOR psuedorandom_byte into the state - This is done in the current place, then in a random place, then in the current place again. """ state = xor_sum(data) ^ xor_sum(key) size = len(data) for index in counter: place = round_constants[index] # the counters are passed through the sbox to attempt to eliminate bias # simple byte ^ index would flip the low order bits more frequently then high order bits for smaller blocksizes # S_BOX is applied twice to prevent index ^ place == 0 when index == place present_modifier = S_BOX[S_BOX[S_BOX[index]] ^ S_BOX[place]] state ^= data[place] ^ present_modifier ephemeral_byte = S_BOX[key[index] ^ S_BOX[state]] data[place] ^= S_BOX[ state ^ ephemeral_byte] # goal is forward secrecy in event of sbox input becoming known state ^= data[place] ^ present_modifier second_place = round_constants[place] state ^= data[second_place] ^ present_modifier ephemeral_byte = S_BOX[key[index] ^ S_BOX[state]] data[second_place] ^= S_BOX[state ^ ephemeral_byte] state ^= data[second_place] ^ present_modifier state ^= data[place] ^ present_modifier ephemeral_byte = S_BOX[key[index] ^ S_BOX[state]] data[place] ^= S_BOX[ state ^ ephemeral_byte] # goal is forward secrecy in event of sbox input becoming known state ^= data[place] ^ present_modifier
def substitute_bytes(data, key, round_constants, counter, state): """ Substitution portion of the cipher. Classifies as an even, complete, consistent, homeogenous, source heavy unbalanced feistel network. (I think?) (https://www.schneier.com/cryptography/paperfiles/paper-unbalanced-feistel.pdf) The basic idea is that each byte of data is encrypted based off of every other byte of data around it. Each byte is substituted, then a byte at a random location substituted, then the current byte substituted again. At each substitution, the output is fed back into the state to modify future outputs. The ideas of time and spatial locality are introduced to modify how the random bytes are generated. Time is represented by the count of how many bytes have been enciphered so far. Space is indicated by the current index being operated upon. The S_BOX lookup could/should conceivably be replaced with a timing attack resistant non linear function. The default S_BOX is based off of modular exponentiation of 251 ^ x mod 257, which was basically selected at random and possesses a bad differential characteristic. The substitution steps are: - Remove the current byte from the state; If this is not done, the transformation is uninvertible - Generate an ephemeral byte to mix with the state; the ephemeral byte aims to preserve forward secrecy in the event the internal state is recovered (i.e. by differential attack) - Generate a psuedorandom byte from the state (everything but the current plaintext byte), then XOR that with current byte; then include current byte XOR psuedorandom_byte into the state - This is done in the current place, then in a random place, then in the current place again. """ state = xor_sum(data) ^ xor_sum(key) size = len(data) for index in counter: place = round_constants[index] # the counters are passed through the sbox to attempt to eliminate bias # simple byte ^ index would flip the low order bits more frequently then high order bits for smaller blocksizes # S_BOX is applied twice to prevent index ^ place == 0 when index == place present_modifier = S_BOX[S_BOX[S_BOX[index]] ^ S_BOX[place]] state ^= data[place] ^ present_modifier ephemeral_byte = S_BOX[key[index] ^ S_BOX[state]] data[place] ^= S_BOX[state ^ ephemeral_byte] # goal is forward secrecy in event of sbox input becoming known state ^= data[place] ^ present_modifier second_place = round_constants[place] state ^= data[second_place] ^ present_modifier ephemeral_byte = S_BOX[key[index] ^ S_BOX[state]] data[second_place] ^= S_BOX[state ^ ephemeral_byte] state ^= data[second_place] ^ present_modifier state ^= data[place] ^ present_modifier ephemeral_byte = S_BOX[key[index] ^ S_BOX[state]] data[place] ^= S_BOX[state ^ ephemeral_byte] # goal is forward secrecy in event of sbox input becoming known state ^= data[place] ^ present_modifier
def test_hash(data): size = len(data) data = data + ("\x00" * (16 - size)) if size == 16: output = bytearray(data) for round in range(1): prp(output, xor_sum(output)) else: output = bytearray(16) for block in slide(bytearray(data), 16): prp(block, xor_sum(block)) xor_subroutine(output, block) return bytes(output)
def stream_cipher(data, seed, key, size=(8, 255, 5), mode="encrypt"): if mode == "encrypt": data_prp_function = prp else: data_prp_function = invert_prp key = list(key) seed = list(seed) state = seed + key key_material = list() bit_width, mask, rotation_amount = size block_count, extra = divmod(len(data), 16) prf_state_xor = 0 state_xor = xor_sum(state) for block in range(block_count + 1 if extra else block_count): state_xor = prp(state, state_xor, mask, rotation_amount, bit_width) prf_state_xor ^= state_xor key_material.extend(state[0:16]) prf(key_material, prf_state_xor, mask, rotation_amount, bit_width) data_xor = xor_with_key(data, key_material) data_xor = data_prp_function(data, data_xor, mask, rotation_amount, bit_width, transpose=False) xor_subroutine(data, key_material)
def prp(data, mask=255, rotation_amount=5, bit_width=8): shuffle_bytes(data) key = xor_sum(data) key ^= data[0] data[0] = (data[0] + key) & mask key ^= data[0] for index in range(len(data)): left, right = data[index], data[(index + 1) % 16] key ^= right right = rotate_left((right + key + index) & mask, rotation_amount, bit_width) key ^= right key ^= left left = (left + (right >> (bit_width / 2))) & mask left ^= rotate_left(right, rotation_amount) key ^= left #print "\nSet left:", index, left #print "Set right: ", (index + 1) % 16, right data[index], data[(index + 1) % 16] = left, right return key
def one_way_function_s_box(data, s_box=S_BOX): """ Non invertible function. Uses an s_box, so is vulnerable to timing attacks. The default s_box has a bad differential characteristic, but can be changed to any 8x8 bit nonlinear mapping. """ state = xor_sum(data) for index, byte in enumerate(data): data[index] = s_box[s_box[byte] ^ s_box[index] ^ state]
def one_way_function_base_conversion(old_value, tweak=ASCII_CONSTANT): new_base = tweak old_base_mapping = {} old_value = ''.join(reversed(bytes(old_value))) for index, symbol in enumerate(slide(old_value, 2)): old_base_mapping[symbol] = index _old_value = bytearray(old_value) xor_key = xor_sum(_old_value) old_base_size = len(old_base_mapping) decimal_value = (xor_key + sum(((xor_key ^ old_base_mapping[value_representation]) * (old_base_size ** power) for power, value_representation in enumerate(slide(old_value, 2))))) #decimal_value = xor_key #for power, value_representation in enumerate(slide(old_value, 2)): # decimal_value += (xor_key ^ old_base_mapping[value_representation]) * (old_base_size ** power) new_value = '' new_base_size = len(new_base) new_value = '' while decimal_value > 0 or not new_value: # divmod = divide and modulo in one action decimal_value, digit = divmod(decimal_value, new_base_size) new_value += new_base[digit] return ''.join(reversed(new_value))
def one_way_function_base_conversion(old_value, tweak=ASCII_CONSTANT): new_base = tweak old_base_mapping = {} old_value = ''.join(reversed(bytes(old_value))) for index, symbol in enumerate(slide(old_value, 2)): old_base_mapping[symbol] = index _old_value = bytearray(old_value) xor_key = xor_sum(_old_value) old_base_size = len(old_base_mapping) decimal_value = (xor_key + sum( ((xor_key ^ old_base_mapping[value_representation]) * (old_base_size**power) for power, value_representation in enumerate(slide(old_value, 2))))) #decimal_value = xor_key #for power, value_representation in enumerate(slide(old_value, 2)): # decimal_value += (xor_key ^ old_base_mapping[value_representation]) * (old_base_size ** power) new_value = '' new_base_size = len(new_base) new_value = '' while decimal_value > 0 or not new_value: # divmod = divide and modulo in one action decimal_value, digit = divmod(decimal_value, new_base_size) new_value += new_base[digit] return ''.join(reversed(new_value))
def encrypt(state, key, rounds=1): xor_subroutine(state, key) p_box_half( state ) # makes halves orthogonal - 8 bytes vertical, 8 bytes horizontal for round in range(rounds): p_box(state) shuffle_bytes(state) round_key = xor_sum(state) # print "State at round start: ", round, round_key, state for index in reversed(range(16)): left, right = state[index - 1], state[index] round_key ^= left ^ right # print "\nIndex: ", index # print "Left: ", left # print "Right: ", right # print "Round key: ", round_key # print "Key: ", key[index] right = (right + round_key + key[index]) & 255 left = (left + (right >> 4)) & 255 left ^= rotate_left(right, 5) round_key ^= left ^ right state[index - 1], state[index] = left, right
def encrypt(state, key, rounds=1): xor_subroutine(state, key) p_box_half(state) # makes halves orthogonal - 8 bytes vertical, 8 bytes horizontal for round in range(rounds): p_box(state) shuffle_bytes(state) round_key = xor_sum(state) # print "State at round start: ", round, round_key, state for index in reversed(range(16)): left, right = state[index - 1], state[index] round_key ^= left ^ right # print "\nIndex: ", index # print "Left: ", left # print "Right: ", right # print "Round key: ", round_key # print "Key: ", key[index] right = (right + round_key + key[index]) & 255 left = (left + (right >> 4)) & 255 left ^= rotate_left(right, 5) round_key ^= left ^ right state[index - 1], state[index] = left, right
def encrypt(data, key, rounds=1, size=(8, 255, 5)): key = key[:] round_key = list(bytearray(len(key))) key_xor = xor_sum(key) data_xor = xor_sum(data) bit_width, mask, rotation_amount = size for round in range(rounds): key_xor = prp(key, key_xor, mask, rotation_amount, bit_width) # generate key round_key[:] = key[:] # maintain invertible keyschedule prf(round_key, key_xor, mask, rotation_amount, bit_width) # one way extraction: class 2B keyschedule data_xor = xor_subroutine2(data, round_key) # pre-whitening data_xor = prp(data, xor_sum(data), mask, rotation_amount, bit_width) # high diffusion prp data_xor = xor_subroutine2(data, round_key) # post_whitening
def permute4(state): shuffle_bytes_optimized(state) state_xor = xor_sum(state) for index in range(len(state)): left, right = state[index - 1], state[index] state_xor ^= right left, right, state_xor = round_function(left, right, state_xor, index) state[index - 1], state[index] = left, right
def generate_round_key(key, constants): """ Invertible round key generation function. """ size = len(key) for round in range(1): state = xor_sum(key) for index in constants: state ^= key[index] key[index] ^= S_BOX[state ^ S_BOX[index] ^ key[(index + 1) % size] ^ key[(index + 2) % size]] state ^= key[index]
def decrypt(data, key, rounds=1, size=(8, 255, 5)): round_keys = [] key = key[:] round_key = list(bytearray(len(key))) key_xor = xor_sum(key) data_xor = xor_sum(data) bit_width, mask, rotation_amount = size for round in range(rounds): key_xor = prp(key, key_xor, mask, rotation_amount, bit_width) round_key[:] = key[:] prf(round_key, key_xor, mask, rotation_amount, bit_width) round_keys.append(round_key[:]) for round in reversed(range(rounds)): round_key = round_keys[round] data_xor = xor_subroutine2(data, round_key) data_xor = invert_prp(data, xor_sum(data), mask, rotation_amount, bit_width) data_xor = xor_subroutine2(data, round_key)
def substitute_bytes(self, data, tweak, start, direction): data_size = len(data) index = start state = xor_sum(data) for count in range(0, data_size): state ^= data[index] random_place = state & (data_size - 1) data[index] ^= data[random_place & (index - 1)] ^ random_place state ^= data[index] index += direction
def test_prp_sponge(): import crypto.designs.hash.sponge import streamcipher2 from crypto.utilities import xor_sum #prp_hash = sponge.sponge_factory(lambda data: streamcipher2.prp(data, xor_sum(data)), capacity=8, rate=8) #print prp_hash("Testing") #import crypto.analysis.metrics prp = sponge.sponge_factory(lambda data: streamcipher2.prp(data, xor_sum(data)), capacity=8, rate=8, output_size=8) print test_xor_difference(prp, 8) metrics.test_hash_function(prp)
def test_prp(): data = list(bytearray(16)) data[-1] = 1 data2 = list(bytearray(16)) data2[-2] = 1 data3 = list(bytearray(16)) data3[-2] = 2 wordsize = 64 size = (((2**wordsize) - 1), 40, wordsize) data_xor = prp(data, xor_sum(data), *size) prf(data, data_xor, *size) #prp(data, xor_sum(data), *size) data_xor = prp(data2, xor_sum(data2), *size) prf(data2, data_xor, *size) #prp(data2, xor_sum(data), *size) data_xor = prp(data3, xor_sum(data3), *size) prf(data3, data_xor, *size) #prp(data3, xor_sum(data), *size) binary = lambda _data: ''.join( format(byte, 'b').zfill(wordsize) for byte in _data) _bytes = lambda _data: ''.join( bytes(integer_to_bytes(word, wordsize / 8)) for word in _data) #print binary(data).count('1') / float(wordsize * 16) #print #print binary(data2).count('1') / float(wordsize * 16) #print #print binary(data3).count('1') / float(wordsize * 16) print _bytes(data) print print _bytes(data2) print print _bytes(data3)
def stream_cipher(data, seed, key, size=(8, 255, 5)): key = list(key) seed = list(seed) key_material = list() key_xor = xor_sum(key) bit_width, mask, rotation_amount = size block_count, extra = divmod(len(data), 16) for block in range(block_count + 1 if extra else block_count): key_xor = prp(key, mask, rotation_amount, bit_width) round_key = key[:] prf(round_key, key_xor, mask, rotation_amount, bit_width) xor_subroutine(seed, round_key) prp(seed, mask, rotation_amount, bit_width) xor_subroutine(seed, round_key) prf(seed, xor_sum(seed), mask, rotation_amount, bit_width) key_material.extend(seed) xor_subroutine(data, key_material)
def test_prp(): data = list(bytearray(16)) data[-1] = 1 data2 = list(bytearray(16)) data2[-2] = 1 data3 = list(bytearray(16)) data3[-2] = 2 wordsize = 64 size = (((2 ** wordsize) - 1), 40, wordsize) data_xor = prp(data, xor_sum(data), *size) prf(data, data_xor, *size) #prp(data, xor_sum(data), *size) data_xor = prp(data2, xor_sum(data2), *size) prf(data2, data_xor, *size) #prp(data2, xor_sum(data), *size) data_xor = prp(data3, xor_sum(data3), *size) prf(data3, data_xor, *size) #prp(data3, xor_sum(data), *size) binary = lambda _data: ''.join(format(byte, 'b').zfill(wordsize) for byte in _data) _bytes = lambda _data: ''.join(bytes(integer_to_bytes(word, wordsize / 8)) for word in _data) #print binary(data).count('1') / float(wordsize * 16) #print #print binary(data2).count('1') / float(wordsize * 16) #print #print binary(data3).count('1') / float(wordsize * 16) print _bytes(data) print print _bytes(data2) print print _bytes(data3)
def xor_test(message, key, direction): xor_subroutine(message, key) state = xor_sum(message) size = len(message) - 1 index = 0 if direction == 1 else size for counter in range(len(message)): state ^= message[index] random_place = state & size message[index] ^= (state + key[random_place] + ephemeral_byte) % 256 #message[index] ^= key[random_place & (index - 1)] ^ random_place ^ state state ^= message[index] index += direction xor_subroutine(message, key)
def diffusion_transformation(_bytes): state = xor_sum(_bytes) size = len(_bytes) for index, byte in enumerate(_bytes): state ^= _bytes[index] _bytes[index] = (_bytes[index] + state + index) % 256 state ^= _bytes[index] # random_index = (state + index) % size # state ^= _bytes[random_index] # _bytes[random_index] = (_bytes[random_index] + state + index) % 256 # state ^= _bytes[random_index] # state ^= _bytes[index] _bytes[index] = (_bytes[index] + state + index) % 256 state ^= _bytes[index]
def test_prp_sponge(): import crypto.designs.hash.sponge import streamcipher2 from crypto.utilities import xor_sum #prp_hash = sponge.sponge_factory(lambda data: streamcipher2.prp(data, xor_sum(data)), capacity=8, rate=8) #print prp_hash("Testing") #import crypto.analysis.metrics prp = sponge.sponge_factory( lambda data: streamcipher2.prp(data, xor_sum(data)), capacity=8, rate=8, output_size=8) print test_xor_difference(prp, 8) metrics.test_hash_function(prp)
def invert_diffusion_transformation(_bytes): state = xor_sum(_bytes) size = len(_bytes) - 1 for index, byte in enumerate(reversed(_bytes)): index = size - index state ^= _bytes[index] _bytes[index] = (256 + (_bytes[index] - (state + index))) % 256 state ^= _bytes[index] # random_index = (state + index) % size # state ^= _bytes[random_index] # _bytes[random_index] = (256 + (_bytes[random_index] - (state + index))) % 256 # state ^= _bytes[random_index] # state ^= _bytes[index] _bytes[index] = (256 + (_bytes[index] - (state + index))) % 256 state ^= _bytes[index]
def permutation(state, sbox, wordsize=WORDSIZE, cache=[branch(index) for index in range(32)]): assert len(state) < 32 _sum = xor_sum(state) # 16 size = len(state) for index in range(size): #for index2 in range(index, size): # word0, word1 = state[index], state[index2] # _sum ^= word0 ^ word1 # word0, word1 = choice_swap(_sum, word0, word1) # state[index] = rotate_left(sbox[word0 ^ cache[index]], 1, wordsize) # state[index2] = sbox[rotate_left(word1, 1, wordsize) ^ cache[index2]] # _sum ^= state[index] ^ state[index2] byte = state[index] state[index] = sbox[_sum ^ cache[index]] # 3 _sum = rotate_left(sbox[_sum ^ byte ^ state[index]], 1, wordsize) # 4
def test_prp_s_box(): import collections s_box = collections.defaultdict(bytearray) rounds = 4 for ending in range(256): data = bytearray(16) data[-1] = ending for round in range(rounds): prp(data, xor_sum(data)) s_box[round].append(data[-2]) from differential import find_best_differential from linear import calculate_linearity for round in range(rounds): _s_box = s_box[round] print "Best differential after {} rounds: ".format(round + 1), find_best_differential(_s_box) print "Linearity after {} rounds: ".format(round + 1), calculate_linearity(_s_box)
def test_prp_s_box(): import collections s_box = collections.defaultdict(bytearray) rounds = 4 for ending in range(256): data = bytearray(16) data[-1] = ending for round in range(rounds): prp(data, xor_sum(data)) s_box[round].append(data[-2]) from differential import find_best_differential from linear import calculate_linearity for round in range(rounds): _s_box = s_box[round] print "Best differential after {} rounds: ".format( round + 1), find_best_differential(_s_box) print "Linearity after {} rounds: ".format( round + 1), calculate_linearity(_s_box)
def prf(state): polarize_state(state) data_xor = xor_sum(state) for round in range(1): decorrelation_layer3(state) data_xor = round_function(state, 14, 15, data_xor) data_xor = round_function(state, 13, 14, data_xor) data_xor = round_function(state, 12, 13, data_xor) data_xor = round_function(state, 11, 12, data_xor) data_xor = round_function(state, 10, 11, data_xor) data_xor = round_function(state, 9, 10, data_xor) data_xor = round_function(state, 8, 9, data_xor) data_xor = round_function(state, 7, 8, data_xor) data_xor = round_function(state, 6, 7, data_xor) data_xor = round_function(state, 5, 6, data_xor) data_xor = round_function(state, 4, 5, data_xor) data_xor = round_function(state, 3, 4, data_xor) data_xor = round_function(state, 2, 3, data_xor) data_xor = round_function(state, 1, 2, data_xor) data_xor = round_function(state, 0, 1, data_xor) data_xor = round_function(state, 15, 0, data_xor)
def decrypt(state, key, rounds=1): for round in range(rounds): # print "\nBeginning of round:\n", state round_key = xor_sum(state) for index in range(16): left, right = state[index - 1], state[index] round_key ^= left ^ right left ^= rotate_left(right, 5) left = (255 + 1 + (left - (right >> 4))) & 255 right = (255 + 1 + (right - round_key - key[index])) & 255 # print left, right, round_key, key[index] round_key ^= left ^ right state[index - 1], state[index] = left, right # print "Before invert shuffle: ", state invert_shuffle_bytes(state) # print "After invert shuffle: ", state p_box(state) # print "After invert pbox: ", state p_box_half(state) xor_subroutine(state, key)
def decrypt_block(data, key, tweak=tuple([0 for byte in range(256)])): data = bytearray(data) key = bytearray(key) crypt_bytes(data, key, len(data) - 1, -1, xor_sum(data), [0] * len(data), tweak) return bytes(data)
def test_invert_prp(): data = bytearray("Testing!" * 2) data_xor = prp(data, xor_sum(data)) invert_prp(data, data_xor) assert data == "Testing!" * 2, data
def stream_to_block_encrypt(data, key, seed, blocksize=32): key_material = stream_cipher(len(data), seed, key) for block in slide(data, blocksize): xor_subroutine(data, key_material) prp(data, xor_sum(data)) xor_subroutine(data, key_material)
def block_to_stream_decrypt(data, key, seed, blocksize=32): key_material = stream_cipher(len(data), seed, key) for block in reversed(list(slide(data, blocksize))): xor_subroutine(data, key_material) invert_prp(data, xor_sum(data)) xor_subroutine(data, key_material)
def test_prp(): print test_xor_difference(lambda data: prp(data, xor_sum(data)), 16)
def encrypt_unrolled(state, key, rounds=1, temp=bytearray(16)): xor_subroutine(state, key) p_box_half(state) round_key = xor_sum(state) print "Beginning unrolled" for round in range(rounds): print "Before: ", state p_box(state) print "After: ", state left, right = state[2], state[7] round_key ^= left ^ right right = (right + round_key + key[15]) & 255 temp[15] = right round_key ^= right left, right = state[10], ( (left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[14]) & 255 temp[14] = right round_key ^= right left, right = state[1], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[13]) & 255 temp[13] = right round_key ^= right left, right = state[8], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[12]) & 255 temp[12] = right round_key ^= right left, right = state[14], ( (left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[11]) & 255 temp[11] = right round_key ^= right left, right = state[3], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[10]) & 255 temp[10] = right round_key ^= right left, right = state[13], ( (left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[9]) & 255 temp[9] = right round_key ^= right left, right = state[0], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[8]) & 255 temp[8] = right round_key ^= right left, right = state[9], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[7]) & 255 temp[7] = right round_key ^= right left, right = state[6], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[6]) & 255 temp[6] = right round_key ^= right left, right = state[12], ( (left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[5]) & 255 temp[5] = right round_key ^= right left, right = state[15], ( (left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[4]) & 255 temp[4] = right round_key ^= right left, right = state[4], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[3]) & 255 temp[3] = right round_key ^= right left, right = state[5], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[2]) & 255 temp[2] = right round_key ^= right left, right = state[11], ( (left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[1]) & 255 temp[1] = right round_key ^= right left, right = temp[15], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[0]) & 255 temp[0] = right round_key ^= right left = ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) temp[15] = left round_key ^= left state[:] = temp[:]
def extract_round_key(key): """ Non invertible round key extraction function. """ xor_sum_of_key = xor_sum(key) for index, key_byte in enumerate(key): key[index] = S_BOX[S_BOX[key_byte] ^ S_BOX[index] ^ xor_sum_of_key]
def encrypt_unrolled(state, key, rounds=1, temp=bytearray(16)): xor_subroutine(state, key) p_box_half(state) round_key = xor_sum(state) print "Beginning unrolled" for round in range(rounds): print "Before: ", state p_box(state) print "After: ", state left, right = state[2], state[7] round_key ^= left ^ right right = (right + round_key + key[15]) & 255 temp[15] = right round_key ^= right left, right = state[10], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[14]) & 255 temp[14] = right round_key ^= right left, right = state[1], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[13]) & 255 temp[13] = right round_key ^= right left, right = state[8], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[12]) & 255 temp[12] = right round_key ^= right left, right = state[14], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[11]) & 255 temp[11] = right round_key ^= right left, right = state[3], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[10]) & 255 temp[10] = right round_key ^= right left, right = state[13], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[9]) & 255 temp[9] = right round_key ^= right left, right = state[0], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[8]) & 255 temp[8] = right round_key ^= right left, right = state[9], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[7]) & 255 temp[7] = right round_key ^= right left, right = state[6], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[6]) & 255 temp[6] = right round_key ^= right left, right = state[12], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[5]) & 255 temp[5] = right round_key ^= right left, right = state[15], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[4]) & 255 temp[4] = right round_key ^= right left, right = state[4], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[3]) & 255 temp[3] = right round_key ^= right left, right = state[5], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[2]) & 255 temp[2] = right round_key ^= right left, right = state[11], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[1]) & 255 temp[1] = right round_key ^= right left, right = temp[15], ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) round_key ^= left right = (right + round_key + key[0]) & 255 temp[0] = right round_key ^= right left = ((left + (right >> 4)) & 255) ^ rotate_left(right, 5) temp[15] = left round_key ^= left state[:] = temp[:]