diff --git a/kmip/core/attributes.py b/kmip/core/attributes.py index fcf76ac..5185e52 100644 --- a/kmip/core/attributes.py +++ b/kmip/core/attributes.py @@ -1250,3 +1250,256 @@ class CustomAttribute(TextString): def __init__(self, value=None): super(CustomAttribute, self).__init__(value, Tags.ATTRIBUTE_VALUE) + + +class DerivationParameters(Struct): + """ + A set of values needed for key or secret derivation. + + A structure containing optional fields describing certain cryptographic + parameters to be used when performing key or secret derivation operations. + """ + + def __init__(self, + cryptographic_parameters=None, + initialization_vector=None, + derivation_data=None, + salt=None, + iteration_count=None): + """ + Construct a DerivationParameters struct. + + Args: + cryptographic_parameters (CryptographicParameters): A + CryptographicParameters struct containing the settings for + the derivation process. Optional, defaults to None. If not + included, the CryptographicParameters associated with the + managed object will be used instead. + initialization_vector (bytes): The IV value to be used with the + pseudo-random derivation function (PRF). Optional depending + on the PRF, defaults to None. + derivation_data (bytes): A data component to be used instead of + or with a derivation key to derive the new cryptographic + object. Optional, defaults to None. + salt (bytes): A salt value required by the PBKDF2 algorithm. + Optional, defaults to None. + iteration_count (bytes): An iteration count value required by + the PBKDF2 algorithm. Optional, defaults to None. + """ + super(DerivationParameters, self).__init__( + tag=Tags.DERIVATION_PARAMETERS + ) + + self._cryptographic_parameters = None + self._initialization_vector = None + self._derivation_data = None + self._salt = None + self._iteration_count = None + + self.cryptographic_parameters = cryptographic_parameters + self.initialization_vector = initialization_vector + self.derivation_data = derivation_data + self.salt = salt + self.iteration_count = iteration_count + + @property + def cryptographic_parameters(self): + return self._cryptographic_parameters + + @cryptographic_parameters.setter + def cryptographic_parameters(self, value): + if value is None: + self._cryptographic_parameters = None + elif isinstance(value, CryptographicParameters): + self._cryptographic_parameters = value + else: + raise TypeError( + "cryptographic parameters must be a CryptographicParameters " + "struct" + ) + + @property + def initialization_vector(self): + if self._initialization_vector: + return self._initialization_vector.value + else: + return None + + @initialization_vector.setter + def initialization_vector(self, value): + if value is None: + self._initialization_vector = None + elif isinstance(value, six.binary_type): + self._initialization_vector = ByteString( + value=value, + tag=enums.Tags.INITIALIZATION_VECTOR + ) + else: + raise TypeError("initialization vector must be bytes") + + @property + def derivation_data(self): + if self._derivation_data: + return self._derivation_data.value + else: + return None + + @derivation_data.setter + def derivation_data(self, value): + if value is None: + self._derivation_data = None + elif isinstance(value, six.binary_type): + self._derivation_data = ByteString( + value=value, + tag=enums.Tags.DERIVATION_DATA + ) + else: + raise TypeError("derivation data must be bytes") + + @property + def salt(self): + if self._salt: + return self._salt.value + else: + return None + + @salt.setter + def salt(self, value): + if value is None: + self._salt = None + elif isinstance(value, six.binary_type): + self._salt = ByteString( + value=value, + tag=enums.Tags.SALT + ) + else: + raise TypeError("salt must be bytes") + + @property + def iteration_count(self): + if self._iteration_count: + return self._iteration_count.value + else: + return None + + @iteration_count.setter + def iteration_count(self, value): + if value is None: + self._iteration_count = None + elif isinstance(value, six.integer_types): + self._iteration_count = Integer( + value=value, + tag=Tags.ITERATION_COUNT + ) + else: + raise TypeError("iteration count must be an integer") + + def read(self, input_stream): + """ + Read the data encoding the DerivationParameters struct and decode it + into its constituent parts. + + Args: + input_stream (stream): A data stream containing encoded object + data, supporting a read method; usually a BytearrayStream + object. + """ + super(DerivationParameters, self).read(input_stream) + local_stream = BytearrayStream(input_stream.read(self.length)) + + if self.is_tag_next( + enums.Tags.CRYPTOGRAPHIC_PARAMETERS, + local_stream + ): + self._cryptographic_parameters = CryptographicParameters() + self._cryptographic_parameters.read(local_stream) + + if self.is_tag_next(enums.Tags.INITIALIZATION_VECTOR, local_stream): + self._initialization_vector = ByteString( + tag=enums.Tags.INITIALIZATION_VECTOR + ) + self._initialization_vector.read(local_stream) + + if self.is_tag_next(enums.Tags.DERIVATION_DATA, local_stream): + self._derivation_data = ByteString(tag=enums.Tags.DERIVATION_DATA) + self._derivation_data.read(local_stream) + + if self.is_tag_next(enums.Tags.SALT, local_stream): + self._salt = ByteString(tag=enums.Tags.SALT) + self._salt.read(local_stream) + + if self.is_tag_next(Tags.ITERATION_COUNT, local_stream): + self._iteration_count = Integer(tag=Tags.ITERATION_COUNT) + self._iteration_count.read(local_stream) + + self.is_oversized(local_stream) + + def write(self, output_stream): + """ + Write the data encoding the DerivationParameters struct to a stream. + + Args: + output_stream (stream): A data stream in which to encode object + data, supporting a write method; usually a BytearrayStream + object. + """ + local_stream = BytearrayStream() + + if self._cryptographic_parameters: + self._cryptographic_parameters.write(local_stream) + if self._initialization_vector: + self._initialization_vector.write(local_stream) + if self._derivation_data: + self._derivation_data.write(local_stream) + if self._salt: + self._salt.write(local_stream) + if self._iteration_count: + self._iteration_count.write(local_stream) + + self.length = local_stream.length() + super(DerivationParameters, self).write(output_stream) + output_stream.write(local_stream.buffer) + + def __eq__(self, other): + if isinstance(other, DerivationParameters): + if self.cryptographic_parameters != other.cryptographic_parameters: + return False + elif self.initialization_vector != other.initialization_vector: + return False + elif self.derivation_data != other.derivation_data: + return False + elif self.salt != other.salt: + return False + elif self.iteration_count != other.iteration_count: + return False + else: + return True + + def __ne__(self, other): + if isinstance(other, DerivationParameters): + return not self == other + else: + return NotImplemented + + def __repr__(self): + args = ", ".join([ + "cryptographic_parameters={0}".format( + repr(self.cryptographic_parameters) + ), + "initialization_vector={0}".format(self.initialization_vector), + "derivation_data={0}".format(self.derivation_data), + "salt={0}".format(self.salt), + "iteration_count={0}".format( + self.iteration_count + ) + ]) + return "DerivationParameters({0})".format(args) + + def __str__(self): + return str({ + 'cryptographic_parameters': self.cryptographic_parameters, + 'initialization_vector': self.initialization_vector, + 'derivation_data': self.derivation_data, + 'salt': self.salt, + 'iteration_count': self.iteration_count + }) diff --git a/kmip/tests/unit/core/attributes/test_attributes.py b/kmip/tests/unit/core/attributes/test_attributes.py index e4bab50..1400e73 100644 --- a/kmip/tests/unit/core/attributes/test_attributes.py +++ b/kmip/tests/unit/core/attributes/test_attributes.py @@ -19,6 +19,7 @@ from kmip.core.attributes import ApplicationData from kmip.core.attributes import ApplicationNamespace from kmip.core.attributes import CertificateType from kmip.core.attributes import CryptographicParameters +from kmip.core.attributes import DerivationParameters from kmip.core.attributes import DigestValue from kmip.core.attributes import HashingAlgorithm from kmip.core.attributes import Name @@ -1596,3 +1597,804 @@ class TestCryptographicParameters(TestCase): observed = str(cryptographic_parameters) self.assertEqual(expected, observed) + + +class TestDerivationParameters(TestCase): + """ + Test suite for the DerivationParameters struct. + """ + + def setUp(self): + super(TestDerivationParameters, self).setUp() + + # Encoding obtained in part from the KMIP 1.1 testing document, + # Section 11.1. The rest of the encoding for KMIP 1.2+ features was + # built by hand; later KMIP testing documents do not include the + # encoding, so a manual construction is necessary. + # + # This encoding matches the following set of values: + # Cryptographic Parameters + # Block Cipher Mode - CBC + # Padding Method - PKCS5 + # Hashing Algorithm - SHA-1 + # Key Role Type - KEK + # Digital Signature Algorithm - SHA-256 with RSA + # Cryptographic Algorithm - AES + # Random IV - True + # IV Length - 96 + # Tag Length - 128 + # Fixed Field Length - 32 + # Invocation Field Length - 64 + # Counter Length - 0 + # Initial Counter Value - 1 + # Initialization Vector - 0x39487432492834A3 + # Derivation Data - 0xFAD98B6ACA6D87DD + # Salt - 0x8F99212AA15435CD + # Iteration Count - 10000 + + self.full_encoding = BytearrayStream( + b'\x42\x00\x32\x01\x00\x00\x01\x18' + b'\x42\x00\x2B\x01\x00\x00\x00\xD0' + b'\x42\x00\x11\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x5F\x05\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00' + b'\x42\x00\x38\x05\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00' + b'\x42\x00\x83\x05\x00\x00\x00\x04\x00\x00\x00\x0B\x00\x00\x00\x00' + b'\x42\x00\xAE\x05\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x00' + b'\x42\x00\x28\x05\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00' + b'\x42\x00\xC5\x06\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x42\x00\xCD\x02\x00\x00\x00\x04\x00\x00\x00\x60\x00\x00\x00\x00' + b'\x42\x00\xCE\x02\x00\x00\x00\x04\x00\x00\x00\x80\x00\x00\x00\x00' + b'\x42\x00\xCF\x02\x00\x00\x00\x04\x00\x00\x00\x20\x00\x00\x00\x00' + b'\x42\x00\xD2\x02\x00\x00\x00\x04\x00\x00\x00\x40\x00\x00\x00\x00' + b'\x42\x00\xD0\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xD1\x02\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x3A\x08\x00\x00\x00\x08\x39\x48\x74\x32\x49\x28\x34\xA3' + b'\x42\x00\x30\x08\x00\x00\x00\x08\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD' + b'\x42\x00\x84\x08\x00\x00\x00\x08\x8F\x99\x21\x2A\xA1\x54\x35\xCD' + b'\x42\x00\x3C\x02\x00\x00\x00\x04\x00\x00\x27\x10\x00\x00\x00\x00' + ) + + # Adapted from the full encoding above. This encoding matches the + # following set of values: + # Initialization Vector - 0x39487432492834A3 + # Derivation Data - 0xFAD98B6ACA6D87DD + + self.partial_encoding = BytearrayStream( + b'\x42\x00\x32\x01\x00\x00\x00\x20' + b'\x42\x00\x3A\x08\x00\x00\x00\x08\x39\x48\x74\x32\x49\x28\x34\xA3' + b'\x42\x00\x30\x08\x00\x00\x00\x08\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD' + ) + + self.empty_encoding = BytearrayStream( + b'\x42\x00\x32\x01\x00\x00\x00\x00' + ) + + def tearDown(self): + super(TestDerivationParameters, self).tearDown() + + def test_init(self): + """ + Test that a DerivationParameters struct can be constructed with + no arguments. + """ + derivation_parameters = DerivationParameters() + + self.assertEqual(None, derivation_parameters.cryptographic_parameters) + self.assertEqual(None, derivation_parameters.initialization_vector) + self.assertEqual(None, derivation_parameters.derivation_data) + self.assertEqual(None, derivation_parameters.salt) + self.assertEqual(None, derivation_parameters.iteration_count) + + def test_init_with_args(self): + """ + Test that a DerivationParameters struct can be constructed with + valid values. + """ + cryptographic_parameters = CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CTR, + padding_method=enums.PaddingMethod.NONE, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + key_role_type=enums.KeyRoleType.BDK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA1_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.TRIPLE_DES, + random_iv=False, + iv_length=128, + tag_length=256, + fixed_field_length=48, + invocation_field_length=60, + counter_length=20, + initial_counter_value=2 + ) + derivation_parameters = DerivationParameters( + cryptographic_parameters=cryptographic_parameters, + initialization_vector=b'\x39\x48\x74\x32\x49\x28\x34\xA3', + derivation_data=b'\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD', + salt=b'\x8F\x99\x21\x2A\xA1\x54\x35\xCD', + iteration_count=10000 + ) + + self.assertIsInstance( + derivation_parameters.cryptographic_parameters, + CryptographicParameters + ) + parameters = derivation_parameters.cryptographic_parameters + self.assertEqual( + enums.BlockCipherMode.CTR, + parameters.block_cipher_mode + ) + self.assertEqual( + enums.PaddingMethod.NONE, + parameters.padding_method + ) + self.assertEqual( + enums.HashingAlgorithm.SHA_256, + parameters.hashing_algorithm + ) + self.assertEqual( + enums.KeyRoleType.BDK, + parameters.key_role_type + ) + self.assertEqual( + enums.DigitalSignatureAlgorithm.SHA1_WITH_RSA_ENCRYPTION, + parameters.digital_signature_algorithm + ) + self.assertEqual( + enums.CryptographicAlgorithm.TRIPLE_DES, + parameters.cryptographic_algorithm + ) + self.assertEqual(False, parameters.random_iv) + self.assertEqual(128, parameters.iv_length) + self.assertEqual(256, parameters.tag_length) + self.assertEqual(48, parameters.fixed_field_length) + self.assertEqual(60, parameters.invocation_field_length) + self.assertEqual(20, parameters.counter_length) + self.assertEqual(2, parameters.initial_counter_value) + + self.assertEqual( + ( + b'\x39\x48\x74\x32\x49\x28\x34\xA3' + ), + derivation_parameters.initialization_vector + ) + self.assertEqual( + ( + b'\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD' + ), + derivation_parameters.derivation_data + ) + self.assertEqual( + ( + b'\x8F\x99\x21\x2A\xA1\x54\x35\xCD' + ), + derivation_parameters.salt + ) + self.assertEqual(10000, derivation_parameters.iteration_count) + + def test_invalid_cryptographic_parameters(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the cryptographic parameters of a DerivationParameters struct. + """ + kwargs = {'cryptographic_parameters': 'invalid'} + self.assertRaisesRegexp( + TypeError, + "cryptographic parameters must be a CryptographicParameters " + "struct", + DerivationParameters, + **kwargs + ) + + derivation_parameters = DerivationParameters() + args = (derivation_parameters, 'cryptographic_parameters', 'invalid') + self.assertRaisesRegexp( + TypeError, + "cryptographic parameters must be a CryptographicParameters " + "struct", + setattr, + *args + ) + + def test_invalid_initialization_vector(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the initialization vector of a DerivationParameters struct. + """ + derivation_parameters = DerivationParameters() + args = (derivation_parameters, 'initialization_vector', 0) + self.assertRaisesRegexp( + TypeError, + "initialization vector must be bytes", + setattr, + *args + ) + + def test_invalid_derivation_data(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the derivation data of a DerivationParameters struct. + """ + derivation_parameters = DerivationParameters() + args = (derivation_parameters, 'derivation_data', 0) + self.assertRaisesRegexp( + TypeError, + "derivation data must be bytes", + setattr, + *args + ) + + def test_invalid_salt(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the salt of a DerivationParameters struct. + """ + derivation_parameters = DerivationParameters() + args = (derivation_parameters, 'salt', 0) + self.assertRaisesRegexp( + TypeError, + "salt must be bytes", + setattr, + *args + ) + + def test_invalid_iteration_count(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the iteration count of a DerivationParameters struct. + """ + derivation_parameters = DerivationParameters() + args = (derivation_parameters, 'iteration_count', 'invalid') + self.assertRaisesRegexp( + TypeError, + "iteration count must be an integer", + setattr, + *args + ) + + def test_read(self): + """ + Test that a DerivationParameters struct can be read from a data + stream. + """ + derivation_parameters = DerivationParameters() + + self.assertEqual(None, derivation_parameters.cryptographic_parameters) + self.assertEqual(None, derivation_parameters.initialization_vector) + self.assertEqual(None, derivation_parameters.derivation_data) + self.assertEqual(None, derivation_parameters.salt) + self.assertEqual(None, derivation_parameters.iteration_count) + + derivation_parameters.read(self.full_encoding) + + self.assertIsInstance( + derivation_parameters.cryptographic_parameters, + CryptographicParameters + ) + cryptographic_parameters = \ + derivation_parameters.cryptographic_parameters + self.assertEqual( + enums.BlockCipherMode.CBC, + cryptographic_parameters.block_cipher_mode + ) + self.assertEqual( + enums.PaddingMethod.PKCS5, + cryptographic_parameters.padding_method + ) + self.assertEqual( + enums.HashingAlgorithm.SHA_1, + cryptographic_parameters.hashing_algorithm + ) + self.assertEqual( + enums.KeyRoleType.KEK, + cryptographic_parameters.key_role_type + ) + self.assertEqual( + enums.DigitalSignatureAlgorithm.SHA256_WITH_RSA_ENCRYPTION, + cryptographic_parameters.digital_signature_algorithm + ) + self.assertEqual( + enums.CryptographicAlgorithm.AES, + cryptographic_parameters.cryptographic_algorithm + ) + self.assertEqual(True, cryptographic_parameters.random_iv) + self.assertEqual(96, cryptographic_parameters.iv_length) + self.assertEqual(128, cryptographic_parameters.tag_length) + self.assertEqual(32, cryptographic_parameters.fixed_field_length) + self.assertEqual(64, cryptographic_parameters.invocation_field_length) + self.assertEqual(0, cryptographic_parameters.counter_length) + self.assertEqual(1, cryptographic_parameters.initial_counter_value) + + self.assertEqual( + ( + b'\x39\x48\x74\x32\x49\x28\x34\xA3' + ), + derivation_parameters.initialization_vector + ) + self.assertEqual( + ( + b'\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD' + ), + derivation_parameters.derivation_data + ) + self.assertEqual( + ( + b'\x8F\x99\x21\x2A\xA1\x54\x35\xCD' + ), + derivation_parameters.salt + ) + self.assertEqual(10000, derivation_parameters.iteration_count) + + def test_read_partial(self): + """ + Test that a DerivationParameters struct can be read from a partial + data stream. + """ + derivation_parameters = DerivationParameters() + + self.assertEqual(None, derivation_parameters.cryptographic_parameters) + self.assertEqual(None, derivation_parameters.initialization_vector) + self.assertEqual(None, derivation_parameters.derivation_data) + self.assertEqual(None, derivation_parameters.salt) + self.assertEqual(None, derivation_parameters.iteration_count) + + derivation_parameters.read(self.partial_encoding) + + self.assertEqual(None, derivation_parameters.cryptographic_parameters) + self.assertEqual( + ( + b'\x39\x48\x74\x32\x49\x28\x34\xA3' + ), + derivation_parameters.initialization_vector + ) + self.assertEqual( + ( + b'\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD' + ), + derivation_parameters.derivation_data + ) + self.assertEqual(None, derivation_parameters.salt) + self.assertEqual(None, derivation_parameters.iteration_count) + + def test_read_empty(self): + """ + Test that a DerivationParameters struct can be read from an empty + data stream. + """ + derivation_parameters = DerivationParameters() + + self.assertEqual(None, derivation_parameters.cryptographic_parameters) + self.assertEqual(None, derivation_parameters.initialization_vector) + self.assertEqual(None, derivation_parameters.derivation_data) + self.assertEqual(None, derivation_parameters.salt) + self.assertEqual(None, derivation_parameters.iteration_count) + + derivation_parameters.read(self.empty_encoding) + + self.assertEqual(None, derivation_parameters.cryptographic_parameters) + self.assertEqual(None, derivation_parameters.initialization_vector) + self.assertEqual(None, derivation_parameters.derivation_data) + self.assertEqual(None, derivation_parameters.salt) + self.assertEqual(None, derivation_parameters.iteration_count) + + def test_write(self): + """ + Test that a DerivationParameters struct can be written to a data + stream. + """ + cryptographic_parameters = CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ) + derivation_parameters = DerivationParameters( + cryptographic_parameters=cryptographic_parameters, + initialization_vector=b'\x39\x48\x74\x32\x49\x28\x34\xA3', + derivation_data=b'\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD', + salt=b'\x8F\x99\x21\x2A\xA1\x54\x35\xCD', + iteration_count=10000 + ) + stream = BytearrayStream() + derivation_parameters.write(stream) + + self.assertEqual(len(self.full_encoding), len(stream)) + self.assertEqual(str(self.full_encoding), str(stream)) + + def test_write_partial(self): + """ + Test that a partially defined DerivationParameters struct can be + written to a data stream. + """ + derivation_parameters = DerivationParameters( + initialization_vector=b'\x39\x48\x74\x32\x49\x28\x34\xA3', + derivation_data=b'\xFA\xD9\x8B\x6A\xCA\x6D\x87\xDD', + ) + stream = BytearrayStream() + derivation_parameters.write(stream) + + self.assertEqual(len(self.partial_encoding), len(stream)) + self.assertEqual(str(self.partial_encoding), str(stream)) + + def test_write_empty(self): + """ + Test that an empty DerivationParameters struct can be written to a + data stream. + """ + derivation_parameters = DerivationParameters() + stream = BytearrayStream() + derivation_parameters.write(stream) + + self.assertEqual(len(self.empty_encoding), len(stream)) + self.assertEqual(str(self.empty_encoding), str(stream)) + + def test_equal_on_equal(self): + """ + Test that the equality operator returns True when comparing two + DerivationParameters structs with the same data. + """ + a = DerivationParameters() + b = DerivationParameters() + + self.assertTrue(a == b) + self.assertTrue(b == a) + + a = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ), + initialization_vector=b'\x01\x02\x03\x04\x05\x06\x07\x08', + derivation_data=b'\x11\x22\x33\x44\x55\x66\x77\x88', + salt=b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + iteration_count=1000 + ) + b = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ), + initialization_vector=b'\x01\x02\x03\x04\x05\x06\x07\x08', + derivation_data=b'\x11\x22\x33\x44\x55\x66\x77\x88', + salt=b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + iteration_count=1000 + ) + + self.assertTrue(a == b) + self.assertTrue(b == a) + + def test_equal_on_not_equal_cryptographic_parameters(self): + """ + Test that the equality operator returns False when comparing two + DerivationParameters structs with different cryptographic parameters. + """ + a = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ) + b = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.GCM + ) + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_initialization_vector(self): + """ + Test that the equality operator returns False when comparing two + DerivationParameters structs with different initialization vectors. + """ + a = DerivationParameters(initialization_vector=b'\x01') + b = DerivationParameters(initialization_vector=b'\x02') + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_derivation_data(self): + """ + Test that the equality operator returns False when comparing two + DerivationParameters structs with different derivation data. + """ + a = DerivationParameters(derivation_data=b'\x01') + b = DerivationParameters(derivation_data=b'\x02') + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_salt(self): + """ + Test that the equality operator returns False when comparing two + DerivationParameters structs with different salts. + """ + a = DerivationParameters(salt=b'\x01') + b = DerivationParameters(salt=b'\x02') + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_iteration_count(self): + """ + Test that the equality operator returns False when comparing two + DerivationParameters structs with different iteration counts. + """ + a = DerivationParameters(iteration_count=1) + b = DerivationParameters(iteration_count=2) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_type_mismatch(self): + """ + Test that the equality operator returns False when comparing two + DerivationParameters structs with different types. + """ + a = DerivationParameters() + b = 'invalid' + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_not_equal_on_equal(self): + """ + Test that the inequality operator returns False when comparing two + DerivationParameters structs with the same data. + """ + a = DerivationParameters() + b = DerivationParameters() + + self.assertTrue(a == b) + self.assertTrue(b == a) + + a = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ), + initialization_vector=b'\x01\x02\x03\x04\x05\x06\x07\x08', + derivation_data=b'\x11\x22\x33\x44\x55\x66\x77\x88', + salt=b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + iteration_count=1000 + ) + b = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ), + initialization_vector=b'\x01\x02\x03\x04\x05\x06\x07\x08', + derivation_data=b'\x11\x22\x33\x44\x55\x66\x77\x88', + salt=b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + iteration_count=1000 + ) + + self.assertFalse(a != b) + self.assertFalse(b != a) + + def test_not_equal_on_not_equal_cryptographic_parameters(self): + """ + Test that the inequality operator returns True when comparing two + DerivationParameters structs with different cryptographic parameters. + """ + a = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ) + b = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.GCM + ) + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_initialization_vectors(self): + """ + Test that the inequality operator returns True when comparing two + DerivationParameters structs with different initialization vectors. + """ + a = DerivationParameters(initialization_vector=b'\x01') + b = DerivationParameters(initialization_vector=b'\x02') + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_derivation_data(self): + """ + Test that the inequality operator returns True when comparing two + DerivationParameters structs with different derivation data. + """ + a = DerivationParameters(derivation_data=b'\x01') + b = DerivationParameters(derivation_data=b'\x02') + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_salt(self): + """ + Test that the inequality operator returns True when comparing two + DerivationParameters structs with different salts. + """ + a = DerivationParameters(salt=b'\x01') + b = DerivationParameters(salt=b'\x02') + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_iteration_counts(self): + """ + Test that the inequality operator returns True when comparing two + DerivationParameters structs with different iteration counts. + """ + a = DerivationParameters(iteration_count=1) + b = DerivationParameters(iteration_count=2) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_type_mismatch(self): + """ + Test that the inequality operator returns True when comparing two + DerivationParameters structs with different types. + """ + a = DerivationParameters() + b = 'invalid' + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_repr(self): + """ + Test that repr can be applied to a DerivationParameters struct. + """ + derivation_parameters = DerivationParameters( + cryptographic_parameters=CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ), + initialization_vector=b'\x01\x02\x03\x04\x05\x06\x07\x08', + derivation_data=b'\x11\x22\x33\x44\x55\x66\x77\x88', + salt=b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + iteration_count=10000 + ) + + expected = ( + "DerivationParameters(" + "cryptographic_parameters=CryptographicParameters(" + "block_cipher_mode=BlockCipherMode.CBC, " + "padding_method=PaddingMethod.PKCS5, " + "hashing_algorithm=HashingAlgorithm.SHA_1, " + "key_role_type=KeyRoleType.KEK, " + "digital_signature_algorithm=" + "DigitalSignatureAlgorithm.SHA256_WITH_RSA_ENCRYPTION, " + "cryptographic_algorithm=CryptographicAlgorithm.AES, " + "random_iv=True, " + "iv_length=96, " + "tag_length=128, " + "fixed_field_length=32, " + "invocation_field_length=64, " + "counter_length=0, " + "initial_counter_value=1), " + "initialization_vector=" + str( + b'\x01\x02\x03\x04\x05\x06\x07\x08' + ) + ", " + "derivation_data=" + str( + b'\x11\x22\x33\x44\x55\x66\x77\x88' + ) + ", " + "salt=" + str(b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0') + ", " + "iteration_count=10000)" + ) + observed = repr(derivation_parameters) + + self.assertEqual(expected, observed) + + def test_str(self): + """ + Test that str can be applied to a DerivationParameters struct. + """ + cryptographic_parameters = CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.PKCS5, + hashing_algorithm=enums.HashingAlgorithm.SHA_1, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + SHA256_WITH_RSA_ENCRYPTION, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=96, + tag_length=128, + fixed_field_length=32, + invocation_field_length=64, + counter_length=0, + initial_counter_value=1 + ) + derivation_parameters = DerivationParameters( + cryptographic_parameters=cryptographic_parameters, + initialization_vector=b'\x01\x02\x03\x04\x05\x06\x07\x08', + derivation_data=b'\x11\x22\x33\x44\x55\x66\x77\x88', + salt=b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + iteration_count=10000 + ) + + expected = str({ + 'cryptographic_parameters': cryptographic_parameters, + 'initialization_vector': b'\x01\x02\x03\x04\x05\x06\x07\x08', + 'derivation_data': b'\x11\x22\x33\x44\x55\x66\x77\x88', + 'salt': b'\x12\x34\x56\x78\x9A\xBC\xDE\xF0', + 'iteration_count': 10000 + }) + observed = str(derivation_parameters) + + self.assertEqual(expected, observed)