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
| class RC5:
def __init__(self, w, R, key, strip_extra_nulls=False):
self.w = w # block size (32, 64 or 128 bits)
self.R = R # number of rounds (0 to 255)
self.key = key # key (0 to 2040 bits)
self.strip_extra_nulls = strip_extra_nulls
# some useful constants
self.T = 2 * (R + 1)
self.w4 = w // 4
self.w8 = w // 8
self.mod = 2 ** self.w
self.mask = self.mod - 1
self.b = len(key)
self.__keyAlign()
self.__keyExtend()
self.__shuffle()
def __lshift(self, val, n):
n %= self.w
return ((val << n) & self.mask) | ((val & self.mask) >> (self.w - n))
def __rshift(self, val, n):
n %= self.w
return ((val & self.mask) >> n) | (val << (self.w - n) & self.mask)
def __const(self): # constants generation
if self.w == 16:
return 0xB7E1, 0x9E37 # return P, Q values
elif self.w == 32:
return 0xB7E15163, 0x9E3779B9
elif self.w == 64:
return 0xB7E151628AED2A6B, 0x9E3779B97F4A7C15
def __keyAlign(self):
if self.b == 0: # key is empty
self.c = 1
elif self.b % self.w8:
self.key += b'\x00' * (self.w8 - self.b % self.w8) # fill key with \x00 bytes
self.b = len(self.key)
self.c = self.b // self.w8
else:
self.c = self.b // self.w8
L = [0] * self.c
for i in range(self.b - 1, -1, -1):
L[i // self.w8] = (L[i // self.w8] << 8) + self.key[i]
self.L = L
def __keyExtend(self):
P, Q = self.__const()
self.S = [(P + i * Q) % self.mod for i in range(self.T)]
def __shuffle(self):
i, j, A, B = 0, 0, 0, 0
for k in range(3 * max(self.c, self.T)):
A = self.S[i] = self.__lshift((self.S[i] + A + B), 3)
B = self.L[j] = self.__lshift((self.L[j] + A + B), A + B)
i = (i + 1) % self.T
j = (j + 1) % self.c
def encryptBlock(self, data):
A = int.from_bytes(data[:self.w8], byteorder='little')
B = int.from_bytes(data[self.w8:], byteorder='little')
A = (A + self.S[0]) % self.mod
B = (B + self.S[1]) % self.mod
for i in range(1, self.R + 1):
A = (self.__lshift((A ^ B), B) + self.S[2 * i]) % self.mod
B = (self.__lshift((A ^ B), A) + self.S[2 * i + 1]) % self.mod
return (A.to_bytes(self.w8, byteorder='little')
+ B.to_bytes(self.w8, byteorder='little'))
def decryptBlock(self, data):
A = int.from_bytes(data[:self.w8], byteorder='little')
B = int.from_bytes(data[self.w8:], byteorder='little')
for i in range(self.R, 0, -1):
B = self.__rshift(B - self.S[2 * i + 1], A) ^ A
A = self.__rshift(A - self.S[2 * i], B) ^ B
B = (B - self.S[1]) % self.mod
A = (A - self.S[0]) % self.mod
return (A.to_bytes(self.w8, byteorder='little')
+ B.to_bytes(self.w8, byteorder='little'))
def encryptFile(self, inpFileName, outFileName):
with open(inpFileName, 'rb') as inp, open(outFileName, 'wb') as out:
run = True
while run:
text = inp.read(self.w4)
if not text:
break
if len(text) != self.w4:
text = text.ljust(self.w4, b'\x00')
run = False
text = self.encryptBlock(text)
out.write(text)
def decryptFile(self, inpFileName, outFileName):
with open(inpFileName, 'rb') as inp, open(outFileName, 'wb') as out:
while True:
text = inp.read(self.w4)
if not text:
break
text = self.decryptBlock(text)
if self.strip_extra_nulls:
text = text.rstrip(b'\x00')
out.write(text)
def encryptBytes(self, data):
res, run = b'', True
while run:
temp = data[:self.w4]
if len(temp) != self.w4:
data = data.ljust(self.w4, b'\x00') # padding
run = False
res += self.encryptBlock(temp)
data = data[self.w4:]
if not data:
break
return res
def decryptBytes(self, data):
res, run = b'', True
while run:
temp = data[:self.w4]
if len(temp) != self.w4:
run = False
res += self.decryptBlock(temp)
data = data[self.w4:]
if not data:
break
return res.rstrip(b'\x00') # padding
|