def aesMixColumns(bstr_state): """ TODO: make variable """ # go for columns state = makeNDArrayFrom(bstr_state, 4, 4).transpose() mds_matrix = np.array(mds_matrix_flat) mds_matrix = mds_matrix.reshape(4, 4) result = np.zeros(shape=(4, 4), dtype=np.int8) # number of columns # iterate over columns for i in range(len(state)): # iterate over bytes result_byte = 0 for bnum in range(len(state[i])): result[i][bnum] = mdsLookup(state[i][0], mds_matrix[bnum][0]) result[i][bnum] ^= mdsLookup(state[i][1], mds_matrix[bnum][1]) result[i][bnum] ^= mdsLookup(state[i][2], mds_matrix[bnum][2]) result[i][bnum] ^= mdsLookup(state[i][3], mds_matrix[bnum][3]) result = bytes(result.transpose().flatten()) return result # gmul variant """
def aesEncrypt(bstr_msg, bstr_key, num_bits, mode='ecb', bstr_IV=None): if len(bstr_key) != 16: # no key derivation yet print("Unsuitable key length!") exit(1) # without padding for now #bstr_msg = misc.padPKCS7(bstr_msg, 16) state_iter = stateGenerator(bstr_msg, 16) rounds = {128: 10, 192: 12, 256: 14} round_keys = aesKeyExpansion(bstr_key) cipher = b'' preceding_cipher_block = bstr_IV for state in state_iter: if mode == 'cbc': state = xorBytestrings(state, preceding_cipher_block) # initial (not actual) round state_trans = bytes(makeNDArrayFrom(state, 4, 4).transpose().flatten()) key_trans = bytes( makeNDArrayFrom(bstr_key, 4, 4).transpose().flatten()) bstr_state = aesAddRoundkey(state_trans, key_trans) for r in range(0, rounds[num_bits]): if r == rounds[num_bits] - 1: # last round no Mix Columns bstr_state = aesSubBytes(bstr_state) bstr_state = aesShiftRows(bstr_state) key_trans = bytes( makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten()) bstr_state = aesAddRoundkey(bstr_state, key_trans) else: bstr_state = aesSubBytes(bstr_state) bstr_state = aesShiftRows(bstr_state) bstr_state = aesMixColumns(bstr_state) key_trans = bytes( makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten()) bstr_state = aesAddRoundkey(bstr_state, key_trans) state_result = bytes( makeNDArrayFrom(bstr_state, 4, 4).transpose().flatten()) preceding_cipher_block = state_result cipher += state_result return cipher
def aesKeyExpansion(bstr_key): """ Returns the roundkeys a list of byte strings TODO: make length parameters variable """ if len(bstr_key) != 16 and len(bstr_key) != 24 and len(bstr_key) != 32: print("Invalid key length!") exit(1) numbits = len(bstr_key) * 8 rounds = {128: 10, 192: 12, 256: 14} round_keys = [] # transposed since we are operating on the columns prevkey = makeNDArrayFrom(bstr_key, 4, 4) newkey = b'' offset = 0 rcon_round = 1 while len(round_keys) < rounds[numbits]: # on every first 4 byte group of the 16 byte blocks perform rotate, # subbytes if offset == 0: word = bytes(prevkey[3]) word = aesKeyExpansionCore(word, rcon_round) rcon_round += 1 else: word = newkey[offset - 4:offset] word_from_prevkey = bytes(prevkey.flatten())[offset:offset + 4] word = xorBytestrings(word, word_from_prevkey) newkey += word offset += 4 if offset == 16: offset = 0 prevkey = makeNDArrayFrom(newkey, 4, 4) # transpose back and convert to byte string before appending to # result list newkey = bytes(makeNDArrayFrom(newkey, 4, 4).flatten()) round_keys.append(newkey) newkey = b'' return round_keys
def aesInvMixColumns(bstr_state): """ TODO: make variable """ # go for columns state = makeNDArrayFrom(bstr_state, 4, 4).transpose() inv_mds_matrix = np.array(inv_mds_matrix_flat) inv_mds_matrix = inv_mds_matrix.reshape(4, 4) result_array = np.zeros(shape=(4, 4), dtype=np.uint8) for c in range(len(state)): for b in range(len(state[c])): result_array[c][b] = gmul(state[c][0], inv_mds_matrix[b][0]) result_array[c][b] ^= gmul(state[c][1], inv_mds_matrix[b][1]) result_array[c][b] ^= gmul(state[c][2], inv_mds_matrix[b][2]) result_array[c][b] ^= gmul(state[c][3], inv_mds_matrix[b][3]) result = bytes(result_array.transpose().flatten()) return result
def aesDecrypt(bstr_cipher, bstr_key, num_bits, mode='ecb', bstr_IV=None): if len(bstr_key) != 16: # no key derivation yet print("Unsuitable key length!") exit(1) state_iter = stateGenerator(bstr_cipher, 16) rounds = {128: 10, 192: 12, 256: 14} round_keys = aesKeyExpansion(bstr_key) cipher = b'' prev_cipherstate = bstr_IV for state in state_iter: # initial round bstr_state = bytes(makeNDArrayFrom(state, 4, 4).transpose().flatten()) key_trans = bytes( makeNDArrayFrom(bstr_key, 4, 4).transpose().flatten()) for r in reversed(range(0, rounds[num_bits])): if r == rounds[num_bits] - 1: # first round no inverse MixColumns key_trans = bytes( makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten()) bstr_state = aesAddRoundkey(bstr_state, key_trans) bstr_state = aesInvShiftRows(bstr_state) bstr_state = aesInvSubBytes(bstr_state) else: key_trans = bytes( makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten()) bstr_state = aesAddRoundkey(bstr_state, key_trans) bstr_state = aesInvMixColumns(bstr_state) bstr_state = aesInvShiftRows(bstr_state) bstr_state = aesInvSubBytes(bstr_state) key_trans = bytes( makeNDArrayFrom(bstr_key, 4, 4).transpose().flatten()) bstr_state = aesAddRoundkey(bstr_state, key_trans) bstr_state = bytes( makeNDArrayFrom(bstr_state, 4, 4).transpose().flatten()) if mode == 'cbc': bstr_state = xorBytestrings(bstr_state, prev_cipherstate) prev_cipherstate = state cipher += bstr_state #cipher = misc.unpadPKCS7(cipher, 16) return cipher
def aesInvShiftRows(bstr_state): arr = makeNDArrayFrom(bstr_state, 4, 4) for i in range(len(arr)): arr[i] = rotateList(arr[i], i, 'r') return bytes(arr.flatten())