Merge pull request #304 from OpenKMIP/feat/update-encryption-key-info

Update the EncryptionKeyInformation struct
This commit is contained in:
Peter Hamilton 2017-07-14 11:40:53 -04:00 committed by GitHub
commit 9e9af140a6
2 changed files with 603 additions and 9 deletions

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import six
from six.moves import xrange
from kmip.core import attributes
@ -30,6 +31,7 @@ from kmip.core.enums import RevocationReasonCode as RevocationReasonCodeEnum
from kmip.core.errors import ErrorStrings
from kmip.core.misc import KeyFormatType
from kmip.core import primitives
from kmip.core.primitives import Struct
from kmip.core.primitives import TextString
from kmip.core.primitives import ByteString
@ -657,21 +659,160 @@ class KeyInformation(Struct):
pass
class EncryptionKeyInformation(KeyInformation):
class EncryptionKeyInformation(Struct):
"""
A set of values detailing how an encrypted value was encrypted.
"""
def __init__(self,
unique_identifier=None,
cryptographic_parameters=None,
tag=Tags.ENCRYPTION_KEY_INFORMATION):
cryptographic_parameters=None):
"""
Construct an EncryptionKeyInformation struct.
Args:
unique_identifier (string): The ID of the managed object (e.g.,
a symmetric key) used for encryption. Required for encoding
and decoding.
cryptographic_parameters (CryptographicParameters): A
CryptographicParameters struct containing the settings for
the encryption process. Optional, defaults to None. If not
included, the CryptographicParameters associated with the
managed object will be used instead.
"""
super(EncryptionKeyInformation, self).__init__(
unique_identifier, cryptographic_parameters, tag)
tag=Tags.ENCRYPTION_KEY_INFORMATION
)
def validate(self):
self.__validate()
self._unique_identifier = None
self._cryptographic_parameters = None
def __validate(self):
# TODO (peter-hamilton) Finish implementation.
pass
self.unique_identifier = unique_identifier
self.cryptographic_parameters = cryptographic_parameters
@property
def unique_identifier(self):
if self._unique_identifier:
return self._unique_identifier.value
else:
return None
@unique_identifier.setter
def unique_identifier(self, value):
if value is None:
self._unique_identifier = None
elif isinstance(value, six.string_types):
self._unique_identifier = primitives.TextString(
value=value,
tag=enums.Tags.UNIQUE_IDENTIFIER
)
else:
raise TypeError("Unique identifier must be a string.")
@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."
)
def read(self, input_stream):
"""
Read the data encoding the EncryptionKeyInformation 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(EncryptionKeyInformation, self).read(input_stream)
local_stream = BytearrayStream(input_stream.read(self.length))
if self.is_tag_next(enums.Tags.UNIQUE_IDENTIFIER, local_stream):
self._unique_identifier = primitives.TextString(
tag=enums.Tags.UNIQUE_IDENTIFIER
)
self._unique_identifier.read(local_stream)
else:
raise ValueError(
"Invalid struct missing the unique identifier attribute."
)
if self.is_tag_next(
enums.Tags.CRYPTOGRAPHIC_PARAMETERS,
local_stream
):
self._cryptographic_parameters = CryptographicParameters()
self._cryptographic_parameters.read(local_stream)
self.is_oversized(local_stream)
def write(self, output_stream):
"""
Write the data encoding the EncryptionKeyInformation 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._unique_identifier:
self._unique_identifier.write(local_stream)
else:
raise ValueError(
"Invalid struct missing the unique identifier attribute."
)
if self._cryptographic_parameters:
self._cryptographic_parameters.write(local_stream)
self.length = local_stream.length()
super(EncryptionKeyInformation, self).write(output_stream)
output_stream.write(local_stream.buffer)
def __eq__(self, other):
if isinstance(other, EncryptionKeyInformation):
if self.unique_identifier != other.unique_identifier:
return False
elif self.cryptographic_parameters != \
other.cryptographic_parameters:
return False
else:
return True
def __ne__(self, other):
if isinstance(other, EncryptionKeyInformation):
return not self == other
else:
return NotImplemented
def __repr__(self):
args = ", ".join([
"unique_identifier='{0}'".format(self.unique_identifier),
"cryptographic_parameters={0}".format(
repr(self.cryptographic_parameters)
)
])
return "EncryptionKeyInformation({0})".format(args)
def __str__(self):
return str({
'unique_identifier': self.unique_identifier,
'cryptographic_parameters': self.cryptographic_parameters
})
class MACSignatureKeyInformation(KeyInformation):

