diff --git a/kmip/core/objects.py b/kmip/core/objects.py index 09bab41..206b7a8 100644 --- a/kmip/core/objects.py +++ b/kmip/core/objects.py @@ -4002,3 +4002,501 @@ class DefaultsInformation(primitives.Struct): return not (self == other) else: return NotImplemented + + +class RNGParameters(primitives.Struct): + """ + A structure containing parameters for a random number generator. + + This is intended for use with KMIP 1.3+. + + Attributes: + rng_algorithm: An RNGAlgorithm enumeration identifying the type of + random number generator to which the parameters pertain. + cryptographic_algorithm: A CryptographicAlgorithm enumeration + identifying the cryptographic algorithm used by the RNG. + cryptographic_length: An integer specifying the length to be used + with the cryptographic algorithm. + hashing_algorithm: A HashingAlgorithm enumeration identifying the + hashing algorithm used by the RNG. + drbg_algorithm: A DRBGAlgorithm enumeration identifying the DRBG + algorithm used by the RNG. + recommended_curve: A RecommendedCurve enumeration identifying the + recommended curve used by the RNG. + fips186_variation: A FIPS186Variation enumeration identifying the + FIPS186 variation used by the RNG. + prediction_resistance: A boolean indicating whether or not + prediction resistance is leveraged by the RNG. + """ + + def __init__(self, + rng_algorithm=None, + cryptographic_algorithm=None, + cryptographic_length=None, + hashing_algorithm=None, + drbg_algorithm=None, + recommended_curve=None, + fips186_variation=None, + prediction_resistance=None): + """ + Construct an RNGParameters structure. + + Args: + rng_algorithm (enum): An RNGAlgorithm enumeration identifying the + type of random number generator to which the parameters + pertain. Optional, defaults to None. Required for read/write. + cryptographic_algorithm (enum): A CryptographicAlgorithm + enumeration identifying the cryptographic algorithm used by + the RNG. Optional, defaults to None. + cryptographic_length (int): An integer specifying the length to be + used with the cryptographic algorithm. Optional, defaults to + None. + hashing_algorithm (enum): A HashingAlgorithm enumeration + identifying the hashing algorithm used by the RNG. Optional, + defaults to None. + drbg_algorithm (enum): A DRBGAlgorithm enumeration identifying the + DRBG algorithm used by the RNG. Optional, defaults to None. + recommended_curve (enum): A RecommendedCurve enumeration + identifying the recommended curve used by the RNG. Optional, + defaults to None. + fips186_variation (enum): A FIPS186Variation enumeration + identifying the FIPS186 variation used by the RNG. Optional, + defaults to None. + prediction_resistance (bool): A boolean indicating whether or not + prediction resistance is leveraged by the RNG. Optional, + defaults to None. + """ + super(RNGParameters, self).__init__(tag=enums.Tags.RNG_PARAMETERS) + + self._rng_algorithm = None + self._cryptographic_algorithm = None + self._cryptographic_length = None + self._hashing_algorithm = None + self._drbg_algorithm = None + self._recommended_curve = None + self._fips186_variation = None + self._prediction_resistance = None + + self.rng_algorithm = rng_algorithm + self.cryptographic_algorithm = cryptographic_algorithm + self.cryptographic_length = cryptographic_length + self.hashing_algorithm = hashing_algorithm + self.drbg_algorithm = drbg_algorithm + self.recommended_curve = recommended_curve + self.fips186_variation = fips186_variation + self.prediction_resistance = prediction_resistance + + @property + def rng_algorithm(self): + return self._rng_algorithm.value if self._rng_algorithm else None + + @rng_algorithm.setter + def rng_algorithm(self, value): + if value is None: + self._rng_algorithm = None + elif isinstance(value, enums.RNGAlgorithm): + self._rng_algorithm = primitives.Enumeration( + enums.RNGAlgorithm, + value=value, + tag=enums.Tags.RNG_ALGORITHM + ) + else: + raise TypeError( + "The RNG algorithm must be an RNGAlgorithm enumeration." + ) + + @property + def cryptographic_algorithm(self): + if self._cryptographic_algorithm: + return self._cryptographic_algorithm.value + else: + return None + + @cryptographic_algorithm.setter + def cryptographic_algorithm(self, value): + if value is None: + self._cryptographic_algorithm = None + elif isinstance(value, enums.CryptographicAlgorithm): + self._cryptographic_algorithm = primitives.Enumeration( + enums.CryptographicAlgorithm, + value=value, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ) + else: + raise TypeError( + "The cryptographic algorithm must be a " + "CryptographicAlgorithm enumeration." + ) + + @property + def cryptographic_length(self): + if self._cryptographic_length: + return self._cryptographic_length.value + else: + return None + + @cryptographic_length.setter + def cryptographic_length(self, value): + if value is None: + self._cryptographic_length = None + elif isinstance(value, six.integer_types): + self._cryptographic_length = primitives.Integer( + value=value, + tag=enums.Tags.CRYPTOGRAPHIC_LENGTH + ) + else: + raise TypeError("The cryptographic length must be an integer.") + + @property + def hashing_algorithm(self): + if self._hashing_algorithm: + return self._hashing_algorithm.value + else: + return None + + @hashing_algorithm.setter + def hashing_algorithm(self, value): + if value is None: + self._hashing_algorithm = None + elif isinstance(value, enums.HashingAlgorithm): + self._hashing_algorithm = primitives.Enumeration( + enums.HashingAlgorithm, + value=value, + tag=enums.Tags.HASHING_ALGORITHM + ) + else: + raise TypeError( + "The hashing algorithm must be a HashingAlgorithm " + "enumeration." + ) + + @property + def drbg_algorithm(self): + return self._drbg_algorithm.value if self._drbg_algorithm else None + + @drbg_algorithm.setter + def drbg_algorithm(self, value): + if value is None: + self._drbg_algorithm = None + elif isinstance(value, enums.DRBGAlgorithm): + self._drbg_algorithm = primitives.Enumeration( + enums.DRBGAlgorithm, + value=value, + tag=enums.Tags.DRBG_ALGORITHM + ) + else: + raise TypeError( + "The DRBG algorithm must be a DRBGAlgorithm enumeration." + ) + + @property + def recommended_curve(self): + if self._recommended_curve: + return self._recommended_curve.value + else: + return None + + @recommended_curve.setter + def recommended_curve(self, value): + if value is None: + self._recommended_curve = None + elif isinstance(value, enums.RecommendedCurve): + self._recommended_curve = primitives.Enumeration( + enums.RecommendedCurve, + value=value, + tag=enums.Tags.RECOMMENDED_CURVE + ) + else: + raise TypeError( + "The recommended curve must be a RecommendedCurve " + "enumeration." + ) + + @property + def fips186_variation(self): + if self._fips186_variation: + return self._fips186_variation.value + else: + return None + + @fips186_variation.setter + def fips186_variation(self, value): + if value is None: + self._fips186_variation = None + elif isinstance(value, enums.FIPS186Variation): + self._fips186_variation = primitives.Enumeration( + enums.FIPS186Variation, + value=value, + tag=enums.Tags.FIPS186_VARIATION + ) + else: + raise TypeError( + "The FIPS186 variation must be a FIPS186Variation " + "enumeration." + ) + + @property + def prediction_resistance(self): + if self._prediction_resistance: + return self._prediction_resistance.value + else: + return None + + @prediction_resistance.setter + def prediction_resistance(self, value): + if value is None: + self._prediction_resistance = None + elif isinstance(value, bool): + self._prediction_resistance = primitives.Boolean( + value=value, + tag=enums.Tags.PREDICTION_RESISTANCE + ) + else: + raise TypeError("The prediction resistance must be a boolean.") + + def read(self, input_buffer, kmip_version=enums.KMIPVersion.KMIP_1_3): + """ + Read the data encoding the RNGParameters structure and decode it + into its constituent parts. + + Args: + input_buffer (stream): A data stream containing encoded object + data, supporting a read method; usually a BytearrayStream + object. + kmip_version (KMIPVersion): An enumeration defining the KMIP + version with which the object will be decoded. Optional, + defaults to KMIP 2.0. + + Raises: + InvalidKmipEncoding: Raised if the RNG algorithm is missing from + the encoding. + VersionNotSupported: Raised when a KMIP version is provided that + does not support the RNGParameters structure. + """ + if kmip_version < enums.KMIPVersion.KMIP_1_3: + raise exceptions.VersionNotSupported( + "KMIP {} does not support the RNGParameters object.".format( + kmip_version.value + ) + ) + + super(RNGParameters, self).read( + input_buffer, + kmip_version=kmip_version + ) + local_buffer = utils.BytearrayStream(input_buffer.read(self.length)) + + if self.is_tag_next(enums.Tags.RNG_ALGORITHM, local_buffer): + rng_algorithm = primitives.Enumeration( + enums.RNGAlgorithm, + tag=enums.Tags.RNG_ALGORITHM + ) + rng_algorithm.read(local_buffer, kmip_version=kmip_version) + self._rng_algorithm = rng_algorithm + else: + raise exceptions.InvalidKmipEncoding( + "The RNGParameters encoding is missing the RNG algorithm." + ) + + if self.is_tag_next(enums.Tags.CRYPTOGRAPHIC_ALGORITHM, local_buffer): + cryptographic_algorithm = primitives.Enumeration( + enums.CryptographicAlgorithm, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ) + cryptographic_algorithm.read( + local_buffer, + kmip_version=kmip_version + ) + self._cryptographic_algorithm = cryptographic_algorithm + + if self.is_tag_next(enums.Tags.CRYPTOGRAPHIC_LENGTH, local_buffer): + cryptographic_length = primitives.Integer( + tag=enums.Tags.CRYPTOGRAPHIC_LENGTH + ) + cryptographic_length.read(local_buffer, kmip_version=kmip_version) + self._cryptographic_length = cryptographic_length + + if self.is_tag_next(enums.Tags.HASHING_ALGORITHM, local_buffer): + hashing_algorithm = primitives.Enumeration( + enums.HashingAlgorithm, + tag=enums.Tags.HASHING_ALGORITHM + ) + hashing_algorithm.read(local_buffer, kmip_version=kmip_version) + self._hashing_algorithm = hashing_algorithm + + if self.is_tag_next(enums.Tags.DRBG_ALGORITHM, local_buffer): + drbg_algorithm = primitives.Enumeration( + enums.DRBGAlgorithm, + tag=enums.Tags.DRBG_ALGORITHM + ) + drbg_algorithm.read(local_buffer, kmip_version=kmip_version) + self._drbg_algorithm = drbg_algorithm + + if self.is_tag_next(enums.Tags.RECOMMENDED_CURVE, local_buffer): + recommended_curve = primitives.Enumeration( + enums.RecommendedCurve, + tag=enums.Tags.RECOMMENDED_CURVE + ) + recommended_curve.read(local_buffer, kmip_version=kmip_version) + self._recommended_curve = recommended_curve + + if self.is_tag_next(enums.Tags.FIPS186_VARIATION, local_buffer): + fips186_variation = primitives.Enumeration( + enums.FIPS186Variation, + tag=enums.Tags.FIPS186_VARIATION + ) + fips186_variation.read(local_buffer, kmip_version=kmip_version) + self._fips186_variation = fips186_variation + + if self.is_tag_next(enums.Tags.PREDICTION_RESISTANCE, local_buffer): + prediction_resistance = primitives.Boolean( + tag=enums.Tags.PREDICTION_RESISTANCE + ) + prediction_resistance.read( + local_buffer, + kmip_version=kmip_version + ) + self._prediction_resistance = prediction_resistance + + self.is_oversized(local_buffer) + + def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_3): + """ + Write the RNGParameters structure encoding to the data stream. + + Args: + output_buffer (stream): A data stream in which to encode + Attributes structure data, supporting a write method. + kmip_version (enum): A KMIPVersion enumeration defining the KMIP + version with which the object will be encoded. Optional, + defaults to KMIP 2.0. + + Raises: + InvalidField: Raised if the RNG algorithm field is not defined. + VersionNotSupported: Raised when a KMIP version is provided that + does not support the RNGParameters structure. + """ + if kmip_version < enums.KMIPVersion.KMIP_1_3: + raise exceptions.VersionNotSupported( + "KMIP {} does not support the RNGParameters object.".format( + kmip_version.value + ) + ) + + local_buffer = BytearrayStream() + + if self._rng_algorithm: + self._rng_algorithm.write(local_buffer, kmip_version=kmip_version) + else: + raise exceptions.InvalidField( + "The RNGParameters structure is missing the RNG algorithm " + "field." + ) + + if self._cryptographic_algorithm: + self._cryptographic_algorithm.write( + local_buffer, + kmip_version=kmip_version + ) + + if self._cryptographic_length: + self._cryptographic_length.write( + local_buffer, + kmip_version=kmip_version + ) + + if self._hashing_algorithm: + self._hashing_algorithm.write( + local_buffer, + kmip_version=kmip_version + ) + + if self._drbg_algorithm: + self._drbg_algorithm.write( + local_buffer, + kmip_version=kmip_version + ) + + if self._recommended_curve: + self._recommended_curve.write( + local_buffer, + kmip_version=kmip_version + ) + + if self._fips186_variation: + self._fips186_variation.write( + local_buffer, + kmip_version=kmip_version + ) + + if self._prediction_resistance: + self._prediction_resistance.write( + local_buffer, + kmip_version=kmip_version + ) + + self.length = local_buffer.length() + super(RNGParameters, self).write( + output_buffer, + kmip_version=kmip_version + ) + output_buffer.write(local_buffer.buffer) + + def __repr__(self): + a = "rng_algorithm={}".format(self.rng_algorithm) + c = "cryptographic_algorithm={}".format(self.cryptographic_algorithm) + e = "cryptographic_length={}".format(self.cryptographic_length) + h = "hashing_algorithm={}".format(self.hashing_algorithm) + d = "drbg_algorithm={}".format(self.drbg_algorithm) + r = "recommended_curve={}".format(self.recommended_curve) + f = "fips186_variation={}".format(self.fips186_variation) + p = "prediction_resistance={}".format(self.prediction_resistance) + + v = ", ".join([a, c, e, h, d, r, f, p]) + + return "RNGParameters({})".format(v) + + def __str__(self): + a = '"rng_algorithm": {}'.format(self.rng_algorithm) + c = '"cryptographic_algorithm": {}'.format( + self.cryptographic_algorithm + ) + e = '"cryptographic_length": {}'.format(self.cryptographic_length) + h = '"hashing_algorithm": {}'.format(self.hashing_algorithm) + d = '"drbg_algorithm": {}'.format(self.drbg_algorithm) + r = '"recommended_curve": {}'.format(self.recommended_curve) + f = '"fips186_variation": {}'.format(self.fips186_variation) + p = '"prediction_resistance": {}'.format(self.prediction_resistance) + + v = ", ".join([a, c, e, h, d, r, f, p]) + + return '{' + v + '}' + + def __eq__(self, other): + if isinstance(other, RNGParameters): + if self.rng_algorithm != other.rng_algorithm: + return False + elif self.cryptographic_algorithm != other.cryptographic_algorithm: + return False + elif self.cryptographic_length != other.cryptographic_length: + return False + elif self.hashing_algorithm != other.hashing_algorithm: + return False + elif self.drbg_algorithm != other.drbg_algorithm: + return False + elif self.recommended_curve != other.recommended_curve: + return False + elif self.fips186_variation != other.fips186_variation: + return False + elif self.prediction_resistance != other.prediction_resistance: + return False + else: + return True + else: + return NotImplemented + + def __ne__(self, other): + if isinstance(other, RNGParameters): + return not (self == other) + else: + return NotImplemented diff --git a/kmip/tests/unit/core/objects/test_objects.py b/kmip/tests/unit/core/objects/test_objects.py index 5cdf39a..7f5e9f4 100644 --- a/kmip/tests/unit/core/objects/test_objects.py +++ b/kmip/tests/unit/core/objects/test_objects.py @@ -5722,3 +5722,794 @@ class TestDefaultsInformation(testtools.TestCase): self.assertTrue(a != b) self.assertTrue(b != a) + + +class TestRNGParameters(testtools.TestCase): + + def setUp(self): + super(TestRNGParameters, self).setUp() + + # This encoding matches the following set of values: + # + # RNGParameters + # RNG Algorithm - FIPS 186-2 + # Cryptographic Algorithm - AES + # Cryptographic Length - 256 + # Hashing Algorithm - SHA256 + # DRBG Algorithm - Hash + # Recommended Curve - P-192 + # FIPS186 Variation - GP x-Original + # Prediction Resistance - True + self.full_encoding = utils.BytearrayStream( + b'\x42\x00\xD9\x01\x00\x00\x00\x80' + b'\x42\x00\xDA\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + b'\x42\x00\x28\x05\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00' + b'\x42\x00\x2A\x02\x00\x00\x00\x04\x00\x00\x01\x00\x00\x00\x00\x00' + b'\x42\x00\x38\x05\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x00' + b'\x42\x00\xDB\x05\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00' + b'\x42\x00\x75\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\xDC\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + b'\x42\x00\xDD\x06\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01' + ) + + # This encoding matches the following set of values: + # + # RNGParameters + # Cryptographic Algorithm - AES + # Cryptographic Length - 256 + # Hashing Algorithm - SHA256 + # DRBG Algorithm - Hash + # Recommended Curve - P-192 + # FIPS186 Variation - GP x-Original + # Prediction Resistance - True + self.no_rng_algorithm_encoding = utils.BytearrayStream( + b'\x42\x00\xD9\x01\x00\x00\x00\x70' + b'\x42\x00\x28\x05\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00' + b'\x42\x00\x2A\x02\x00\x00\x00\x04\x00\x00\x01\x00\x00\x00\x00\x00' + b'\x42\x00\x38\x05\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x00' + b'\x42\x00\xDB\x05\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00' + b'\x42\x00\x75\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\xDC\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + b'\x42\x00\xDD\x06\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01' + ) + + # This encoding matches the following set of values: + # + # RNGParameters + # RNG Algorithm - FIPS 186-2 + self.only_rng_algorithm_encoding = utils.BytearrayStream( + b'\x42\x00\xD9\x01\x00\x00\x00\x10' + b'\x42\x00\xDA\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + ) + + def tearDown(self): + super(TestRNGParameters, self).tearDown() + + def test_invalid_rng_algorithm(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the RNG algorithm of an RNGParameters structure. + """ + kwargs = {"rng_algorithm": "invalid"} + self.assertRaisesRegex( + TypeError, + "The RNG algorithm must be an RNGAlgorithm enumeration.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "rng_algorithm", "invalid") + self.assertRaisesRegex( + TypeError, + "The RNG algorithm must be an RNGAlgorithm enumeration.", + setattr, + *args + ) + + def test_invalid_cryptographic_algorithm(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the cryptographic algorithm of an RNGParameters structure. + """ + kwargs = {"cryptographic_algorithm": "invalid"} + self.assertRaisesRegex( + TypeError, + "The cryptographic algorithm must be a CryptographicAlgorithm " + "enumeration.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "cryptographic_algorithm", "invalid") + self.assertRaisesRegex( + TypeError, + "The cryptographic algorithm must be a CryptographicAlgorithm " + "enumeration.", + setattr, + *args + ) + + def test_invalid_cryptographic_length(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the cryptographic length of an RNGParameters structure. + """ + kwargs = {"cryptographic_length": "invalid"} + self.assertRaisesRegex( + TypeError, + "The cryptographic length must be an integer.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "cryptographic_length", "invalid") + self.assertRaisesRegex( + TypeError, + "The cryptographic length must be an integer.", + setattr, + *args + ) + + def test_invalid_hashing_algorithm(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the hashing algorithm of an RNGParameters structure. + """ + kwargs = {"hashing_algorithm": "invalid"} + self.assertRaisesRegex( + TypeError, + "The hashing algorithm must be a HashingAlgorithm enumeration.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "hashing_algorithm", "invalid") + self.assertRaisesRegex( + TypeError, + "The hashing algorithm must be a HashingAlgorithm enumeration.", + setattr, + *args + ) + + def test_invalid_drbg_algorithm(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the DRBG algorithm of an RNGParameters structure. + """ + kwargs = {"drbg_algorithm": "invalid"} + self.assertRaisesRegex( + TypeError, + "The DRBG algorithm must be a DRBGAlgorithm enumeration.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "drbg_algorithm", "invalid") + self.assertRaisesRegex( + TypeError, + "The DRBG algorithm must be a DRBGAlgorithm enumeration.", + setattr, + *args + ) + + def test_invalid_recommended_curve(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the recommended curve of an RNGParameters structure. + """ + kwargs = {"recommended_curve": "invalid"} + self.assertRaisesRegex( + TypeError, + "The recommended curve must be a RecommendedCurve enumeration.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "recommended_curve", "invalid") + self.assertRaisesRegex( + TypeError, + "The recommended curve must be a RecommendedCurve enumeration.", + setattr, + *args + ) + + def test_invalid_fips186_variation(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the FIPS186 variation of an RNGParameters structure. + """ + kwargs = {"fips186_variation": "invalid"} + self.assertRaisesRegex( + TypeError, + "The FIPS186 variation must be a FIPS186Variation enumeration.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "fips186_variation", "invalid") + self.assertRaisesRegex( + TypeError, + "The FIPS186 variation must be a FIPS186Variation enumeration.", + setattr, + *args + ) + + def test_invalid_prediction_resistance(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the prediction resistance of an RNGParameters structure. + """ + kwargs = {"prediction_resistance": "invalid"} + self.assertRaisesRegex( + TypeError, + "The prediction resistance must be a boolean.", + objects.RNGParameters, + **kwargs + ) + + args = (objects.RNGParameters(), "prediction_resistance", "invalid") + self.assertRaisesRegex( + TypeError, + "The prediction resistance must be a boolean.", + setattr, + *args + ) + + def test_read(self): + """ + Test that a RNGParameters structure can be correctly read in from a + data stream. + """ + rng_parameters = objects.RNGParameters() + + self.assertIsNone(rng_parameters.rng_algorithm) + self.assertIsNone(rng_parameters.cryptographic_algorithm) + self.assertIsNone(rng_parameters.cryptographic_length) + self.assertIsNone(rng_parameters.hashing_algorithm) + self.assertIsNone(rng_parameters.drbg_algorithm) + self.assertIsNone(rng_parameters.recommended_curve) + self.assertIsNone(rng_parameters.fips186_variation) + self.assertIsNone(rng_parameters.prediction_resistance) + + rng_parameters.read( + self.full_encoding, + kmip_version=enums.KMIPVersion.KMIP_1_3 + ) + + self.assertEqual( + enums.RNGAlgorithm.FIPS186_2, + rng_parameters.rng_algorithm + ) + self.assertEqual( + enums.CryptographicAlgorithm.AES, + rng_parameters.cryptographic_algorithm + ) + self.assertEqual(256, rng_parameters.cryptographic_length) + self.assertEqual( + enums.HashingAlgorithm.SHA_256, + rng_parameters.hashing_algorithm + ) + self.assertEqual( + enums.DRBGAlgorithm.HASH, + rng_parameters.drbg_algorithm + ) + self.assertEqual( + enums.RecommendedCurve.P_192, + rng_parameters.recommended_curve + ) + self.assertEqual( + enums.FIPS186Variation.GP_X_ORIGINAL, + rng_parameters.fips186_variation + ) + self.assertTrue(rng_parameters.prediction_resistance) + + def test_read_unsupported_kmip_version(self): + """ + Test that a VersionNotSupported error is raised during the decoding of + an RNGParameters structure when the structure is read for an + unsupported KMIP version. + """ + rng_parameters = objects.RNGParameters() + + args = (self.full_encoding, ) + kwargs = {"kmip_version": enums.KMIPVersion.KMIP_1_2} + self.assertRaisesRegex( + exceptions.VersionNotSupported, + "KMIP 1.2 does not support the RNGParameters object.", + rng_parameters.read, + *args, + **kwargs + ) + + def test_read_missing_rng_algorithm(self): + """ + Test that an InvalidKmipEncoding error is raised during the decoding + of an RNGParameters structure when the RNG algorithm is missing + from the encoding. + """ + rng_parameters = objects.RNGParameters() + + args = (self.no_rng_algorithm_encoding, ) + self.assertRaisesRegex( + exceptions.InvalidKmipEncoding, + "The RNGParameters encoding is missing the RNG algorithm.", + rng_parameters.read, + *args + ) + + def test_read_only_rng_algorithm(self): + """ + Test that a RNGParameters structure can be correctly read in from a + data stream even when missing all fields except the RNG algorithm. + """ + rng_parameters = objects.RNGParameters() + + self.assertIsNone(rng_parameters.rng_algorithm) + self.assertIsNone(rng_parameters.cryptographic_algorithm) + self.assertIsNone(rng_parameters.cryptographic_length) + self.assertIsNone(rng_parameters.hashing_algorithm) + self.assertIsNone(rng_parameters.drbg_algorithm) + self.assertIsNone(rng_parameters.recommended_curve) + self.assertIsNone(rng_parameters.fips186_variation) + self.assertIsNone(rng_parameters.prediction_resistance) + + rng_parameters.read( + self.only_rng_algorithm_encoding, + kmip_version=enums.KMIPVersion.KMIP_1_3 + ) + + self.assertEqual( + enums.RNGAlgorithm.FIPS186_2, + rng_parameters.rng_algorithm + ) + self.assertIsNone(rng_parameters.cryptographic_algorithm) + self.assertIsNone(rng_parameters.cryptographic_length) + self.assertIsNone(rng_parameters.hashing_algorithm) + self.assertIsNone(rng_parameters.drbg_algorithm) + self.assertIsNone(rng_parameters.recommended_curve) + self.assertIsNone(rng_parameters.fips186_variation) + self.assertIsNone(rng_parameters.prediction_resistance) + + def test_write(self): + """ + Test that an RNGParameters structure can be written to a data + stream. + """ + rng_parameters = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + + buffer = utils.BytearrayStream() + rng_parameters.write( + buffer, + kmip_version=enums.KMIPVersion.KMIP_1_3 + ) + + self.assertEqual(len(self.full_encoding), len(buffer)) + self.assertEqual(str(self.full_encoding), str(buffer)) + + def test_write_unsupported_kmip_version(self): + """ + Test that a VersionNotSupported error is raised during the encoding of + an RNGParameters structure when the structure is written for an + unsupported KMIP version. + """ + rng_parameters = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + + args = (utils.BytearrayStream(), ) + kwargs = {"kmip_version": enums.KMIPVersion.KMIP_1_2} + self.assertRaisesRegex( + exceptions.VersionNotSupported, + "KMIP 1.2 does not support the RNGParameters object.", + rng_parameters.write, + *args, + **kwargs + ) + + def test_write_missing_rng_algorithm(self): + """ + Test that an InvalidField error is raised during the encoding of an + RNGParameters structure when the structure is missing the RNG + algorithm field. + """ + rng_parameters = objects.RNGParameters() + + args = (utils.BytearrayStream(), ) + self.assertRaisesRegex( + exceptions.InvalidField, + "The RNGParameters structure is missing the RNG algorithm field.", + rng_parameters.write, + *args + ) + + def test_write_only_rng_algorithm(self): + """ + Test that an RNGParameters structure can be written to a data + stream even when missing all fields except the RNG algorithm. + """ + rng_parameters = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2 + ) + + buffer = utils.BytearrayStream() + rng_parameters.write( + buffer, + kmip_version=enums.KMIPVersion.KMIP_1_3 + ) + + self.assertEqual(len(self.only_rng_algorithm_encoding), len(buffer)) + self.assertEqual(str(self.only_rng_algorithm_encoding), str(buffer)) + + def test_repr(self): + """ + Test that repr can be applied to an RNGParameters structure. + """ + rng_parameters = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + + a = "rng_algorithm=RNGAlgorithm.FIPS186_2" + c = "cryptographic_algorithm=CryptographicAlgorithm.AES" + e = "cryptographic_length=256" + h = "hashing_algorithm=HashingAlgorithm.SHA_256" + d = "drbg_algorithm=DRBGAlgorithm.HASH" + r = "recommended_curve=RecommendedCurve.P_192" + f = "fips186_variation=FIPS186Variation.GP_X_ORIGINAL" + p = "prediction_resistance=True" + + v = ", ".join([a, c, e, h, d, r, f, p]) + + self.assertEqual( + "RNGParameters({})".format(v), + repr(rng_parameters) + ) + + def test_str(self): + """ + Test that str can be applied to an RNGParameters structure. + """ + rng_parameters = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + + a = '"rng_algorithm": RNGAlgorithm.FIPS186_2' + c = '"cryptographic_algorithm": CryptographicAlgorithm.AES' + e = '"cryptographic_length": 256' + h = '"hashing_algorithm": HashingAlgorithm.SHA_256' + d = '"drbg_algorithm": DRBGAlgorithm.HASH' + r = '"recommended_curve": RecommendedCurve.P_192' + f = '"fips186_variation": FIPS186Variation.GP_X_ORIGINAL' + p = '"prediction_resistance": True' + + v = ", ".join([a, c, e, h, d, r, f, p]) + + self.assertEqual( + "{" + v + "}", + str(rng_parameters) + ) + + def test_equal_on_equal(self): + """ + Test that the equality operator returns True when comparing two + RNGParameters structures with the same data. + """ + a = objects.RNGParameters() + b = objects.RNGParameters() + + self.assertTrue(a == b) + self.assertTrue(b == a) + + a = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + b = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + + self.assertTrue(a == b) + self.assertTrue(b == a) + + def test_equal_on_not_equal_rng_algorithm(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different RNG algorithm fields. + """ + a = objects.RNGParameters(rng_algorithm=enums.RNGAlgorithm.FIPS186_2) + b = objects.RNGParameters(rng_algorithm=enums.RNGAlgorithm.UNSPECIFIED) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_cryptographic_algorithm(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different cryptographic algorithm fields. + """ + a = objects.RNGParameters( + cryptographic_algorithm=enums.CryptographicAlgorithm.DES + ) + b = objects.RNGParameters( + cryptographic_algorithm=enums.CryptographicAlgorithm.AES + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_cryptographic_length(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different cryptographic length fields. + """ + a = objects.RNGParameters(cryptographic_length=128) + b = objects.RNGParameters(cryptographic_length=256) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_hashing_algorithm(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different hashing algorithm fields. + """ + a = objects.RNGParameters(hashing_algorithm=enums.HashingAlgorithm.MD2) + b = objects.RNGParameters(hashing_algorithm=enums.HashingAlgorithm.MD4) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_drbg_algorithm(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different DRBG algorithm fields. + """ + a = objects.RNGParameters(drbg_algorithm=enums.DRBGAlgorithm.HASH) + b = objects.RNGParameters( + drbg_algorithm=enums.DRBGAlgorithm.UNSPECIFIED + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_recommended_curve(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different recommended curve fields. + """ + a = objects.RNGParameters( + recommended_curve=enums.RecommendedCurve.P_192 + ) + b = objects.RNGParameters( + recommended_curve=enums.RecommendedCurve.K_163 + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_fips186_variation(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different FIPS186 variation fields. + """ + a = objects.RNGParameters( + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL + ) + b = objects.RNGParameters( + fips186_variation=enums.FIPS186Variation.X_ORIGINAL + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_prediction_resistance(self): + """ + Test that the equality operator returns False when comparing two + RNGParameters structures with different prediction resistance fields. + """ + a = objects.RNGParameters(prediction_resistance=True) + b = objects.RNGParameters(prediction_resistance=False) + + 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 + RNGParameters structures with different types. + """ + a = objects.RNGParameters() + 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 + RNGParameters structures with the same data. + """ + a = objects.RNGParameters() + b = objects.RNGParameters() + + self.assertFalse(a != b) + self.assertFalse(b != a) + + a = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + b = objects.RNGParameters( + rng_algorithm=enums.RNGAlgorithm.FIPS186_2, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + cryptographic_length=256, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + drbg_algorithm=enums.DRBGAlgorithm.HASH, + recommended_curve=enums.RecommendedCurve.P_192, + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL, + prediction_resistance=True + ) + + self.assertFalse(a != b) + self.assertFalse(b != a) + + def test_not_equal_on_not_equal_rng_algorithm(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different RNG algorithm fields. + """ + a = objects.RNGParameters(rng_algorithm=enums.RNGAlgorithm.FIPS186_2) + b = objects.RNGParameters(rng_algorithm=enums.RNGAlgorithm.UNSPECIFIED) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_cryptographic_algorithm(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different cryptographic algorithm fields. + """ + a = objects.RNGParameters( + cryptographic_algorithm=enums.CryptographicAlgorithm.DES + ) + b = objects.RNGParameters( + cryptographic_algorithm=enums.CryptographicAlgorithm.AES + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_cryptographic_length(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different cryptographic length fields. + """ + a = objects.RNGParameters(cryptographic_length=128) + b = objects.RNGParameters(cryptographic_length=256) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_hashing_algorithm(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different hashing algorithm fields. + """ + a = objects.RNGParameters(hashing_algorithm=enums.HashingAlgorithm.MD2) + b = objects.RNGParameters(hashing_algorithm=enums.HashingAlgorithm.MD4) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_drbg_algorithm(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different DRBG algorithm fields. + """ + a = objects.RNGParameters(drbg_algorithm=enums.DRBGAlgorithm.HASH) + b = objects.RNGParameters( + drbg_algorithm=enums.DRBGAlgorithm.UNSPECIFIED + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_recommended_curve(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different recommended curve fields. + """ + a = objects.RNGParameters( + recommended_curve=enums.RecommendedCurve.P_192 + ) + b = objects.RNGParameters( + recommended_curve=enums.RecommendedCurve.K_163 + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_fips186_variation(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different FIPS186 variation fields. + """ + a = objects.RNGParameters( + fips186_variation=enums.FIPS186Variation.GP_X_ORIGINAL + ) + b = objects.RNGParameters( + fips186_variation=enums.FIPS186Variation.X_ORIGINAL + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_prediction_resistance(self): + """ + Test that the inequality operator returns True when comparing two + RNGParameters structures with different prediction resistance fields. + """ + a = objects.RNGParameters(prediction_resistance=True) + b = objects.RNGParameters(prediction_resistance=False) + + 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 + RNGParameters structures with different types. + """ + a = objects.RNGParameters() + b = "invalid" + + self.assertTrue(a != b) + self.assertTrue(b != a)