1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
"""
Lilliput TBC
"""
from .constants import BLOCK_BYTES, Sbox
from .multiplications import ALPHAS
permutation = [14, 11, 12, 10, 8, 9, 13, 15, 3, 1, 4, 5, 6, 0, 2, 7]
permutationInv = [13, 9, 14, 8, 10, 11, 12, 15, 4, 5, 3, 1, 2, 6 ,0 ,7]
################################################################################
def BuildTweakey(tweak, key):
return tweak+key
#############################
def _lane(TK, j):
return TK[j*8:(j+1)*8]
def RoundTweakeySchedule(tweakey):
p = len(tweakey)//8
multiplied_lanes = (
ALPHAS[j](_lane(tweakey, j)) for j in range(p)
)
return [byte for lane in multiplied_lanes for byte in lane]
def SubTweakeyExtract(tweakey, Ci):
RTKi = [0]*8
for j, byte in enumerate(tweakey):
RTKi[j%8] ^= byte
RTKi[0] ^= Ci
return RTKi
def TweakeyScheduleWhole(tweakey, r):
# store main tweakey in TKs[0]
# and corresponding round tweakey in RTKs[0]
TKs = [tweakey]
RTKs = [SubTweakeyExtract(TKs[0], 0)]
for i in range(1, r):
TKs.append(RoundTweakeySchedule(TKs[i-1]))
RTKs.append(SubTweakeyExtract(TKs[i], i))
return RTKs
################################################################################
def NonLinearLayer(state, subtweakey):
variables_xored = [0 for byte in range(0, 8)]
for byte in range(0,8):
variables_xored[byte] = state[byte] ^ subtweakey[byte]
variables_sboxed = [0 for byte in range(0, 8)]
for byte in range(0, 8):
variables_sboxed[byte] = Sbox[variables_xored[byte]]
state_output = [0 for byte in range(0, BLOCK_BYTES)]
for byte in range(0,BLOCK_BYTES):
state_output[byte] = state[byte]
for byte in range(0, 8):
state_output[15 - byte] ^= variables_sboxed[byte]
return state_output
def LinearLayer(state):
state_output = [0 for byte in range(0, BLOCK_BYTES)]
for byte in range(0, BLOCK_BYTES):
state_output[byte] = state[byte]
for byte in range(1, 8):
state_output[15] ^= state[byte]
for byte in range(9, 15):
state_output[byte] ^= state[7]
return state_output
def PermutationLayerEnc(state):
state_output = [0 for byte in range(0, BLOCK_BYTES)]
for byte in range(0, BLOCK_BYTES):
state_output[byte] = state[permutation[byte]]
return state_output
def PermutationLayerDec(state):
state_output = [0 for byte in range(0, BLOCK_BYTES)]
for byte in range(0, BLOCK_BYTES):
state_output[byte] = state[permutationInv[byte]]
return state_output
def OneRoundEGFNEnc(state, subtweakey):
state_non_linear = NonLinearLayer(state, subtweakey)
state_linear = LinearLayer(state_non_linear)
state_permutation = PermutationLayerEnc(state_linear)
return state_permutation
def LastRoundEGFN(state, subtweakey):
state_non_linear = NonLinearLayer(state, subtweakey)
state_linear = LinearLayer(state_non_linear)
return state_linear
def OneRoundEGFNDec(state, subtweakey):
state_non_linear = NonLinearLayer(state, subtweakey)
state_linear = LinearLayer(state_non_linear)
state_permutation = PermutationLayerDec(state_linear)
return state_permutation
def _rounds(key_bytes):
rounds = {
128: 32,
192: 36,
256: 42
}
return rounds[key_bytes*8]
################################################################################
# Lilliput TBC
def encrypt(tweak, key, message):
r = _rounds(len(key))
tweakey = BuildTweakey(tweak, key)
RTKs = TweakeyScheduleWhole(tweakey, r)
state = [0 for byte in range(0, BLOCK_BYTES)]
for byte in range(0, BLOCK_BYTES):
state[byte] = message[byte]
for i in range(0, r-1):
state_output = OneRoundEGFNEnc(state, RTKs[i])
for byte in range(0, BLOCK_BYTES):
state[byte] = state_output[byte]
state_output = LastRoundEGFN(state, RTKs[r-1])
return state_output
def decrypt(tweak, key, cipher):
r = _rounds(len(key))
tweakey = BuildTweakey(tweak, key)
RTKs = TweakeyScheduleWhole(tweakey, r)
state = [0 for byte in range(0, BLOCK_BYTES)]
for byte in range(0, BLOCK_BYTES):
state[byte] = cipher[byte]
for i in range(0, r-1):
state_output = OneRoundEGFNDec(state, RTKs[r-i-1])
for byte in range(0, BLOCK_BYTES):
state[byte] = state_output[byte]
state_output = LastRoundEGFN(state, RTKs[0])
return state_output
|