├── requirements.txt ├── .gitignore ├── resources ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── banner.png ├── aes128_de.gif └── aes128_en.gif ├── LICENCE ├── index.py ├── utils ├── converter.py └── constant.py ├── aes128.py ├── aes192.py ├── aes256.py ├── aes512.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.23.4 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv-aes 2 | __pycache__ 3 | *.pyc -------------------------------------------------------------------------------- /resources/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/1.png -------------------------------------------------------------------------------- /resources/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/2.png -------------------------------------------------------------------------------- /resources/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/3.png -------------------------------------------------------------------------------- /resources/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/4.png -------------------------------------------------------------------------------- /resources/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/banner.png -------------------------------------------------------------------------------- /resources/aes128_de.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/aes128_de.gif -------------------------------------------------------------------------------- /resources/aes128_en.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandeep-shaw10/py-aes/HEAD/resources/aes128_en.gif -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Sandeep Shaw 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /index.py: -------------------------------------------------------------------------------- 1 | from aes128 import AES as AES_128 2 | from aes192 import AES as AES_192 3 | from aes256 import AES as AES_256 4 | from aes512 import AES as AES_512 5 | 6 | 7 | msg = 'Checking AES Encryption & Decryption on python' 8 | encode = '__all__' 9 | 10 | 11 | print('AES 128') 12 | key = 'Thats my Kung Fu' # 16 character / 128 bits 13 | encrypt_128 = AES_128() 14 | x = encrypt_128.encrypt(key, msg, encode) 15 | y = encrypt_128.decrypt(key, x['hex']) 16 | print(x) 17 | print(y, end='\n\n') 18 | 19 | 20 | print('AES 192') 21 | key = 'Thats my Kung Fu Panda !' # 24 character / 192 bits 22 | encrypt_192 = AES_192() 23 | x = encrypt_192.encrypt(key, msg, encode) 24 | y = encrypt_192.decrypt(key, x['hex']) 25 | print(x) 26 | print(y, end='\n\n') 27 | 28 | 29 | print('AES 256') 30 | key = 'Thats my Kung Fu Panda ! Style12' # 32 character / 256 bits 31 | encrypt_256 = AES_256() 32 | x = encrypt_256.encrypt(key, msg, encode) 33 | y = encrypt_256.decrypt(key, x['hex']) 34 | print(x) 35 | print(y, end='\n\n') 36 | 37 | 38 | print('AES 512') 39 | key = 'Thats my Kung Fu Panda ! Style12Thats my Kung Fu Panda ! Style12' # 64 character / 512 bits 40 | encrypt_512 = AES_512() 41 | x = encrypt_512.encrypt(key, msg, encode) 42 | y = encrypt_512.decrypt(key, x['hex']) 43 | print(x) 44 | print(y, end='\n\n') -------------------------------------------------------------------------------- /utils/converter.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from utils.constant import s_box, roundConstant, encryptMDS, mc2, mc3 3 | from utils.constant import invs_box, decryptMDS, mc9, mc11, mc13, mc14 4 | # aes512 5 | from utils.constant import roundConstant_8, encryptMDS_8, decryptMDS_8 6 | 7 | 8 | # Key to Matrix 9 | def keyToHexArray(key, row=4, col=4): 10 | arr = [] 11 | for i in key: 12 | arr.append(ord(i)) 13 | arr = np.array(arr) 14 | arr = arr.reshape(row,col) # 4*4 matrix 15 | return arr 16 | 17 | 18 | # Apply left shift / RotWord 19 | def arrayShift(arr, shift=-1): 20 | return np.roll(arr, shift) 21 | 22 | 23 | # S-box on 1D Array 24 | def arraySbox(arr): 25 | for i in range(0, len(arr)): 26 | lsb = arr[i] & 0b00001111 27 | msb = (arr[i] & 0b11110000) >> 4 28 | arr[i] = s_box[msb, lsb] 29 | return arr 30 | 31 | 32 | # Inverse S-box on 1D Array 33 | def arrayInvSbox(arr): 34 | for i in range(0, len(arr)): 35 | lsb = arr[i] & 0b00001111 36 | msb = (arr[i] & 0b11110000) >> 4 37 | arr[i] = invs_box[msb, lsb] 38 | return arr 39 | 40 | 41 | # XOR Operation on [arr1, arr2] or [arr1,arr2,rcon(i)] 42 | def xorArray(arr1, arr2, order=4, rcon=-1): 43 | xor_arr = [] 44 | if(arr1.shape == arr2.shape and (rcon >= -1 and rcon <= 9)): 45 | if(rcon == -1): 46 | for i in range(len(arr1)): 47 | val = arr1[i] ^ arr2[i] 48 | xor_arr.append(val) 49 | else: 50 | rcon_arr = roundConstant[rcon] 51 | if(order == 8): 52 | rcon_arr = roundConstant_8[rcon] 53 | for i in range(len(arr1)): 54 | val = arr1[i] ^ arr2[i] ^ rcon_arr[i] 55 | xor_arr.append(val) 56 | xor_arr = np.array(xor_arr) 57 | return xor_arr 58 | else: 59 | print('Array must be same dimension numpy OR Rcon: roundconstant must be 0-10') 60 | print(arr1, arr2, rcon) 61 | return False 62 | 63 | 64 | # Xor 2 2D array 65 | def addRoundKey(arr1, arr2): 66 | return np.bitwise_xor(arr1, arr2) 67 | 68 | 69 | # Substitution-box on 2D Array 70 | def subBytes(arr, inverse=False): 71 | for i in arr: 72 | if(not inverse): 73 | arraySbox(i) 74 | else: 75 | arrayInvSbox(i) 76 | return arr 77 | 78 | 79 | # Shift Row on 2D Array 80 | def shiftRow(arr, left=True, order=4): 81 | shifted_arr = [] 82 | for i in range(0, order): 83 | if(left): 84 | x = arrayShift(arr[:,i],-1*i) #Left circular shift: Encryption 85 | else: 86 | x = arrayShift(arr[:,i],i) #Right circular shift: Decryption 87 | shifted_arr.append(x) 88 | shifted_arr = np.array(shifted_arr) # Accurate 89 | return np.transpose(shifted_arr) 90 | 91 | 92 | # Mix Column 93 | def mixColumn(arr, order=4): 94 | arr = np.transpose(arr) 95 | mix_arr = np.zeros((order, order), dtype=int) 96 | encryptMDS_arr = encryptMDS 97 | if(order == 8): 98 | encryptMDS_arr = encryptMDS_8 99 | for i in range(0, order): 100 | for j in range(0, order): 101 | for k in range(0, order): 102 | if(encryptMDS_arr[i][k] == 1): 103 | mix_arr[i][j] ^= arr[k][j] 104 | lsb = arr[k][j] & 0b00001111 105 | msb = (arr[k][j] & 0b11110000) >> 4 106 | if(encryptMDS_arr[i][k] == 2): 107 | mix_arr[i][j] ^= mc2[msb,lsb] 108 | if(encryptMDS_arr[i][k] == 3): 109 | mix_arr[i][j] ^= mc3[msb,lsb] 110 | return np.transpose(mix_arr) 111 | 112 | 113 | # Inverse Mix Column 114 | def inverseMixColumn(arr, order=4): 115 | decryptMDS_arr = decryptMDS 116 | if(order == 8): 117 | decryptMDS_arr = decryptMDS_8 118 | arr = np.transpose(arr) 119 | mix_arr = np.zeros((order, order), dtype=int) 120 | for i in range(0, order): 121 | for j in range(0, order): 122 | for k in range(0, order): 123 | if(decryptMDS_arr[i][k] == 1): 124 | mix_arr[i][j] ^= arr[k][j] 125 | lsb = arr[k][j] & 0b00001111 126 | msb = (arr[k][j] & 0b11110000) >> 4 127 | if(decryptMDS_arr[i][k] == 9): 128 | mix_arr[i][j] ^= mc9[msb,lsb] 129 | if(decryptMDS_arr[i][k] == 11): 130 | mix_arr[i][j] ^= mc11[msb,lsb] 131 | if(decryptMDS_arr[i][k] == 13): 132 | mix_arr[i][j] ^= mc13[msb,lsb] 133 | if(decryptMDS_arr[i][k] == 14): 134 | mix_arr[i][j] ^= mc14[msb,lsb] 135 | return np.transpose(mix_arr) 136 | 137 | 138 | 139 | # Decryption: ecrypted hex to matrix 140 | ''' 141 | 4*4: 16 box => 128 bits => 32 in hex (representation) 142 | 8*8: 64 box => 512 bits => 128 in hex (representation) 143 | ''' 144 | def hexToMatrix(data, order=4): 145 | hexbit = order*order*2 146 | if(len(data) == hexbit): 147 | val = [data[i:i+2] for i in range(0, len(data), 2)] 148 | val = [int(x,16) for x in val] 149 | arr = np.array(val) 150 | arr = arr.reshape(order,order) # 4*4 matrix 151 | return arr 152 | else: 153 | print('length of encrypted data should be 32') -------------------------------------------------------------------------------- /aes128.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from base64 import b64encode, b64decode 3 | from utils.converter import keyToHexArray, arrayShift, arraySbox, xorArray, addRoundKey, subBytes, shiftRow, mixColumn 4 | from utils.converter import hexToMatrix, inverseMixColumn 5 | 6 | 7 | class AES: 8 | 9 | def __init__(self): 10 | self.ROUND = 10 11 | self.ORDER = 4 12 | self.ROUNDKEY = [] 13 | 14 | # Key Scheduling 15 | def __keySchedule(self, KEY): 16 | hexKey = keyToHexArray(KEY) 17 | self.ROUNDKEY.append(hexKey) 18 | for i in range(0, self.ROUND): 19 | prev_arr = self.ROUNDKEY[-1] 20 | last_col = prev_arr[self.ORDER-1] 21 | shift_col = arrayShift(last_col) 22 | sbox_col = arraySbox(shift_col) 23 | col_1 = xorArray(prev_arr[0], sbox_col, i) 24 | col_2 = xorArray(col_1, prev_arr[1]) 25 | col_3 = xorArray(col_2, prev_arr[2]) 26 | col_4 = xorArray(col_3, prev_arr[3]) 27 | new_arr = np.array([col_1, col_2, col_3, col_4]) 28 | self.ROUNDKEY.append(new_arr) 29 | 30 | # Encryption Process 31 | def __encryptProcess(self, TEXT): 32 | hexData = keyToHexArray(TEXT) 33 | cipher_arr = addRoundKey(hexData, self.ROUNDKEY[0]) 34 | for i in range(1, self.ROUND+1): 35 | arr = cipher_arr 36 | arr = subBytes(arr) 37 | arr = shiftRow(arr) 38 | if(i != self.ROUND): 39 | arr = mixColumn(arr) 40 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 41 | cipher_arr = arr 42 | return cipher_arr 43 | 44 | # Encryption Add Padding 45 | def __addPadding(self, data): 46 | bytes = 16 47 | bits_arr = [] 48 | while(True): 49 | if(len(data) > bytes): 50 | bits_arr.append(data[:bytes]) 51 | data = data[bytes:] 52 | else: 53 | space = bytes-len(data) 54 | bits_arr.append(data + chr(space)*space) 55 | break 56 | return bits_arr 57 | 58 | # Decryption Process 59 | def __decryptProcess(self, CIPHER_HEX): 60 | hexData = hexToMatrix(CIPHER_HEX) 61 | plain_arr = addRoundKey(hexData, self.ROUNDKEY[-1]) 62 | for i in range(self.ROUND-1, -1, -1): 63 | arr = plain_arr 64 | arr = shiftRow(arr, left=False) 65 | arr = subBytes(arr, inverse=True) 66 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 67 | if(i != 0): 68 | arr = inverseMixColumn(arr) 69 | plain_arr = arr 70 | return plain_arr 71 | 72 | # Decryption Delete Padding 73 | def __delPadding(self, data): 74 | verify = data[-1] 75 | if(verify >= 1 and verify <= 15): 76 | pad = data[16-verify:] 77 | sameCount = pad.count(verify) 78 | if(sameCount == verify): 79 | return data[:16-verify] 80 | return data 81 | return data 82 | 83 | #Encryption 84 | def encrypt(self, KEY, TEXT, type='hex'): 85 | text_arr = self.__addPadding(TEXT) 86 | self.__keySchedule(KEY) 87 | hex_ecrypt='' 88 | for i in text_arr: 89 | cipher_matrix = self.__encryptProcess(i) 90 | cipher_text = list(np.array(cipher_matrix).reshape(-1,)) 91 | for j in cipher_text: 92 | hex_ecrypt+=f'{j:02x}' 93 | self.ROUNDKEY = [] 94 | #conversion 95 | if(type == 'b64'): 96 | return b64encode(bytes.fromhex(hex_ecrypt)).decode() 97 | if(type == '0b'): 98 | return f'{int(hex_ecrypt, 16):0>b}' 99 | if(type == '__all__'): 100 | return { 101 | 'hex': hex_ecrypt, 102 | 'b64': b64encode(bytes.fromhex(hex_ecrypt)).decode(), 103 | '0b': bin(int(hex_ecrypt, 16))[2:].zfill(len(hex_ecrypt) * 4) 104 | } 105 | return hex_ecrypt 106 | 107 | # Decryption 108 | def decrypt(self, KEY, CIPHER, type='hex'): 109 | if type in ['hex', '0b', 'b64']: 110 | self.__keySchedule(KEY) 111 | data = '' 112 | 113 | if(type == 'b64'): 114 | CIPHER = b64decode(CIPHER).hex() 115 | 116 | if(type == '0b'): 117 | CIPHER = hex(int(CIPHER, 2)).replace('0x','') 118 | 119 | if(len(CIPHER) % 32 == 0 and len(CIPHER) > 0): 120 | examine = CIPHER 121 | while(len(examine) != 0): 122 | plain_matrix = self.__decryptProcess(examine[:32]) 123 | plain_arr = list(np.array(plain_matrix).reshape(-1,)) 124 | plain_arr = self.__delPadding(plain_arr) 125 | for j in plain_arr: 126 | data+=chr(j) 127 | if(len(examine)==32): 128 | examine='' 129 | else: 130 | examine=examine[32:] 131 | self.ROUNDKEY = [] 132 | return data 133 | 134 | else: 135 | raise Exception(f"Hex: {CIPHER}, should be non-empty multiple of 32bits") 136 | 137 | else: 138 | raise Exception(f"type := ['hex', '0b', 'b64'] but got '{type}'") 139 | 140 | 141 | if(__name__ == '__main__'): 142 | 143 | aes128 = AES() 144 | 145 | key = 'Thats my Kung Fu' 146 | msg = 'Checking AES 128 on Python' 147 | encode = '__all__' # hex, b64 => base64, 0b => binary 148 | 149 | x = aes128.encrypt(key, msg, encode) 150 | print(x) 151 | 152 | # decode from binary 153 | y = aes128.decrypt(key, x['0b'], '0b') 154 | print(y) 155 | 156 | # decode from base64 157 | y = aes128.decrypt(key, x['b64'], 'b64') 158 | print(y) 159 | 160 | # decode from hex (default) 161 | y = aes128.decrypt(key, x['hex']) 162 | print(y) -------------------------------------------------------------------------------- /aes192.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from base64 import b64encode, b64decode 3 | from utils.converter import keyToHexArray, arrayShift, arraySbox, xorArray, addRoundKey, subBytes, shiftRow, mixColumn 4 | from utils.converter import hexToMatrix, inverseMixColumn 5 | 6 | 7 | class AES: 8 | 9 | def __init__(self): 10 | self.ROUND = 12 11 | self.ROUNDKEY = [] 12 | 13 | # Key Scheduling 14 | def __keySchedule(self, KEY): 15 | ROW, COL = 6, 4 16 | EXPANSION = 8 17 | hexKey = keyToHexArray(KEY, ROW, COL) 18 | self.ROUNDKEY.append(hexKey) 19 | for i in range(0, EXPANSION): 20 | prev_arr = self.ROUNDKEY[-1] 21 | last_col = prev_arr[ROW-1] 22 | shift_col = arrayShift(last_col) 23 | sbox_col = arraySbox(shift_col) 24 | col_1 = xorArray(prev_arr[0], sbox_col, i) 25 | col_2 = xorArray(col_1, prev_arr[1]) 26 | col_3 = xorArray(col_2, prev_arr[2]) 27 | col_4 = xorArray(col_3, prev_arr[3]) 28 | col_5 = xorArray(col_4, prev_arr[4]) 29 | col_6 = xorArray(col_5, prev_arr[5]) 30 | new_arr = np.array([col_1, col_2, col_3, col_4, col_5, col_6]) 31 | self.ROUNDKEY.append(new_arr) 32 | self.__convertRoundKey() 33 | 34 | # Convert 9 4*6 Matrix to 13 4*4 Matrix 35 | def __convertRoundKey(self): 36 | self.ROUNDKEY = np.concatenate(self.ROUNDKEY) 37 | temp = [] 38 | for i in range(self.ROUND+1): 39 | temp.append(self.ROUNDKEY[i*4:i*4+4]) 40 | self.ROUNDKEY = temp 41 | 42 | # Encryption Process 43 | def __encryptProcess(self, TEXT): 44 | hexData = keyToHexArray(TEXT) 45 | cipher_arr = addRoundKey(hexData, self.ROUNDKEY[0]) 46 | for i in range(1, self.ROUND+1): 47 | arr = cipher_arr 48 | arr = subBytes(arr) 49 | arr = shiftRow(arr) 50 | if(i != self.ROUND): 51 | arr = mixColumn(arr) 52 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 53 | cipher_arr = arr 54 | return cipher_arr 55 | 56 | # Encryption Add Padding 57 | def __addPadding(self, data): 58 | bytes = 16 59 | bits_arr = [] 60 | while(True): 61 | if(len(data) > bytes): 62 | bits_arr.append(data[:bytes]) 63 | data = data[bytes:] 64 | else: 65 | space = bytes-len(data) 66 | bits_arr.append(data + chr(space)*space) 67 | break 68 | return bits_arr 69 | 70 | # Decryption Process 71 | def __decryptProcess(self, CIPHER_HEX): 72 | hexData = hexToMatrix(CIPHER_HEX) 73 | plain_arr = addRoundKey(hexData, self.ROUNDKEY[-1]) 74 | for i in range(self.ROUND-1, -1, -1): 75 | arr = plain_arr 76 | arr = shiftRow(arr, left=False) 77 | arr = subBytes(arr, inverse=True) 78 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 79 | if(i != 0): 80 | arr = inverseMixColumn(arr) 81 | plain_arr = arr 82 | return plain_arr 83 | 84 | # Decryption Delete Padding 85 | def __delPadding(self, data): 86 | verify = data[-1] 87 | bytes = 16 88 | if(verify >= 1 and verify <= bytes-1): 89 | pad = data[bytes-verify:] 90 | sameCount = pad.count(verify) 91 | if(sameCount == verify): 92 | return data[:bytes-verify] 93 | return data 94 | return data 95 | 96 | #Encryption 97 | def encrypt(self, KEY, TEXT, type='hex'): 98 | text_arr = self.__addPadding(TEXT) 99 | self.__keySchedule(KEY) 100 | hex_ecrypt='' 101 | for i in text_arr: 102 | cipher_matrix = self.__encryptProcess(i) 103 | cipher_text = list(np.array(cipher_matrix).reshape(-1,)) 104 | for j in cipher_text: 105 | hex_ecrypt+=f'{j:02x}' 106 | self.ROUNDKEY = [] 107 | #conversion 108 | if(type == 'b64'): 109 | return b64encode(bytes.fromhex(hex_ecrypt)).decode() 110 | if(type == '0b'): 111 | return f'{int(hex_ecrypt, 16):0>b}' 112 | if(type == '__all__'): 113 | return { 114 | 'hex': hex_ecrypt, 115 | 'b64': b64encode(bytes.fromhex(hex_ecrypt)).decode(), 116 | '0b': bin(int(hex_ecrypt, 16))[2:].zfill(len(hex_ecrypt) * 4) 117 | } 118 | return hex_ecrypt 119 | 120 | # Decryption 121 | def decrypt(self, KEY, CIPHER, type='hex'): 122 | if type in ['hex', '0b', 'b64']: 123 | self.__keySchedule(KEY) 124 | data = '' 125 | 126 | if(type == 'b64'): 127 | CIPHER = b64decode(CIPHER).hex() 128 | 129 | if(type == '0b'): 130 | CIPHER = hex(int(CIPHER, 2)).replace('0x','') 131 | 132 | if(len(CIPHER) % 32 == 0 and len(CIPHER) > 0): 133 | examine = CIPHER 134 | while(len(examine) != 0): 135 | plain_matrix = self.__decryptProcess(examine[:32]) 136 | plain_arr = list(np.array(plain_matrix).reshape(-1,)) 137 | plain_arr = self.__delPadding(plain_arr) 138 | for j in plain_arr: 139 | data+=chr(j) 140 | if(len(examine)==32): 141 | examine='' 142 | else: 143 | examine=examine[32:] 144 | self.ROUNDKEY = [] 145 | return data 146 | 147 | else: 148 | raise Exception(f"Hex: {CIPHER}, should be non-empty multiple of 32bits") 149 | 150 | else: 151 | raise Exception(f"type := ['hex', '0b', 'b64'] but got '{type}'") 152 | 153 | 154 | if(__name__ == '__main__'): 155 | 156 | aes192 = AES() 157 | 158 | key = 'Thats my Kung Fu12345678' 159 | msg = 'Checking AES 192 on Python' 160 | encode = '__all__' # hex, b64 => base64, 0b => binary 161 | 162 | x = aes192.encrypt(key, msg, encode) 163 | print(x) 164 | 165 | # decode from binary 166 | y = aes192.decrypt(key, x['0b'], '0b') 167 | print(y) 168 | 169 | # decode from base64 170 | y = aes192.decrypt(key, x['b64'], 'b64') 171 | print(y) 172 | 173 | # decode from hex (default) 174 | y = aes192.decrypt(key, x['hex']) 175 | print(y) -------------------------------------------------------------------------------- /aes256.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from base64 import b64encode, b64decode 3 | from utils.converter import keyToHexArray, arrayShift, arraySbox, xorArray, addRoundKey, subBytes, shiftRow, mixColumn 4 | from utils.converter import hexToMatrix, inverseMixColumn 5 | 6 | 7 | class AES: 8 | 9 | def __init__(self): 10 | self.ROUND = 14 11 | self.ROUNDKEY = [] 12 | 13 | # Key Scheduling 14 | def __keySchedule(self, KEY): 15 | ROW, COL = 8, 4 16 | EXPANSION = 7 17 | hexKey = keyToHexArray(KEY, ROW, COL) 18 | self.ROUNDKEY.append(hexKey) 19 | for i in range(0, EXPANSION): 20 | prev_arr = self.ROUNDKEY[-1] 21 | last_col = prev_arr[ROW-1] 22 | shift_col = arrayShift(last_col) 23 | sbox_col = arraySbox(shift_col) 24 | col_1 = xorArray(prev_arr[0], sbox_col, i) 25 | col_2 = xorArray(col_1, prev_arr[1]) 26 | col_3 = xorArray(col_2, prev_arr[2]) 27 | col_4 = xorArray(col_3, prev_arr[3]) 28 | # additional non-linear transformation after the fourth column 29 | # https://crypto.stackexchange.com/questions/20/what-are-the-practical-differences-between-256-bit-192-bit-and-128-bit-aes-enc#answer-1527 30 | col_5 = xorArray(arraySbox(np.copy(col_4)), prev_arr[4]) 31 | col_6 = xorArray(col_5, prev_arr[5]) 32 | col_7 = xorArray(col_6, prev_arr[6]) 33 | col_8 = xorArray(col_7, prev_arr[7]) 34 | new_arr = np.array([col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8]) 35 | self.ROUNDKEY.append(new_arr) 36 | self.__convertRoundKey() 37 | 38 | # Convert 8 4*8 Matrix to 15 4*4 Matrix 39 | def __convertRoundKey(self): 40 | self.ROUNDKEY = np.concatenate(self.ROUNDKEY) 41 | temp = [] 42 | for i in range(self.ROUND+1): 43 | temp.append(self.ROUNDKEY[i*4:i*4+4]) 44 | self.ROUNDKEY = temp 45 | 46 | # Encryption Process 47 | def __encryptProcess(self, TEXT): 48 | hexData = keyToHexArray(TEXT) 49 | cipher_arr = addRoundKey(hexData, self.ROUNDKEY[0]) 50 | for i in range(1, self.ROUND+1): 51 | arr = cipher_arr 52 | arr = subBytes(arr) 53 | arr = shiftRow(arr) 54 | if(i != self.ROUND): 55 | arr = mixColumn(arr) 56 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 57 | cipher_arr = arr 58 | return cipher_arr 59 | 60 | # Encryption Add Padding 61 | def __addPadding(self, data): 62 | bytes = 16 63 | bits_arr = [] 64 | while(True): 65 | if(len(data) > bytes): 66 | bits_arr.append(data[:bytes]) 67 | data = data[bytes:] 68 | else: 69 | space = bytes-len(data) 70 | bits_arr.append(data + chr(space)*space) 71 | break 72 | return bits_arr 73 | 74 | # Decryption Process 75 | def __decryptProcess(self, CIPHER_HEX): 76 | hexData = hexToMatrix(CIPHER_HEX) 77 | plain_arr = addRoundKey(hexData, self.ROUNDKEY[-1]) 78 | for i in range(self.ROUND-1, -1, -1): 79 | arr = plain_arr 80 | arr = shiftRow(arr, left=False) 81 | arr = subBytes(arr, inverse=True) 82 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 83 | if(i != 0): 84 | arr = inverseMixColumn(arr) 85 | plain_arr = arr 86 | return plain_arr 87 | 88 | # Decryption Delete Padding 89 | def __delPadding(self, data): 90 | verify = data[-1] 91 | bytes = 16 92 | if(verify >= 1 and verify <= bytes-1): 93 | pad = data[bytes-verify:] 94 | sameCount = pad.count(verify) 95 | if(sameCount == verify): 96 | return data[:bytes-verify] 97 | return data 98 | return data 99 | 100 | #Encryption 101 | def encrypt(self, KEY, TEXT, type='hex'): 102 | text_arr = self.__addPadding(TEXT) 103 | self.__keySchedule(KEY) 104 | hex_ecrypt='' 105 | for i in text_arr: 106 | cipher_matrix = self.__encryptProcess(i) 107 | cipher_text = list(np.array(cipher_matrix).reshape(-1,)) 108 | for j in cipher_text: 109 | hex_ecrypt+=f'{j:02x}' 110 | self.ROUNDKEY = [] 111 | #conversion 112 | if(type == 'b64'): 113 | return b64encode(bytes.fromhex(hex_ecrypt)).decode() 114 | if(type == '0b'): 115 | return f'{int(hex_ecrypt, 16):0>b}' 116 | if(type == '__all__'): 117 | return { 118 | 'hex': hex_ecrypt, 119 | 'b64': b64encode(bytes.fromhex(hex_ecrypt)).decode(), 120 | '0b': bin(int(hex_ecrypt, 16))[2:].zfill(len(hex_ecrypt) * 4) 121 | } 122 | return hex_ecrypt 123 | 124 | # Decryption 125 | def decrypt(self, KEY, CIPHER, type='hex'): 126 | if type in ['hex', '0b', 'b64']: 127 | self.__keySchedule(KEY) 128 | data = '' 129 | 130 | if(type == 'b64'): 131 | CIPHER = b64decode(CIPHER).hex() 132 | 133 | if(type == '0b'): 134 | CIPHER = hex(int(CIPHER, 2)).replace('0x','') 135 | 136 | if(len(CIPHER) % 32 == 0 and len(CIPHER) > 0): 137 | examine = CIPHER 138 | while(len(examine) != 0): 139 | plain_matrix = self.__decryptProcess(examine[:32]) 140 | plain_arr = list(np.array(plain_matrix).reshape(-1,)) 141 | plain_arr = self.__delPadding(plain_arr) 142 | for j in plain_arr: 143 | data+=chr(j) 144 | if(len(examine)==32): 145 | examine='' 146 | else: 147 | examine=examine[32:] 148 | self.ROUNDKEY = [] 149 | return data 150 | 151 | else: 152 | raise Exception(f"Hex: {CIPHER}, should be non-empty multiple of 32bits") 153 | 154 | else: 155 | raise Exception(f"type := ['hex', '0b', 'b64'] but got '{type}'") 156 | 157 | 158 | if(__name__ == '__main__'): 159 | 160 | aes256 = AES() 161 | 162 | key = 'Thats my Kung Fu1234567876543210' 163 | msg = 'Checking AES 256 on Python' 164 | encode = '__all__' # hex, b64 => base64, 0b => binary 165 | 166 | x = aes256.encrypt(key, msg, encode) 167 | print(x) 168 | 169 | # decode from binary 170 | y = aes256.decrypt(key, x['0b'], '0b') 171 | print(y) 172 | 173 | # decode from base64 174 | y = aes256.decrypt(key, x['b64'], 'b64') 175 | print(y) 176 | 177 | # decode from hex (default) 178 | y = aes256.decrypt(key, x['hex']) 179 | print(y) -------------------------------------------------------------------------------- /aes512.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from base64 import b64encode, b64decode 3 | from utils.converter import keyToHexArray, arrayShift, arraySbox, xorArray, addRoundKey, subBytes, shiftRow, mixColumn 4 | from utils.converter import hexToMatrix, inverseMixColumn 5 | 6 | 7 | class AES: 8 | 9 | def __init__(self): 10 | self.ROUND = 10 11 | self.ORDER = 8 12 | self.ROUNDKEY = [] 13 | 14 | # Key Scheduling 15 | def __keySchedule(self, KEY): 16 | ROW, COL = 8, 8 17 | hexKey = keyToHexArray(KEY, ROW, COL) 18 | self.ROUNDKEY.append(hexKey) 19 | #print(hexKey) 20 | for i in range(0, self.ROUND): 21 | prev_arr = self.ROUNDKEY[-1] 22 | last_col = prev_arr[ROW-1] 23 | shift_col = arrayShift(last_col) 24 | sbox_col = arraySbox(shift_col) 25 | col_1 = xorArray(prev_arr[0], sbox_col, self.ORDER, i) 26 | col_2 = xorArray(col_1, prev_arr[1], self.ORDER) 27 | col_3 = xorArray(col_2, prev_arr[2], self.ORDER) 28 | col_4 = xorArray(col_3, prev_arr[3]) 29 | # additional non-linear transformation after the fourth column 30 | # https://crypto.stackexchange.com/questions/20/what-are-the-practical-differences-between-256-bit-192-bit-and-128-bit-aes-enc#answer-1527 31 | col_5 = xorArray(arraySbox(np.copy(col_4)), prev_arr[4], self.ORDER) 32 | col_6 = xorArray(col_5, prev_arr[5], self.ORDER) 33 | col_7 = xorArray(col_6, prev_arr[6], self.ORDER) 34 | col_8 = xorArray(col_7, prev_arr[7], self.ORDER) 35 | new_arr = np.array([col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8]) 36 | self.ROUNDKEY.append(new_arr) 37 | self.__convertRoundKey() 38 | 39 | # Convert 8 4*8 Matrix to 15 4*4 Matrix 40 | def __convertRoundKey(self): 41 | self.ROUNDKEY = np.concatenate(self.ROUNDKEY) 42 | temp = [] 43 | for i in range(self.ROUND+1): 44 | temp.append(self.ROUNDKEY[i*8:i*8+8]) 45 | self.ROUNDKEY = temp 46 | 47 | # Encryption Process 48 | def __encryptProcess(self, TEXT): 49 | #print(TEXT) 50 | hexData = keyToHexArray(TEXT, self.ORDER, self.ORDER) 51 | #print(hexData) 52 | cipher_arr = addRoundKey(hexData, self.ROUNDKEY[0]) 53 | for i in range(1, self.ROUND+1): 54 | arr = cipher_arr 55 | arr = subBytes(arr) 56 | arr = shiftRow(arr, left=True, order=self.ORDER) 57 | if(i != self.ROUND): 58 | arr = mixColumn(arr, order=self.ORDER) 59 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 60 | cipher_arr = arr 61 | return cipher_arr 62 | 63 | # Encryption Add Padding 64 | def __addPadding(self, data): 65 | bytes = self.ORDER**2 66 | bits_arr = [] 67 | while(True): 68 | if(len(data) > bytes): 69 | bits_arr.append(data[:bytes]) 70 | data = data[bytes:] 71 | else: 72 | space = bytes-len(data) 73 | bits_arr.append(data + chr(space)*space) 74 | break 75 | return bits_arr 76 | 77 | # Decryption Process 78 | def __decryptProcess(self, CIPHER_HEX): 79 | hexData = hexToMatrix(CIPHER_HEX, self.ORDER) 80 | plain_arr = addRoundKey(hexData, self.ROUNDKEY[-1]) 81 | for i in range(self.ROUND-1, -1, -1): 82 | arr = plain_arr 83 | arr = shiftRow(arr, left=False, order=self.ORDER) 84 | arr = subBytes(arr, inverse=True) 85 | arr = addRoundKey(arr, self.ROUNDKEY[i]) 86 | if(i != 0): 87 | arr = inverseMixColumn(arr, order=self.ORDER) 88 | plain_arr = arr 89 | return plain_arr 90 | 91 | # Decryption Delete Padding 92 | def __delPadding(self, data): 93 | verify = data[-1] 94 | bytes = self.ORDER**2 95 | if(verify >= 1 and verify <= bytes-1): 96 | pad = data[bytes-verify:] 97 | sameCount = pad.count(verify) 98 | if(sameCount == verify): 99 | return data[:bytes-verify] 100 | return data 101 | return data 102 | 103 | #Encryption 104 | def encrypt(self, KEY, TEXT, type='hex'): 105 | text_arr = self.__addPadding(TEXT) 106 | self.__keySchedule(KEY) 107 | hex_ecrypt='' 108 | for i in text_arr: 109 | cipher_matrix = self.__encryptProcess(i) 110 | cipher_text = list(np.array(cipher_matrix).reshape(-1,)) 111 | for j in cipher_text: 112 | hex_ecrypt+=f'{j:02x}' 113 | self.ROUNDKEY = [] 114 | #conversion 115 | if(type == 'b64'): 116 | return b64encode(bytes.fromhex(hex_ecrypt)).decode() 117 | if(type == '0b'): 118 | return f'{int(hex_ecrypt, 16):0>b}' 119 | if(type == '__all__'): 120 | return { 121 | 'hex': hex_ecrypt, 122 | 'b64': b64encode(bytes.fromhex(hex_ecrypt)).decode(), 123 | '0b': bin(int(hex_ecrypt, 16))[2:].zfill(len(hex_ecrypt) * 4) 124 | } 125 | return hex_ecrypt 126 | 127 | # Decryption 128 | def decrypt(self, KEY, CIPHER, type='hex'): 129 | block = self.ORDER*self.ORDER*2 130 | if type in ['hex', '0b', 'b64']: 131 | self.__keySchedule(KEY) 132 | data = '' 133 | 134 | if(type == 'b64'): 135 | CIPHER = b64decode(CIPHER).hex() 136 | 137 | if(type == '0b'): 138 | CIPHER = hex(int(CIPHER, 2)).replace('0x','') 139 | 140 | if(len(CIPHER) % block == 0 and len(CIPHER) > 0): 141 | examine = CIPHER 142 | while(len(examine) != 0): 143 | plain_matrix = self.__decryptProcess(examine[:block]) 144 | plain_arr = list(np.array(plain_matrix).reshape(-1,)) 145 | plain_arr = self.__delPadding(plain_arr) 146 | for j in plain_arr: 147 | data+=chr(j) 148 | if(len(examine)==block): 149 | examine='' 150 | else: 151 | examine=examine[block:] 152 | self.ROUNDKEY = [] 153 | return data 154 | 155 | else: 156 | raise Exception(f"Hex: {CIPHER}, should be non-empty multiple of 32bits") 157 | 158 | else: 159 | raise Exception(f"type := ['hex', '0b', 'b64'] but got '{type}'") 160 | 161 | 162 | if(__name__ == '__main__'): 163 | 164 | aes512 = AES() 165 | 166 | key = 'Thats my Kung Fu1234567876543210Thats my Kung Fu1234567876543210' 167 | msg = 'Checking AES 512 on Python' 168 | encode = '__all__' # hex, b64 => base64, 0b => binary 169 | 170 | x = aes512.encrypt(key, msg, encode) 171 | print(x) 172 | 173 | # # decode from binary 174 | y = aes512.decrypt('Thats my Kung Fu1234567876543210Thats my Kung Fu1234567876543210', x['0b'], '0b') 175 | print(y) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![banner](./resources/banner.png) 2 | 3 |

