Loading scared/aes/selection_functions/encrypt.py +56 −11 Original line number Diff line number Diff line Loading @@ -28,6 +28,14 @@ def _delta_last_rounds(data, guesses): ).swapaxes(0, 1) def _first_key(key): return aes.key_schedule(key)[0] def _last_key(key): return aes.key_schedule(key)[-1] class FirstAddRoundKey: """Build an attack selection function which computes intermediate values after AES encrypt round key operation at first round, for guesses values. Loading @@ -39,9 +47,15 @@ class FirstAddRoundKey: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _add_round_key, words=words, guesses=guesses, target_tag=plaintext_tag) # self.target_tag = plaintext_tag def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _add_round_key, expected_key_function=_first_key, words=words, guesses=guesses, target_tag=plaintext_tag, key_tag=key_tag) class LastAddRoundKey: Loading @@ -55,8 +69,15 @@ class LastAddRoundKey: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _add_round_key, words=words, guesses=guesses, target_tag=ciphertext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _add_round_key, expected_key_function=_last_key, words=words, guesses=guesses, target_tag=ciphertext_tag, key_tag=key_tag ) class FirstSubBytes: Loading @@ -70,8 +91,16 @@ class FirstSubBytes: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _sub_bytes, words=words, guesses=guesses, target_tag=plaintext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _sub_bytes, expected_key_function=_first_key, words=words, guesses=guesses, target_tag=plaintext_tag, key_tag=key_tag ) class LastSubBytes: Loading @@ -85,8 +114,16 @@ class LastSubBytes: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _inv_sub_bytes, words=words, guesses=guesses, target_tag=ciphertext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _inv_sub_bytes, expected_key_function=_last_key, words=words, guesses=guesses, target_tag=ciphertext_tag, key_tag=key_tag ) class DeltaRLastRounds: Loading @@ -99,5 +136,13 @@ class DeltaRLastRounds: values from the metadata dict when selection function is called. """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _delta_last_rounds, words=words, guesses=guesses, target_tag=ciphertext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _delta_last_rounds, expected_key_function=_last_key, words=words, guesses=guesses, target_tag=ciphertext_tag, key_tag=key_tag ) scared/selection_functions/base.py +11 −3 Original line number Diff line number Diff line Loading @@ -80,7 +80,9 @@ class _AttackSelectionFunction(SelectionFunction): try: kargs[name] = kwargs[name] except KeyError as e: raise SelectionFunctionError(f'Missing key values in metadata {list(kwargs.keys())} for expected argument {e} of compute expected function {self}.') raise SelectionFunctionError( f'Missing key values in metadata {list(kwargs.keys())} for expected argument {e} of compute expected function {self}.' ) return self.expected_key_function(**kargs) Loading Loading @@ -137,11 +139,17 @@ def reverse_selection_function(function=None, words=None): class _AttackSelectionFunctionWrapped(_AttackSelectionFunction): def __init__(self, function, guesses, words, target_tag=None, target_name='data'): super().__init__(function=function, words=words, guesses=guesses) def __init__(self, function, guesses, words, expected_key_function=None, target_tag=None, key_tag=None, target_name='data', key_name='key'): super().__init__(function=function, words=words, guesses=guesses, expected_key_function=expected_key_function) self.target_tag = target_tag self.target_name = target_name self.key_name = key_name self.key_tag = key_tag def __call__(self, **kwargs): kwargs[self.target_name] = kwargs[self.target_tag] return super().__call__(**kwargs) def compute_expected_key(self, **kwargs): kwargs[self.key_name] = kwargs[self.key_tag] return super().compute_expected_key(**kwargs) tests/test_aes_selection_functions.py +99 −10 Original line number Diff line number Diff line Loading @@ -8,29 +8,38 @@ def test_aes_encrypt_first_round_key_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'plaintext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_first_round_key_with_alternative_args(): sf = aes.selection_functions.encrypt.FirstAddRoundKey( plaintext_tag='plain', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 assert sf.target_tag == 'plain' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(plain=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_last_round_key_with_default_arguments(): Loading @@ -38,29 +47,38 @@ def test_aes_encrypt_last_round_key_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_last_round_key_with_alternative_args(): sf = aes.selection_functions.encrypt.LastAddRoundKey( ciphertext_tag='nop', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 assert sf.target_tag == 'nop' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(nop=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_first_sub_bytes_with_default_arguments(): Loading @@ -68,6 +86,7 @@ def test_aes_encrypt_first_sub_bytes_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'plaintext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') Loading @@ -75,17 +94,22 @@ def test_aes_encrypt_first_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_first_sub_bytes_with_alternative_args(): sf = aes.selection_functions.encrypt.FirstSubBytes( plaintext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) assert sf.target_tag == 'foo' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') Loading @@ -93,6 +117,9 @@ def test_aes_encrypt_first_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_last_sub_bytes_with_default_arguments(): Loading @@ -100,6 +127,7 @@ def test_aes_encrypt_last_sub_bytes_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') Loading @@ -107,17 +135,22 @@ def test_aes_encrypt_last_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_last_sub_bytes_with_alternative_args(): sf = aes.selection_functions.encrypt.LastSubBytes( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) assert sf.target_tag == 'foo' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') Loading @@ -125,6 +158,9 @@ def test_aes_encrypt_last_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_delta_r_last_rounds_with_default_arguments(): Loading @@ -132,6 +168,7 @@ def test_aes_encrypt_delta_r_last_rounds_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') Loading @@ -140,13 +177,17 @@ def test_aes_encrypt_delta_r_last_rounds_with_default_arguments(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_delta_r_last_rounds_with_alternative_args(): sf = aes.selection_functions.encrypt.DeltaRLastRounds( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -159,6 +200,9 @@ def test_aes_encrypt_delta_r_last_rounds_with_alternative_args(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_decrypt_first_round_key_with_default_arguments(): Loading @@ -166,29 +210,38 @@ def test_aes_decrypt_first_round_key_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_decrypt_first_round_key_with_alternative_args(): sf = aes.selection_functions.decrypt.FirstAddRoundKey( ciphertext_tag='cif', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 assert sf.target_tag == 'cif' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(cif=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_decrypt_last_round_key_with_default_arguments(): Loading @@ -202,13 +255,18 @@ def test_aes_decrypt_last_round_key_with_default_arguments(): for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_last_round_key_with_alternative_args(): sf = aes.selection_functions.decrypt.LastAddRoundKey( plaintext_tag='nop', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 Loading @@ -219,6 +277,10 @@ def test_aes_decrypt_last_round_key_with_alternative_args(): for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(nop=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' def test_aes_decrypt_first_sub_bytes_with_default_arguments(): Loading @@ -233,13 +295,18 @@ def test_aes_decrypt_first_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_first_sub_bytes_with_alternative_args(): sf = aes.selection_functions.decrypt.FirstSubBytes( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -251,6 +318,10 @@ def test_aes_decrypt_first_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' def test_aes_decrypt_last_sub_bytes_with_default_arguments(): Loading @@ -265,13 +336,18 @@ def test_aes_decrypt_last_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_last_sub_bytes_with_alternative_args(): sf = aes.selection_functions.decrypt.LastSubBytes( plaintext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -283,6 +359,10 @@ def test_aes_decrypt_last_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' def test_aes_decrypt_delta_r_first_rounds_with_default_arguments(): Loading @@ -298,13 +378,18 @@ def test_aes_decrypt_delta_r_first_rounds_with_default_arguments(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_delta_r_first_rounds_with_alternative_args(): sf = aes.selection_functions.decrypt.DeltaRFirstRounds( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -317,3 +402,7 @@ def test_aes_decrypt_delta_r_first_rounds_with_alternative_args(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' Loading
scared/aes/selection_functions/encrypt.py +56 −11 Original line number Diff line number Diff line Loading @@ -28,6 +28,14 @@ def _delta_last_rounds(data, guesses): ).swapaxes(0, 1) def _first_key(key): return aes.key_schedule(key)[0] def _last_key(key): return aes.key_schedule(key)[-1] class FirstAddRoundKey: """Build an attack selection function which computes intermediate values after AES encrypt round key operation at first round, for guesses values. Loading @@ -39,9 +47,15 @@ class FirstAddRoundKey: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _add_round_key, words=words, guesses=guesses, target_tag=plaintext_tag) # self.target_tag = plaintext_tag def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _add_round_key, expected_key_function=_first_key, words=words, guesses=guesses, target_tag=plaintext_tag, key_tag=key_tag) class LastAddRoundKey: Loading @@ -55,8 +69,15 @@ class LastAddRoundKey: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _add_round_key, words=words, guesses=guesses, target_tag=ciphertext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _add_round_key, expected_key_function=_last_key, words=words, guesses=guesses, target_tag=ciphertext_tag, key_tag=key_tag ) class FirstSubBytes: Loading @@ -70,8 +91,16 @@ class FirstSubBytes: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _sub_bytes, words=words, guesses=guesses, target_tag=plaintext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, plaintext_tag='plaintext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _sub_bytes, expected_key_function=_first_key, words=words, guesses=guesses, target_tag=plaintext_tag, key_tag=key_tag ) class LastSubBytes: Loading @@ -85,8 +114,16 @@ class LastSubBytes: """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _inv_sub_bytes, words=words, guesses=guesses, target_tag=ciphertext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _inv_sub_bytes, expected_key_function=_last_key, words=words, guesses=guesses, target_tag=ciphertext_tag, key_tag=key_tag ) class DeltaRLastRounds: Loading @@ -99,5 +136,13 @@ class DeltaRLastRounds: values from the metadata dict when selection function is called. """ def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext'): return _decorated_selection_function(_AttackSelectionFunctionWrapped, _delta_last_rounds, words=words, guesses=guesses, target_tag=ciphertext_tag) def __new__(cls, guesses=_np.arange(256, dtype='uint8'), words=None, ciphertext_tag='ciphertext', key_tag='key'): return _decorated_selection_function( _AttackSelectionFunctionWrapped, _delta_last_rounds, expected_key_function=_last_key, words=words, guesses=guesses, target_tag=ciphertext_tag, key_tag=key_tag )
scared/selection_functions/base.py +11 −3 Original line number Diff line number Diff line Loading @@ -80,7 +80,9 @@ class _AttackSelectionFunction(SelectionFunction): try: kargs[name] = kwargs[name] except KeyError as e: raise SelectionFunctionError(f'Missing key values in metadata {list(kwargs.keys())} for expected argument {e} of compute expected function {self}.') raise SelectionFunctionError( f'Missing key values in metadata {list(kwargs.keys())} for expected argument {e} of compute expected function {self}.' ) return self.expected_key_function(**kargs) Loading Loading @@ -137,11 +139,17 @@ def reverse_selection_function(function=None, words=None): class _AttackSelectionFunctionWrapped(_AttackSelectionFunction): def __init__(self, function, guesses, words, target_tag=None, target_name='data'): super().__init__(function=function, words=words, guesses=guesses) def __init__(self, function, guesses, words, expected_key_function=None, target_tag=None, key_tag=None, target_name='data', key_name='key'): super().__init__(function=function, words=words, guesses=guesses, expected_key_function=expected_key_function) self.target_tag = target_tag self.target_name = target_name self.key_name = key_name self.key_tag = key_tag def __call__(self, **kwargs): kwargs[self.target_name] = kwargs[self.target_tag] return super().__call__(**kwargs) def compute_expected_key(self, **kwargs): kwargs[self.key_name] = kwargs[self.key_tag] return super().compute_expected_key(**kwargs)
tests/test_aes_selection_functions.py +99 −10 Original line number Diff line number Diff line Loading @@ -8,29 +8,38 @@ def test_aes_encrypt_first_round_key_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'plaintext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_first_round_key_with_alternative_args(): sf = aes.selection_functions.encrypt.FirstAddRoundKey( plaintext_tag='plain', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 assert sf.target_tag == 'plain' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(plain=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_last_round_key_with_default_arguments(): Loading @@ -38,29 +47,38 @@ def test_aes_encrypt_last_round_key_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_last_round_key_with_alternative_args(): sf = aes.selection_functions.encrypt.LastAddRoundKey( ciphertext_tag='nop', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 assert sf.target_tag == 'nop' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(nop=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_first_sub_bytes_with_default_arguments(): Loading @@ -68,6 +86,7 @@ def test_aes_encrypt_first_sub_bytes_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'plaintext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') Loading @@ -75,17 +94,22 @@ def test_aes_encrypt_first_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_first_sub_bytes_with_alternative_args(): sf = aes.selection_functions.encrypt.FirstSubBytes( plaintext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) assert sf.target_tag == 'foo' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') Loading @@ -93,6 +117,9 @@ def test_aes_encrypt_first_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_last_sub_bytes_with_default_arguments(): Loading @@ -100,6 +127,7 @@ def test_aes_encrypt_last_sub_bytes_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') Loading @@ -107,17 +135,22 @@ def test_aes_encrypt_last_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_last_sub_bytes_with_alternative_args(): sf = aes.selection_functions.encrypt.LastSubBytes( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) assert sf.target_tag == 'foo' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') Loading @@ -125,6 +158,9 @@ def test_aes_encrypt_last_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_encrypt_delta_r_last_rounds_with_default_arguments(): Loading @@ -132,6 +168,7 @@ def test_aes_encrypt_delta_r_last_rounds_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') Loading @@ -140,13 +177,17 @@ def test_aes_encrypt_delta_r_last_rounds_with_default_arguments(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_encrypt_delta_r_last_rounds_with_alternative_args(): sf = aes.selection_functions.encrypt.DeltaRLastRounds( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -159,6 +200,9 @@ def test_aes_encrypt_delta_r_last_rounds_with_alternative_args(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_decrypt_first_round_key_with_default_arguments(): Loading @@ -166,29 +210,38 @@ def test_aes_decrypt_first_round_key_with_default_arguments(): assert sf.guesses.tolist() == list(range(256)) assert sf.words is Ellipsis assert sf.target_tag == 'ciphertext' assert sf.key_tag == 'key' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 256, 16), dtype='uint8') for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) def test_aes_decrypt_first_round_key_with_alternative_args(): sf = aes.selection_functions.decrypt.FirstAddRoundKey( ciphertext_tag='cif', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 assert sf.target_tag == 'cif' assert sf.key_tag == 'thekey' assert isinstance(sf, selection_functions.SelectionFunction) data = np.random.randint(0, 255, (10, 16), dtype='uint8') expected = np.empty((10, 16, 16), dtype='uint8') for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(cif=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) def test_aes_decrypt_last_round_key_with_default_arguments(): Loading @@ -202,13 +255,18 @@ def test_aes_decrypt_last_round_key_with_default_arguments(): for i in np.arange(256, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_last_round_key_with_alternative_args(): sf = aes.selection_functions.decrypt.LastAddRoundKey( plaintext_tag='nop', words=6, guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == 6 Loading @@ -219,6 +277,10 @@ def test_aes_decrypt_last_round_key_with_alternative_args(): for i in np.arange(16, dtype='uint8'): expected[:, i, :] = np.bitwise_xor(data, i) assert np.array_equal(expected[:, :, 6], sf(nop=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' def test_aes_decrypt_first_sub_bytes_with_default_arguments(): Loading @@ -233,13 +295,18 @@ def test_aes_decrypt_first_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_first_sub_bytes_with_alternative_args(): sf = aes.selection_functions.decrypt.FirstSubBytes( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -251,6 +318,10 @@ def test_aes_decrypt_first_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.inv_sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' def test_aes_decrypt_last_sub_bytes_with_default_arguments(): Loading @@ -265,13 +336,18 @@ def test_aes_decrypt_last_sub_bytes_with_default_arguments(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected, sf(plaintext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_last_sub_bytes_with_alternative_args(): sf = aes.selection_functions.decrypt.LastSubBytes( plaintext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -283,6 +359,10 @@ def test_aes_decrypt_last_sub_bytes_with_alternative_args(): expected[:, i, :] = np.bitwise_xor(data, i) expected = aes.sub_bytes(expected) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[0] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey' def test_aes_decrypt_delta_r_first_rounds_with_default_arguments(): Loading @@ -298,13 +378,18 @@ def test_aes_decrypt_delta_r_first_rounds_with_default_arguments(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected, sf(ciphertext=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(key=master_key)) assert sf.key_tag == 'key' def test_aes_decrypt_delta_r_first_rounds_with_alternative_args(): sf = aes.selection_functions.decrypt.DeltaRFirstRounds( ciphertext_tag='foo', words=slice(2, 8), guesses=np.arange(16, dtype='uint8') guesses=np.arange(16, dtype='uint8'), key_tag='thekey' ) assert sf.guesses.tolist() == list(range(16)) assert sf.words == slice(2, 8, None) Loading @@ -317,3 +402,7 @@ def test_aes_decrypt_delta_r_first_rounds_with_alternative_args(): s = aes.inv_sub_bytes(state=expected) expected = np.bitwise_xor(aes.shift_rows(data), s.swapaxes(0, 1)).swapaxes(0, 1) assert np.array_equal(expected[:, :, slice(2, 8)], sf(foo=data)) master_key = np.random.randint(0, 255, (16,), dtype='uint8') expected_key = aes.key_schedule(master_key)[-1] assert np.array_equal(expected_key, sf.compute_expected_key(thekey=master_key)) assert sf.key_tag == 'thekey'