View File

@ -14,8 +14,11 @@
# under the License.
from six import string_types
import testtools
from testtools import TestCase
from kmip.core import attributes
from kmip.core import enums
from kmip.core.enums import AttributeType
from kmip.core.enums import BlockCipherMode
from kmip.core.enums import HashingAlgorithm as HashingAlgorithmEnum
@ -25,12 +28,14 @@ from kmip.core.enums import Tags
from kmip.core.factories.attributes import AttributeValueFactory
from kmip.core import objects
from kmip.core.objects import Attribute
from kmip.core.objects import ExtensionName
from kmip.core.objects import ExtensionTag
from kmip.core.objects import ExtensionType
from kmip.core.objects import KeyMaterialStruct
from kmip.core import utils
from kmip.core.utils import BytearrayStream
@ -295,3 +300,451 @@ class TestExtensionType(TestCase):
used to construct an ExtensionType object.
"""
self._test_init("invalid")
class TestEncryptionKeyInformation(testtools.TestCase):
"""
Test suite for the EncryptionKeyInformation struct.
"""
def setUp(self):
super(TestEncryptionKeyInformation, self).setUp()
# Encoding obtained from the KMIP 1.1 testing document, Section 14.1.
#
# This encoding matches the following set of values:
# Unique Identifier - 100182d5-72b8-47aa-8383-4d97d512e98a
# Cryptographic Parameters
# Block Cipher Mode - NIST_KEY_WRAP
self.full_encoding = BytearrayStream(
b'\x42\x00\x36\x01\x00\x00\x00\x48'
b'\x42\x00\x94\x07\x00\x00\x00\x24'
b'\x31\x30\x30\x31\x38\x32\x64\x35\x2D\x37\x32\x62\x38\x2D\x34\x37'
b'\x61\x61\x2D\x38\x33\x38\x33\x2D\x34\x64\x39\x37\x64\x35\x31\x32'
b'\x65\x39\x38\x61\x00\x00\x00\x00'
b'\x42\x00\x2B\x01\x00\x00\x00\x10'
b'\x42\x00\x11\x05\x00\x00\x00\x04\x00\x00\x00\x0D\x00\x00\x00\x00'
)
# Adapted from the full encoding above. This encoding matches the
# following set of values:
# Unique Identifier - 100182d5-72b8-47aa-8383-4d97d512e98a
self.partial_encoding = BytearrayStream(
b'\x42\x00\x36\x01\x00\x00\x00\x30'
b'\x42\x00\x94\x07\x00\x00\x00\x24'
b'\x31\x30\x30\x31\x38\x32\x64\x35\x2D\x37\x32\x62\x38\x2D\x34\x37'
b'\x61\x61\x2D\x38\x33\x38\x33\x2D\x34\x64\x39\x37\x64\x35\x31\x32'
b'\x65\x39\x38\x61\x00\x00\x00\x00'
)
self.empty_encoding = BytearrayStream(
b'\x42\x00\x36\x01\x00\x00\x00\x00'
)
def tearDown(self):
super(TestEncryptionKeyInformation, self).tearDown()
def test_init(self):
"""
Test that an EncryptionKeyInformation struct can be constructed with
no arguments.
"""
encryption_key_information = objects.EncryptionKeyInformation()
self.assertEqual(None, encryption_key_information.unique_identifier)
self.assertEqual(
None,
encryption_key_information.cryptographic_parameters
)
def test_init_with_args(self):
"""
Test that an EncryptionKeyInformation struct can be constructed with
valid values.
"""
cryptographic_parameters = attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CTR)
encryption_key_information = objects.EncryptionKeyInformation(
unique_identifier="00000000-1111-2222-3333-444444444444",
cryptographic_parameters=cryptographic_parameters
)
self.assertEqual(
"00000000-1111-2222-3333-444444444444",
encryption_key_information.unique_identifier
)
self.assertIsInstance(
encryption_key_information.cryptographic_parameters,
attributes.CryptographicParameters
)
parameters = encryption_key_information.cryptographic_parameters
self.assertEqual(
enums.BlockCipherMode.CTR,
parameters.block_cipher_mode
)
def test_invalid_unique_identifier(self):
"""
Test that a TypeError is raised when an invalid value is used to set
the unique identifier of an EncryptionKeyInformation struct.
"""
kwargs = {'unique_identifier': 0}
self.assertRaisesRegexp(
TypeError,
"Unique identifier must be a string.",
objects.EncryptionKeyInformation,
**kwargs
)
encryption_key_information = objects.EncryptionKeyInformation()
args = (encryption_key_information, 'unique_identifier', 0)
self.assertRaisesRegexp(
TypeError,
"Unique identifier must be a string.",
setattr,
*args
)
def test_invalid_cryptographic_parameters(self):
"""
Test that a TypeError is raised when an invalid value is used to set
the cryptographic parameters of an EncryptionKeyInformation struct.
"""
kwargs = {'cryptographic_parameters': 'invalid'}
self.assertRaisesRegexp(
TypeError,
"Cryptographic parameters must be a CryptographicParameters "
"struct.",
objects.EncryptionKeyInformation,
**kwargs
)
encryption_key_information = objects.EncryptionKeyInformation()
args = (
encryption_key_information,
'cryptographic_parameters',
'invalid'
)
self.assertRaisesRegexp(
TypeError,
"Cryptographic parameters must be a CryptographicParameters "
"struct.",
setattr,
*args
)
def test_read(self):
"""
Test that an EncryptionKeyInformation struct can be read from a data
stream.
"""
encryption_key_information = objects.EncryptionKeyInformation()
self.assertEqual(None, encryption_key_information.unique_identifier)
self.assertEqual(
None,
encryption_key_information.cryptographic_parameters
)
encryption_key_information.read(self.full_encoding)
self.assertEqual(
"100182d5-72b8-47aa-8383-4d97d512e98a",
encryption_key_information.unique_identifier
)
self.assertIsInstance(
encryption_key_information.cryptographic_parameters,
attributes.CryptographicParameters
)
cryptographic_parameters = \
encryption_key_information.cryptographic_parameters
self.assertEqual(
enums.BlockCipherMode.NIST_KEY_WRAP,
cryptographic_parameters.block_cipher_mode
)
def test_read_partial(self):
"""
Test that an EncryptionKeyInformation struct can be read from a partial
data stream.
"""
encryption_key_information = objects.EncryptionKeyInformation()
self.assertEqual(None, encryption_key_information.unique_identifier)
self.assertEqual(
None,
encryption_key_information.cryptographic_parameters
)
encryption_key_information.read(self.partial_encoding)
self.assertEqual(
"100182d5-72b8-47aa-8383-4d97d512e98a",
encryption_key_information.unique_identifier
)
self.assertEqual(
None,
encryption_key_information.cryptographic_parameters
)
def test_read_invalid(self):
"""
Test that a ValueError gets raised when a required
EncryptionKeyInformation field is missing from the struct encoding.
"""
encryption_key_information = objects.EncryptionKeyInformation()
args = (self.empty_encoding,)
self.assertRaisesRegexp(
ValueError,
"Invalid struct missing the unique identifier attribute.",
encryption_key_information.read,
*args
)
def test_write(self):
"""
Test that an EncryptionKeyInformation struct can be written to a data
stream.
"""
cryptographic_parameters = attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP
)
encryption_key_information = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=cryptographic_parameters
)
stream = BytearrayStream()
encryption_key_information.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 EncryptionKeyInformation struct can be
written to a data stream.
"""
encryption_key_information = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a"
)
stream = BytearrayStream()
encryption_key_information.write(stream)
self.assertEqual(len(self.partial_encoding), len(stream))
self.assertEqual(str(self.partial_encoding), str(stream))
def test_write_invalid(self):
"""
Test that a ValueError gets raised when a required
EncryptionKeyInformation field is missing when encoding the struct.
"""
encryption_key_information = objects.EncryptionKeyInformation()
stream = utils.BytearrayStream()
args = (stream,)
self.assertRaisesRegexp(
ValueError,
"Invalid struct missing the unique identifier attribute.",
encryption_key_information.write,
*args
)
def test_equal_on_equal(self):
"""
Test that the equality operator returns True when comparing two
EncryptionKeyInformation structs with the same data.
"""
a = objects.EncryptionKeyInformation()
b = objects.EncryptionKeyInformation()
self.assertTrue(a == b)
self.assertTrue(b == a)
a = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
b = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
self.assertTrue(a == b)
self.assertTrue(b == a)
def test_equal_on_not_equal_unique_identifier(self):
"""
Test that the equality operator returns False when comparing two
EncryptionKeyInformation structs with different unique identifiers.
"""
a = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a"
)
b = objects.EncryptionKeyInformation(
unique_identifier="00000000-1111-2222-3333-444444444444"
)
self.assertFalse(a == b)
self.assertFalse(b == a)
def test_equal_on_not_equal_cryptographic_parameters(self):
"""
Test that the equality operator returns False when comparing two
EncryptionKeyInformation structs with different cryptographic
parameters.
"""
a = objects.EncryptionKeyInformation(
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
b = objects.EncryptionKeyInformation(
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.GCM
)
)
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
EncryptionKeyInformation structs with different types.
"""
a = objects.EncryptionKeyInformation()
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
EncryptionKeyInformation structs with the same data.
"""
a = objects.EncryptionKeyInformation()
b = objects.EncryptionKeyInformation()
self.assertFalse(a != b)
self.assertFalse(b != a)
a = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
b = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
self.assertFalse(a != b)
self.assertFalse(b != a)
def test_not_equal_on_not_equal_unique_identifier(self):
"""
Test that the inequality operator returns True when comparing two
EncryptionKeyInformation structs with different unique identifiers.
"""
a = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a"
)
b = objects.EncryptionKeyInformation(
unique_identifier="00000000-1111-2222-3333-444444444444"
)
self.assertTrue(a != b)
self.assertTrue(b != a)
def test_not_equal_on_not_equal_cryptographic_parameters(self):
"""
Test that the inequality operator returns True when comparing two
EncryptionKeyInformation structs with different cryptographic
parameters.
"""
a = objects.EncryptionKeyInformation(
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
b = objects.EncryptionKeyInformation(
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.GCM
)
)
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
EncryptionKeyInformation structs with different types.
"""
a = objects.EncryptionKeyInformation()
b = 'invalid'
self.assertTrue(a != b)
self.assertTrue(b != a)
def test_repr(self):
"""
Test that repr can be applied to an EncryptionKeyInformation struct.
"""
encryption_key_information = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
)
expected = (
"EncryptionKeyInformation("
"unique_identifier='100182d5-72b8-47aa-8383-4d97d512e98a', "
"cryptographic_parameters=CryptographicParameters("
"block_cipher_mode=BlockCipherMode.CBC, "
"padding_method=None, "
"hashing_algorithm=None, "
"key_role_type=None, "
"digital_signature_algorithm=None, "
"cryptographic_algorithm=None, "
"random_iv=None, "
"iv_length=None, "
"tag_length=None, "
"fixed_field_length=None, "
"invocation_field_length=None, "
"counter_length=None, "
"initial_counter_value=None))"
)
observed = repr(encryption_key_information)
self.assertEqual(expected, observed)
def test_str(self):
"""
Test that str can be applied to an EncryptionKeyInformation struct.
"""
cryptographic_parameters = attributes.CryptographicParameters(
block_cipher_mode=enums.BlockCipherMode.CBC
)
encryption_key_information = objects.EncryptionKeyInformation(
unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a",
cryptographic_parameters=cryptographic_parameters
)
expected = str({
'unique_identifier': "100182d5-72b8-47aa-8383-4d97d512e98a",
'cryptographic_parameters': cryptographic_parameters
})
observed = str(encryption_key_information)
self.assertEqual(expected, observed)