tbc.py (3541B)
1 # Implementation of the Lilliput-AE tweakable block cipher. 2 # 3 # Authors, hereby denoted as "the implementer": 4 # Kévin Le Gouguec, 5 # Léo Reynaud 6 # 2019. 7 # 8 # For more information, feedback or questions, refer to our website: 9 # https://paclido.fr/lilliput-ae 10 # 11 # To the extent possible under law, the implementer has waived all copyright 12 # and related or neighboring rights to the source code in this file. 13 # http://creativecommons.org/publicdomain/zero/1.0/ 14 15 """Lilliput-TBC tweakable block cipher. 16 17 This module provides functions to encrypt and decrypt blocks of 128 bits. 18 """ 19 20 from .constants import BLOCK_BYTES, SBOX 21 from .helpers import xor 22 from .multiplications import ALPHAS 23 24 25 _PERMUTATION = [14, 11, 12, 10, 8, 9, 13, 15, 3, 1, 4, 5, 6, 0, 2, 7] 26 _PERMUTATION_INV = [13, 9, 14, 8, 10, 11, 12, 15, 4, 5, 3, 1, 2, 6 ,0 ,7] 27 28 29 _ROUNDS = { 30 128: 32, 31 192: 36, 32 256: 42 33 } 34 35 36 def _build_tweakey(tweak, key): 37 return tweak+key 38 39 40 def _lane(TK, j): 41 return TK[j*8:(j+1)*8] 42 43 44 def _round_tweakey_schedule(tweakey): 45 p = len(tweakey)//8 46 47 multiplied_lanes = ( 48 ALPHAS[j](_lane(tweakey, j)) for j in range(p) 49 ) 50 51 return [byte for lane in multiplied_lanes for byte in lane] 52 53 54 def _subtweakey_extract(tweakey, Ci): 55 RTKi = [0]*8 56 57 for j, byte in enumerate(tweakey): 58 RTKi[j%8] ^= byte 59 60 RTKi[0] ^= Ci 61 62 return RTKi 63 64 65 def _tweakey_schedule_whole(tweakey, r): 66 TKs = [tweakey] 67 RTKs = [_subtweakey_extract(TKs[0], 0)] 68 69 for i in range(1, r): 70 TKs.append(_round_tweakey_schedule(TKs[i-1])) 71 RTKs.append(_subtweakey_extract(TKs[i], i)) 72 73 return RTKs 74 75 76 def _non_linear_layer(state, subtweakey): 77 variables_xored = xor(state, subtweakey) 78 79 variables_sboxed = [ 80 SBOX[variables_xored[i]] for i in range(8) 81 ] 82 83 state_output = state 84 for i in range(8): 85 state_output[15-i] ^= variables_sboxed[i] 86 87 return state_output 88 89 90 def _linear_layer(state): 91 state_output = state 92 93 for byte in range(1, 8): 94 state_output[15] ^= state[byte] 95 96 for byte in range(9, 15): 97 state_output[byte] ^= state[7] 98 99 return state_output 100 101 102 def _permutation_layer(state, p): 103 return [ 104 state[p[i]] for i in range(BLOCK_BYTES) 105 ] 106 107 108 def _one_round_egfn_enc(state, subtweakey): 109 state_non_linear = _non_linear_layer(state, subtweakey) 110 state_linear = _linear_layer(state_non_linear) 111 state_permutation = _permutation_layer(state_linear, _PERMUTATION) 112 113 return state_permutation 114 115 116 def _last_round_egfn(state, subtweakey): 117 state_non_linear = _non_linear_layer(state, subtweakey) 118 state_linear = _linear_layer(state_non_linear) 119 120 return state_linear 121 122 123 def _one_round_egfn_dec(state, subtweakey): 124 state_non_linear = _non_linear_layer(state, subtweakey) 125 state_linear = _linear_layer(state_non_linear) 126 state_permutation = _permutation_layer(state_linear, _PERMUTATION_INV) 127 128 return state_permutation 129 130 131 def encrypt(tweak, key, message): 132 r = _ROUNDS[8*len(key)] 133 134 tweakey = _build_tweakey(tweak, key) 135 RTKs = _tweakey_schedule_whole(tweakey, r) 136 137 state = message 138 139 for i in range(r-1): 140 state = _one_round_egfn_enc(state, RTKs[i]) 141 142 return _last_round_egfn(state, RTKs[r-1]) 143 144 145 def decrypt(tweak, key, cipher): 146 r = _ROUNDS[8*len(key)] 147 148 tweakey = _build_tweakey(tweak, key) 149 RTKs = _tweakey_schedule_whole(tweakey, r) 150 151 state = cipher 152 153 for i in range(r-1): 154 state = _one_round_egfn_dec(state, RTKs[r-i-1]) 155 156 return _last_round_egfn(state, RTKs[0])