-
Notifications
You must be signed in to change notification settings - Fork 0
/
IDEA.py
125 lines (94 loc) · 3.09 KB
/
IDEA.py
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
def _mul(x, y):
assert 0 <= x <= 0xFFFF
assert 0 <= y <= 0xFFFF
if x == 0:
x = 0x10000
if y == 0:
y = 0x10000
r = (x * y) % 0x10001
if r == 0x10000:
r = 0
assert 0 <= r <= 0xFFFF
return r
def _KA_layer(x1, x2, x3, x4, round_keys):
assert 0 <= x1 <= 0xFFFF
assert 0 <= x2 <= 0xFFFF
assert 0 <= x3 <= 0xFFFF
assert 0 <= x4 <= 0xFFFF
z1, z2, z3, z4 = round_keys[0:4]
assert 0 <= z1 <= 0xFFFF
assert 0 <= z2 <= 0xFFFF
assert 0 <= z3 <= 0xFFFF
assert 0 <= z4 <= 0xFFFF
y1 = _mul(x1, z1)
y2 = (x2 + z2) % 0x10000
y3 = (x3 + z3) % 0x10000
y4 = _mul(x4, z4)
return y1, y2, y3, y4
def _MA_layer(y1, y2, y3, y4, round_keys):
assert 0 <= y1 <= 0xFFFF
assert 0 <= y2 <= 0xFFFF
assert 0 <= y3 <= 0xFFFF
assert 0 <= y4 <= 0xFFFF
z5, z6 = round_keys[4:6]
assert 0 <= z5 <= 0xFFFF
assert 0 <= z6 <= 0xFFFF
p = y1 ^ y3
q = y2 ^ y4
s = _mul(p, z5)
t = _mul((q + s) % 0x10000, z6)
u = (s + t) % 0x10000
x1 = y1 ^ t
x2 = y2 ^ u
x3 = y3 ^ t
x4 = y4 ^ u
return x1, x2, x3, x4
class IDEA:
def __init__(self, key):
self._keys = None
self.change_key(key)
def change_key(self, key):
assert 0 <= key < (1 << 128)
modulus = 1 << 128
sub_keys = []
for i in range(9 * 6):
sub_keys.append((key >> (112 - 16 * (i % 8))) % 0x10000)
if i % 8 == 7:
key = ((key << 25) | (key >> 103)) % modulus
keys = []
for i in range(9):
round_keys = sub_keys[6 * i: 6 * (i + 1)]
keys.append(tuple(round_keys))
self._keys = tuple(keys)
def encrypt(self, plaintext):
assert 0 <= plaintext < (1 << 64)
x1 = (plaintext >> 48) & 0xFFFF
x2 = (plaintext >> 32) & 0xFFFF
x3 = (plaintext >> 16) & 0xFFFF
x4 = plaintext & 0xFFFF
for i in range(8):
round_keys = self._keys[i]
y1, y2, y3, y4 = _KA_layer(x1, x2, x3, x4, round_keys)
x1, x2, x3, x4 = _MA_layer(y1, y2, y3, y4, round_keys)
x2, x3 = x3, x2
# Note: The words x2 and x3 are not permuted in the last round
# So here we use x1, x3, x2, x4 as input instead of x1, x2, x3, x4
# in order to cancel the last permutation x2, x3 = x3, x2
y1, y2, y3, y4 = _KA_layer(x1, x3, x2, x4, self._keys[8])
ciphertext = (y1 << 48) | (y2 << 32) | (y3 << 16) | y4
return ciphertext
def main():
# key = 0x00000000000000000000000000000000
# plain = 0x8000000000000000
# cipher = 0x8001000180008000
key = 0x2BD6459F82C5B300952C49104881FF48
plain = 0xF129A6601EF62A47
cipher = 0xEA024714AD5C4D84
print('key :', hex(key))
print('plaintext : ', hex(plain))
my_IDEA = IDEA(key)
encrypted = my_IDEA.encrypt(plain)
assert encrypted == cipher
print('ciphertext :', hex(cipher))
if __name__ == '__main__':
main()