Path: blob/master/Authenticated-Encryption/AES-GCM/AES-GCM-implementation.py
1402 views
from Crypto.Cipher import AES1from os import urandom23def xor(s1, s2):4"""5XOR two strings s1, s26Strings s1 and s2 need not be of equal length7Whatever be the length of two strings, the longer string will be sliced8to a string of length equal to that of the shorter string9"""10if len(s1) == len(s2):11return "".join(chr(ord(i) ^ ord(j)) for i, j in zip(s1, s2))12elif len(s1) > len(s2):13return "".join(chr(ord(i) ^ ord(j)) for i, j in zip(s1[:len(s2)], s2))14elif len(s1) < len(s2):15return "".join(chr(ord(i) ^ ord(j)) for i, j in zip(s1, s2[:len(s1)]))1617def str2bin(s1):18"""19Convert an ASCII string to corresponding binary string20"""21char_list = [bin(ord(i))[2:].zfill(8) for i in s1]22return "".join(char_list)2324def bin2str(s1):25"""26Convert a binary string to corresponding ASCII string27"""28for i in s1:29assert i == "0" or i == "1"30bin_list = [int(s1[i:i+8], 2) for i in range(0, len(s1), 8)]31for i in bin_list:32assert i < 25633bin_list = [chr(i) for i in bin_list]34return "".join(bin_list)3536def str2int(s1):37"""38Convert an ASCII string to it's corresponding integer format39"""40return int(s1.encode("hex"), 16)4142def int2str(i):43"""44Convert an integer to corresponding ASCII string45"""46return hex(i)[2:].replace("L","").decode("hex")4748def pad(s1):49"""50Pad a string to make it a multiple of blocksize.51If the string is already a multiple of blocksize, then simply return the string52"""53if len(s1) % 16 == 0:54return s155else:56return s1 + "\x00"*(16 - len(s1) % 16)575859class AES_GCM:60"""61Implementation of encryption/decryption in AES_GCM using AES_ECB of pycrypto62"""63def __init__(self, key, nonce, associated_data):64"""65Initialising key for cipher object66"""67try:68assert len(key) == 16 or len(key) == 24 or len(key) == 3269assert len(nonce) == 1270self.key = key71self.nonce = nonce72self.associated_data = pad(associated_data)73except:74raise ValueError("[+] Key length must be of length 16, 24 or 32 bytes and nonce must be of size 12 bytes")7576def _encrypt(self, plaintext):77"""78Encryption of plaintext using key and nonce in CTR mode7996 bit nonce and 32 bit counter starting from 180"""81plaintext = [plaintext[i:i+16] for i in range(0, len(plaintext), 16)]82ciphertext = ""83for i in range(len(plaintext)):84construct_nctr = bin2str(str2bin(self.nonce) + bin(pow(i+1, 1, 2**32))[2:].zfill(32))85assert len(construct_nctr) == 1686obj1 = AES.new(self.key, AES.MODE_ECB)87ct = obj1.encrypt(construct_nctr)88ciphertext += xor(plaintext[i], ct)89return ciphertext9091def mod_polynomial_mult(self, a, b, p):92"""93Multiplication of polynomials a.b modulo an irreducible polynomial p over GF(2**128)94Assertion: a, b must already belong to the Galois Field GF(2**128)95"""96assert len(bin(a)[2:]) <= 12897assert len(bin(b)[2:]) <= 12898result = 099for i in bin(b)[2:]:100result = result << 1101if int(i):102result = result ^ a103if result >> 128:104result = result ^ p105return result106107def authtag_gen(self, ciphertext1):108"""109Generating auth-tag using ciphertext and associated data110"""111ciphertext = [str2int(ciphertext1[i:i+16]) for i in range(0, len(ciphertext1), 16)]112associated_data = [str2int(self.associated_data[i:i+16]) for i in range(0, len(self.associated_data), 16)]113114obj1 = AES.new(self.key, AES.MODE_ECB)115116# Step-1: Secret String Generation117H = str2int(obj1.encrypt("\x00"*16))118X = 0119p = (1<<128) + (1<<7) + (1<<2) + (1<<1) + 1120121# Step-2: Modular Polynomial Multiplication of Associated Data blocks with H122for i in range(len(associated_data)):123X = self.mod_polynomial_mult(X, associated_data[i], p)124125# Step-3: Modular Polynomial Multiplication of Ciphertext blocks with H126for i in range(len(ciphertext)):127X = self.mod_polynomial_mult(X, ciphertext[i], p)128129# Step-4: Modular Polynomial Multiplication of H with (bit length of A concatenated with bit length of C)130la = bin(len(self.associated_data))[2:].zfill(64)131lc = bin(len(ciphertext1))[2:].zfill(64)132res = int(la + lc, 2)133S = self.mod_polynomial_mult(X, res, p)134135# Step-5: XORing S with E(J0) ie. XORing S obtained above with ciphertext of (iv || ctr)136obj1 = AES.new(self.key, AES.MODE_ECB)137construct_nctr = bin2str(str2bin(self.nonce) + "0"*32)138T = S ^ str2int(obj1.encrypt(construct_nctr))139140return int2str(T)141142143def _decrypt(self, ciphertext):144"""145Decryption of ciphertext using key and nonce in CTR mode14696 bit nonce and 32 bit counter starting from 1147"""148ciphertext = [ciphertext[i:i+16] for i in range(0, len(ciphertext), 16)]149plaintext = ""150for i in range(len(ciphertext)):151construct_nctr = bin2str(str2bin(self.nonce) + bin(pow(i+1, 1, 2**32))[2:].zfill(32))152assert len(construct_nctr) == 16153obj1 = AES.new(self.key, AES.MODE_ECB)154pt = obj1.encrypt(construct_nctr)155plaintext += xor(ciphertext[i], pt)156return plaintext157158