Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ashutosh1206
GitHub Repository: ashutosh1206/crypton
Path: blob/master/Authenticated-Encryption/AES-GCM/AES-GCM-implementation.py
1402 views
1
from Crypto.Cipher import AES
2
from os import urandom
3
4
def xor(s1, s2):
5
"""
6
XOR two strings s1, s2
7
Strings s1 and s2 need not be of equal length
8
Whatever be the length of two strings, the longer string will be sliced
9
to a string of length equal to that of the shorter string
10
"""
11
if len(s1) == len(s2):
12
return "".join(chr(ord(i) ^ ord(j)) for i, j in zip(s1, s2))
13
elif len(s1) > len(s2):
14
return "".join(chr(ord(i) ^ ord(j)) for i, j in zip(s1[:len(s2)], s2))
15
elif len(s1) < len(s2):
16
return "".join(chr(ord(i) ^ ord(j)) for i, j in zip(s1, s2[:len(s1)]))
17
18
def str2bin(s1):
19
"""
20
Convert an ASCII string to corresponding binary string
21
"""
22
char_list = [bin(ord(i))[2:].zfill(8) for i in s1]
23
return "".join(char_list)
24
25
def bin2str(s1):
26
"""
27
Convert a binary string to corresponding ASCII string
28
"""
29
for i in s1:
30
assert i == "0" or i == "1"
31
bin_list = [int(s1[i:i+8], 2) for i in range(0, len(s1), 8)]
32
for i in bin_list:
33
assert i < 256
34
bin_list = [chr(i) for i in bin_list]
35
return "".join(bin_list)
36
37
def str2int(s1):
38
"""
39
Convert an ASCII string to it's corresponding integer format
40
"""
41
return int(s1.encode("hex"), 16)
42
43
def int2str(i):
44
"""
45
Convert an integer to corresponding ASCII string
46
"""
47
return hex(i)[2:].replace("L","").decode("hex")
48
49
def pad(s1):
50
"""
51
Pad a string to make it a multiple of blocksize.
52
If the string is already a multiple of blocksize, then simply return the string
53
"""
54
if len(s1) % 16 == 0:
55
return s1
56
else:
57
return s1 + "\x00"*(16 - len(s1) % 16)
58
59
60
class AES_GCM:
61
"""
62
Implementation of encryption/decryption in AES_GCM using AES_ECB of pycrypto
63
"""
64
def __init__(self, key, nonce, associated_data):
65
"""
66
Initialising key for cipher object
67
"""
68
try:
69
assert len(key) == 16 or len(key) == 24 or len(key) == 32
70
assert len(nonce) == 12
71
self.key = key
72
self.nonce = nonce
73
self.associated_data = pad(associated_data)
74
except:
75
raise ValueError("[+] Key length must be of length 16, 24 or 32 bytes and nonce must be of size 12 bytes")
76
77
def _encrypt(self, plaintext):
78
"""
79
Encryption of plaintext using key and nonce in CTR mode
80
96 bit nonce and 32 bit counter starting from 1
81
"""
82
plaintext = [plaintext[i:i+16] for i in range(0, len(plaintext), 16)]
83
ciphertext = ""
84
for i in range(len(plaintext)):
85
construct_nctr = bin2str(str2bin(self.nonce) + bin(pow(i+1, 1, 2**32))[2:].zfill(32))
86
assert len(construct_nctr) == 16
87
obj1 = AES.new(self.key, AES.MODE_ECB)
88
ct = obj1.encrypt(construct_nctr)
89
ciphertext += xor(plaintext[i], ct)
90
return ciphertext
91
92
def mod_polynomial_mult(self, a, b, p):
93
"""
94
Multiplication of polynomials a.b modulo an irreducible polynomial p over GF(2**128)
95
Assertion: a, b must already belong to the Galois Field GF(2**128)
96
"""
97
assert len(bin(a)[2:]) <= 128
98
assert len(bin(b)[2:]) <= 128
99
result = 0
100
for i in bin(b)[2:]:
101
result = result << 1
102
if int(i):
103
result = result ^ a
104
if result >> 128:
105
result = result ^ p
106
return result
107
108
def authtag_gen(self, ciphertext1):
109
"""
110
Generating auth-tag using ciphertext and associated data
111
"""
112
ciphertext = [str2int(ciphertext1[i:i+16]) for i in range(0, len(ciphertext1), 16)]
113
associated_data = [str2int(self.associated_data[i:i+16]) for i in range(0, len(self.associated_data), 16)]
114
115
obj1 = AES.new(self.key, AES.MODE_ECB)
116
117
# Step-1: Secret String Generation
118
H = str2int(obj1.encrypt("\x00"*16))
119
X = 0
120
p = (1<<128) + (1<<7) + (1<<2) + (1<<1) + 1
121
122
# Step-2: Modular Polynomial Multiplication of Associated Data blocks with H
123
for i in range(len(associated_data)):
124
X = self.mod_polynomial_mult(X, associated_data[i], p)
125
126
# Step-3: Modular Polynomial Multiplication of Ciphertext blocks with H
127
for i in range(len(ciphertext)):
128
X = self.mod_polynomial_mult(X, ciphertext[i], p)
129
130
# Step-4: Modular Polynomial Multiplication of H with (bit length of A concatenated with bit length of C)
131
la = bin(len(self.associated_data))[2:].zfill(64)
132
lc = bin(len(ciphertext1))[2:].zfill(64)
133
res = int(la + lc, 2)
134
S = self.mod_polynomial_mult(X, res, p)
135
136
# Step-5: XORing S with E(J0) ie. XORing S obtained above with ciphertext of (iv || ctr)
137
obj1 = AES.new(self.key, AES.MODE_ECB)
138
construct_nctr = bin2str(str2bin(self.nonce) + "0"*32)
139
T = S ^ str2int(obj1.encrypt(construct_nctr))
140
141
return int2str(T)
142
143
144
def _decrypt(self, ciphertext):
145
"""
146
Decryption of ciphertext using key and nonce in CTR mode
147
96 bit nonce and 32 bit counter starting from 1
148
"""
149
ciphertext = [ciphertext[i:i+16] for i in range(0, len(ciphertext), 16)]
150
plaintext = ""
151
for i in range(len(ciphertext)):
152
construct_nctr = bin2str(str2bin(self.nonce) + bin(pow(i+1, 1, 2**32))[2:].zfill(32))
153
assert len(construct_nctr) == 16
154
obj1 = AES.new(self.key, AES.MODE_ECB)
155
pt = obj1.encrypt(construct_nctr)
156
plaintext += xor(ciphertext[i], pt)
157
return plaintext
158