4 | 5 | v1 6 | 7 | 8 | mit-license 9 | 10 | 11 | mit-license 12 | 13 | 14 | mit-license 15 | 16 |

17 | 18 |
19 | 20 | # Advance Encryption Standard 21 | 22 | ![py](https://img.shields.io/badge/Python-FFD43B?style=for-the-badge&logo=python&logoColor=gray) 23 | ![num-py](https://img.shields.io/badge/Numpy-777BB4?style=for-the-badge&logo=numpy&logoColor=white) 24 | ![num-py](https://img.shields.io/badge/base64-f75cd8?style=for-the-badge&logo=python&logoColor=white) 25 | 26 | ### AES-128 Encryption 27 | 28 | ![](./resources/aes128_en.gif) 29 | 30 | ### AES-128 Decryption 31 | 32 | ![](./resources/aes128_de.gif) 33 | 34 |
35 | 36 | ### Key Schedule 37 | 38 | ```py 39 | # ROUNDKEY := [] 40 | # hexKey := keyToHexArray(KEY) 41 | # ROUNDKEY.append(hexKey) 42 | # LOOP => 1 to ORDER 43 | # arr := Fetch last array of roundkey 44 | # xc := last row of arr 45 | # sc := shift row / ROTWORD 46 | # s-box-row := S_box(sc) 47 | # a := XOR row-1,s-box-row,rcon-1 48 | # b := XOR a,row-2 49 | # c := XOR b,row-3 50 | # d := XOR c,row-4 51 | # x := matrix [a,b,c,d] 52 | # append x to ROUNDKEY 53 | ``` 54 | 55 | ### Example 56 | Round Key: [Detailed Example](https://www.kavaliro.com/wp-content/uploads/2014/03/AES.pdf). 57 | 58 | Key: 'Thats my Kung Fu' => hex(54 68 61 74 73 20 6D 79 20 4B 75 6E 67 20 46 75) 59 | - `Round 0:` 54 68 61 74 73 20 6D 79 20 4B 75 6E 67 20 46 75 60 | - `Round 1:` E2 32 FC F1 91 12 91 88 B1 59 E4 E6 D6 79 A2 93 61 | - `Round 2:` 56 08 20 07 C7 1A B1 8F 76 43 55 69 A0 3A F7 FA 62 | - `Round 3:` D2 60 0D E7 15 7A BC 68 63 39 E9 01 C3 03 1E FB 63 | - `Round 4:` A1 12 02 C9 B4 68 BE A1 D7 51 57 A0 14 52 49 5B 64 | - `Round 5:` B1 29 3B 33 05 41 85 92 D2 10 D2 32 C6 42 9B 69 65 | - `Round 6:` BD 3D C2 B7 B8 7C 47 15 6A 6C 95 27 AC 2E 0E 4E 66 | - `Round 7:` CC 96 ED 16 74 EA AA 03 1E 86 3F 24 B2 A8 31 6A 67 | - `Round 8:` 8E 51 EF 21 FA BB 45 22 E4 3D 7A 06 56 95 4B 6C 68 | - `Round 9:` BF E2 BF 90 45 59 FA B2 A1 64 80 B4 F7 F1 CB D8 69 | - `Round 10:` 28 FD DE F8 6D A4 24 4A CC C0 A4 FE 3B 31 6F 26 70 | 71 | ![wikipedia algorithm](./resources/1.png) 72 | 73 | Key Schedule: [Wikipedia](https://en.wikipedia.org/wiki/AES_key_schedule) 74 | 75 |
76 |
77 | 78 | # `Rounds` & `Keys` 79 | 80 | ![aes-128](./resources/2.png) 81 | ![aes-128](./resources/3.png) 82 | ![aes-128](./resources/4.png) 83 | 84 |
85 |
86 | 87 | # Encryption Process 88 | 89 | ```py 90 | # cipher_arr := [] 91 | 92 | # Round 0 93 | # data_arr := dataToHexArray(data) 94 | # cipher_arr := XOR(data_arr, ROUNDKEY[0]) 95 | 96 | # Round [i] from 1 to 10 97 | # arr := prev_arr 98 | # arr := sBox(arr) 99 | # arr := shiftRow(arr) 100 | # arr := mixColumn(arr) <> 101 | # key_arr := ROUNDKEY[i] 102 | # xor_arr := XOR(data_arr, key_arr) 103 | 104 | # return cipher_arr 105 | ``` 106 | 107 | # Decryption Process 108 | 109 | ```py 110 | # plain_arr := [] 111 | 112 | # Round 0 113 | # data_arr := dataToHexArray(data) 114 | # plain_arr := XOR(data_arr, ROUNDKEY[0]) 115 | 116 | # Round [i] from 1 to 10 117 | # arr := prev_arr 118 | # arr := shiftRow(arr) 119 | # arr := sBox(arr) 120 | # key_arr := ROUNDKEY[10-i] 121 | # xor_arr := XOR(data_arr, key_arr) 122 | # arr := mixColumn(arr) <> 123 | 124 | # return plain_arr 125 | ``` 126 | 127 | 128 | 129 | # Using AES-128/192/256 130 | 131 | `index.py` 132 | 133 | ```py 134 | from aes128 import AES as AES_128 135 | from aes192 import AES as AES_192 136 | from aes256 import AES as AES_256 137 | from aes512 import AES as AES_512 138 | 139 | 140 | msg = 'Checking AES Encryption & Decryption on python' 141 | encode = '__all__' 142 | 143 | 144 | print('AES 128') 145 | key = 'Thats my Kung Fu' # 16 character / 128 bits 146 | encrypt_128 = AES_128() 147 | x = encrypt_128.encrypt(key, msg, encode) 148 | y = encrypt_128.decrypt(key, x['hex']) 149 | print(x) 150 | print(y, end='\n\n') 151 | 152 | 153 | print('AES 192') 154 | key = 'Thats my Kung Fu Panda !' # 24 character / 192 bits 155 | encrypt_192 = AES_192() 156 | x = encrypt_192.encrypt(key, msg, encode) 157 | y = encrypt_192.decrypt(key, x['hex']) 158 | print(x) 159 | print(y, end='\n\n') 160 | 161 | 162 | print('AES 256') 163 | key = 'Thats my Kung Fu Panda ! Style12' # 32 character / 256 bits 164 | encrypt_256 = AES_256() 165 | x = encrypt_256.encrypt(key, msg, encode) 166 | y = encrypt_256.decrypt(key, x['hex']) 167 | print(x) 168 | print(y, end='\n\n') 169 | 170 | 171 | print('AES 512') 172 | key = 'Thats my Kung Fu Panda ! Style12Thats my Kung Fu Panda ! Style12' # 64 character / 512 bits 173 | encrypt_512 = AES_512() 174 | x = encrypt_512.encrypt(key, msg, encode) 175 | y = encrypt_512.decrypt(key, x['hex']) 176 | print(x) 177 | print(y, end='\n\n') 178 | ``` 179 | 180 | `Create Virtual Environment` 181 | 182 | ```cmd 183 | py -m venv venv-aes 184 | ``` 185 | 186 | `Activate Virtual Environment` 187 | 188 | ```cmd 189 | source venv-aes/Scripts/activate 190 | ``` 191 | 192 | `Install Dependencies` 193 | 194 | ```cmd 195 | pip install -r requirements.txt 196 | ``` 197 | 198 | `Run` 199 | 200 | ```cmd 201 | py index.py 202 | ``` 203 | 204 | `Output` 205 | 206 | ```json 207 | AES 128 208 | { 209 | "hex": "aa04ae93ef2ccaa610b90f96074941601545f82d2e7a4d3dffeb97749d81108b3c104e9459ef5d0671cd97122d972bd0", 210 | "b64": "qgSuk+8syqYQuQ+WB0lBYBVF+C0uek09/+uXdJ2BEIs8EE6UWe9dBnHNlxItlyvQ", 211 | "0b": "101010100000010010101110100100111110111100101100110010101010011000010000101110010000111110010110000001110100100101000001011000000001010101000101111110000010110100101110011110100100110100111101111111111110101110010111011101001001110110000001000100001000101100111100000100000100111010010100010110011110111101011101000001100111000111001101100101110001001000101101100101110010101111010000" 212 | } 213 | Checking AES Encryption & Decryption on python 214 | 215 | AES 192 216 | { 217 | "hex": "dc999a4e37270708591d464de88e0c1702bcb5b4008a76ec8e9d023bc9ef67559801ad1a6ca936788a6b14d6c37baf1a", 218 | "b64": "3JmaTjcnBwhZHUZN6I4MFwK8tbQAinbsjp0CO8nvZ1WYAa0abKk2eIprFNbDe68a", 219 | "0b": "110111001001100110011010010011100011011100100111000001110000100001011001000111010100011001001101111010001000111000001100000101110000001010111100101101011011010000000000100010100111011011101100100011101001110100000010001110111100100111101111011001110101010110011000000000011010110100011010011011001010100100110110011110001000101001101011000101001101011011000011011110111010111100011010" 220 | } 221 | Checking AES Encryption & Decryption on python 222 | 223 | AES 256 224 | { 225 | "hex": "47719d9f4b4dc13c5647ef0962846a86f29942ac04b036d7385711a924aa1028e3d3b3cedccb8836cb1344ca80613f16", 226 | "b64": "R3Gdn0tNwTxWR+8JYoRqhvKZQqwEsDbXOFcRqSSqECjj07PO3MuINssTRMqAYT8W", 227 | "0b": "010001110111000110011101100111110100101101001101110000010011110001010110010001111110111100001001011000101000010001101010100001101111001010011001010000101010110000000100101100000011011011010111001110000101011100010001101010010010010010101010000100000010100011100011110100111011001111001110110111001100101110001000001101101100101100010011010001001100101010000000011000010011111100010110" 228 | } 229 | Checking AES Encryption & Decryption on python 230 | 231 | AES 512 232 | { 233 | "hex": "4972a7a011927bab546820136529c8add65a5bb4e860172dccf0e828e631b3f77d73bf42ab9dbeff65f9c9e6ff7d24e720b6ae9cc8ea333f78d02a67f5a42b88", 234 | "b64": "SXKnoBGSe6tUaCATZSnIrdZaW7ToYBctzPDoKOYxs/d9c79Cq52+/2X5yeb/fSTnILaunMjqMz940Cpn9aQriA==", 235 | "0b": "01001001011100101010011110100000000100011001001001111011101010110101010001101000001000000001001101100101001010011100100010101101110101100101101001011011101101001110100001100000000101110010110111001100111100001110100000101000111001100011000110110011111101110111110101110011101111110100001010101011100111011011111011111111011001011111100111001001111001101111111101111101001001001110011100100000101101101010111010011100110010001110101000110011001111110111100011010000001010100110011111110101101001000010101110001000" 236 | } 237 | Checking AES Encryption & Decryption on python 238 | ``` 239 | 240 |
241 |
242 | 243 | # AES-512 `Testing` 244 | 245 | Instead of traditional 4\*4 matrix it uses 8\*8 matrix with 246 | - Key Length = `512b` / `64B` 247 | - Rounds = 11 (initial + 9 intermediate + 1 final) -------------------------------------------------------------------------------- /utils/constant.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | roundConstant = np.array([ 5 | [0x01, 0x00, 0x00, 0x00], 6 | [0x02, 0x00, 0x00, 0x00], 7 | [0x04, 0x00, 0x00, 0x00], 8 | [0x08, 0x00, 0x00, 0x00], 9 | [0x10, 0x00, 0x00, 0x00], 10 | [0x20, 0x00, 0x00, 0x00], 11 | [0x40, 0x00, 0x00, 0x00], 12 | [0x80, 0x00, 0x00, 0x00], 13 | [0x1b, 0x00, 0x00, 0x00], 14 | [0x36, 0x00, 0x00, 0x00], 15 | ]) 16 | 17 | roundConstant_8 = np.array([ 18 | [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 19 | [0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 20 | [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 21 | [0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 22 | [0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 23 | [0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 24 | [0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 25 | [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 26 | [0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 27 | [0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 28 | ]) 29 | 30 | 31 | # Substitution Box: Encryption 32 | s_box = np.array([ 33 | [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76], 34 | [0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0], 35 | [0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15], 36 | [0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75], 37 | [0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84], 38 | [0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf], 39 | [0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8], 40 | [0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2], 41 | [0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73], 42 | [0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb], 43 | [0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79], 44 | [0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08], 45 | [0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a], 46 | [0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e], 47 | [0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf], 48 | [0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16], 49 | ]) 50 | 51 | 52 | # Substitution Box: Decryption 53 | invs_box = np.array([ 54 | [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb], 55 | [0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb], 56 | [0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e], 57 | [0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25], 58 | [0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92], 59 | [0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84], 60 | [0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06], 61 | [0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b], 62 | [0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73], 63 | [0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e], 64 | [0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b], 65 | [0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4], 66 | [0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f], 67 | [0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef], 68 | [0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61], 69 | [0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d], 70 | ]) 71 | 72 | 73 | # Rijndael Galois Field: Encryption 74 | encryptMDS = np.array([ 75 | [0x02, 0x03, 0x01, 0x01], 76 | [0x01, 0x02, 0x03, 0x01], 77 | [0x01, 0x01, 0x02, 0x03], 78 | [0x03, 0x01, 0x01, 0x02], 79 | ]) 80 | 81 | 82 | # Rijndael Galois Field: Encryption 8*8 83 | encryptMDS_8 = np.array([ 84 | [0x02, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01], 85 | [0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02], 86 | [0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01], 87 | [0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03], 88 | [0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01], 89 | [0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x01], 90 | [0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x01, 0x01], 91 | [0x01, 0x02, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01], 92 | ]) 93 | 94 | 95 | # Rijndael Galois Field: Decryption 96 | decryptMDS = np.array([ 97 | [0x0e, 0x0b, 0x0d, 0x09], 98 | [0x09, 0x0e, 0x0b, 0x0d], 99 | [0x0d, 0x09, 0x0e, 0x0b], 100 | [0x0b, 0x0d, 0x09, 0x0e], 101 | ]) 102 | 103 | # Rijndael Galois Field: Decryption 8*8 104 | decryptMDS_8 = np.array([ 105 | [0x0e, 0x01, 0x09, 0x01, 0x0d, 0x01, 0x0b, 0x01], 106 | [0x01, 0x09, 0x01, 0x0d, 0x01, 0x0b, 0x01, 0x0e], 107 | [0x09, 0x01, 0x0d, 0x01, 0x0b, 0x01, 0x0e, 0x01], 108 | [0x01, 0x0d, 0x01, 0x0b, 0x01, 0x0e, 0x01, 0x09], 109 | [0x0d, 0x01, 0x0b, 0x01, 0x0e, 0x01, 0x09, 0x01], 110 | [0x01, 0x0b, 0x01, 0x0e, 0x01, 0x09, 0x01, 0x0d], 111 | [0x0b, 0x01, 0x0e, 0x01, 0x09, 0x01, 0x0d, 0x01], 112 | [0x01, 0x0e, 0x01, 0x09, 0x01, 0x0d, 0x01, 0x0b], 113 | ]) 114 | 115 | 116 | # Look UP Table Mix Column: 117 | mc2 = np.array([ 118 | [0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e], 119 | [0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e], 120 | [0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e], 121 | [0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e], 122 | [0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e], 123 | [0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe], 124 | [0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde], 125 | [0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe], 126 | [0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05], 127 | [0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25], 128 | [0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45], 129 | [0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65], 130 | [0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85], 131 | [0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5], 132 | [0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5], 133 | [0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5] 134 | ]) 135 | 136 | 137 | mc3 = np.array([ 138 | [0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11], 139 | [0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21], 140 | [0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71], 141 | [0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41], 142 | [0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1], 143 | [0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1], 144 | [0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1], 145 | [0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81], 146 | [0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a], 147 | [0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba], 148 | [0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea], 149 | [0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda], 150 | [0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a], 151 | [0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a], 152 | [0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a], 153 | [0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a] 154 | ]) 155 | 156 | 157 | mc9 = np.array([ 158 | [0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77], 159 | [0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7], 160 | [0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c], 161 | [0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc], 162 | [0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01], 163 | [0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91], 164 | [0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a], 165 | [0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa], 166 | [0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b], 167 | [0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b], 168 | [0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0], 169 | [0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30], 170 | [0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed], 171 | [0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d], 172 | [0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6], 173 | [0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46] 174 | ]) 175 | 176 | # 0x0b 177 | mc11 = np.array([ 178 | [0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69], 179 | [0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9], 180 | [0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12], 181 | [0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2], 182 | [0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f], 183 | [0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f], 184 | [0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4], 185 | [0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54], 186 | [0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e], 187 | [0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e], 188 | [0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5], 189 | [0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55], 190 | [0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68], 191 | [0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8], 192 | [0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13], 193 | [0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3] 194 | ]) 195 | 196 | 197 | # 0x0d 198 | mc13 = np.array([ 199 | [0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b], 200 | [0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b], 201 | [0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0], 202 | [0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20], 203 | [0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26], 204 | [0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6], 205 | [0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d], 206 | [0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d], 207 | [0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91], 208 | [0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41], 209 | [0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a], 210 | [0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa], 211 | [0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc], 212 | [0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c], 213 | [0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47], 214 | [0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97] 215 | ]) 216 | 217 | 218 | # 0x0e 219 | mc14 = np.array([ 220 | [0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a], 221 | [0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba], 222 | [0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81], 223 | [0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61], 224 | [0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7], 225 | [0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17], 226 | [0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c], 227 | [0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc], 228 | [0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b], 229 | [0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb], 230 | [0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0], 231 | [0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20], 232 | [0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6], 233 | [0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56], 234 | [0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d], 235 | [0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d] 236 | ]) --------------------------------------------------------------------------------