def leaky_encipher(key, A): # Let me denote the state in AES as follows: # A = input to AES # Z = enciphering of A (aka, result after applying all 10 rounds) # Y = value just before the final AddRoundKey # X = value at the beginning of the 10th round, before ShiftRows and SubBytes as well (remember: the final round lacks MixColumns) # So the final round of AES looks like this: # X -> [SubBytes] -> [ShiftRows] -> Y -> [AddRoundKey, aka strxor with lastroundkey] -> Z # First, perform all 10 rounds of AES assert(len(A) == 16) permutation = AES.new(key, AES.MODE_ECB) Z = permutation.encrypt(A) # This is the desired output! Now we just have to simulate the cache lines... # Now go back one round of AES, from the end back to the beginning. We begin with AddRoundKey, which is its own inverse. lastroundkey = aes128_lastroundkey(key) # This is the key used in the final xor step of AES. You need the aeskeyexp helper file for this. Y = strxor(Z, lastroundkey) # xor is its own inverse #print("key",lastroundkey) Yvec = [ord(i) for i in Y] # Transform the string into a vector of bytes #print("Yvec",Yvec) sinv_yvec = [Sinv[y] for y in Yvec] # ShiftRows is irrelevant here because it merely permutes the order of bytes, and we won't care about that when we output a set. # So it remains to perform an inverse SubBytes operation. #X = frozenset(map(Sinv, Yvec)) # Apply Sinv to each byte of the state, and form the *set* of resulting values X = frozenset(sinv_yvec) # Return both the ciphertext and the set of bytes at the start of the 10th round return [Z, X]
def leaky_encipher_example(A): """performs an AES encipher on the input 16-bytes input `file_bytes` Args: A (bytes) : 16-bytes input to be passed to AES for enciphering Output: ret (bytes, set) : tuple with the actual ciphertext and a Python set stating which cachelines are accessed during the final round's SubBytes operation. """ key = TEST_KEY # NOTE: Just as an example, a random key would be used to test your code # Let me denote the state in AES as follows: # A = input to AES # Z = enciphering of A (aka, result after applying all 10 rounds) # Y = value just before the final AddRoundKey # X = value at the beginning of the 10th round, before ShiftRows and SubBytes as well (remember: the final round lacks MixColumns) # So the final round of AES looks like this: # X -> [SubBytes] -> [ShiftRows] -> Y -> [AddRoundKey, aka strxor with lastroundkey] -> Z # First, perform all 10 rounds of AES assert (len(A) == 16) permutation = AES.new(key.encode('ascii'), AES.MODE_ECB) Z = permutation.encrypt( A ) # This is the desired output! Now we just have to simulate the cache lines... # Now go back one round of AES, from the end back to the beginning. We begin with AddRoundKey, which is its own inverse. lastroundkey = aes128_lastroundkey( key ) # This is the key used in the final xor step of AES. You need the aeskeyexp helper file for this. Yvec = strxor(Z, lastroundkey) # xor is its own inverse # ShiftRows is irrelevant here because it merely permutes the order of bytes, and we won't care about that when we output a set. # So it remains to perform an inverse SubBytes operation. X = frozenset( map(Sinv, Yvec) ) # Apply Sinv to each byte of the state, and form the *set* of resulting values # Return both the ciphertext and the set of bytes at the start of the 10th round return [Z, X]
def less_leaky_encipher_example(A): key = TEST_KEY # NOTE: Just as an example, a random key would be used to test your code # I use the variables A, X, Y, and Z here just as in the previous routine # Let's compute Yvec just as we did before. assert (len(A) == 16) permutation = AES.new(key.encode('ascii'), AES.MODE_ECB) Z = permutation.encrypt(A) lastroundkey = aes128_lastroundkey(key) Yvec = strxor(Z, lastroundkey) # Now we invert the SubBytes operation, but only store the set of the upper 4 bits of the result Xvec = map( Sinv, Yvec ) # This is the *list* of full bytes at the start of the 10th round X = frozenset( map(lambda x: x >> 4, Xvec) ) # And now we form the *set* of values with the lower 4 bits truncated # Return the enciphering of A together with the *set* of cache lines accessed in round 10 return [Z, X]
def less_leaky_encipher(key, A): # I use the variables A, X, Y, and Z here just as in the previous routine # Let's compute Yvec just as we did before. assert(len(A) == 16) permutation = AES.new(key, AES.MODE_ECB) Z = permutation.encrypt(A) lastroundkey = aes128_lastroundkey(key) #print("key",lastroundkey) Y = strxor(Z, lastroundkey) Yvec = [ord(i) for i in Y] # Now we invert the SubBytes operation, but only store the set of the upper 4 bits of the result #Xvec = map(Sinv, Yvec) # This is the *list* of full bytes at the start of the 10th round Xvec = [Sinv[y] for y in Yvec] X = frozenset( map(lambda x: x >> 4, Xvec) ) # And now we form the *set* of values with the lower 4 bits truncated # Return the enciphering of A together with the *set* of cache lines accessed in round 10 return [Z, X]