Skip to content

Commit 84ab77c

Browse files
committed
Add SQLAlchemy-based SplitKey support
This change adds a SQLAlchemy-based implementation of the SplitKey object that will be used by the ProxyKmipClient and PyKMIP server to store SplitKeys. A new unit test suite is included that checks object fields and verifies it can be persisted to and retrieved from an in-memory SQLAlchemy-managed database. Partially implements #545
1 parent 5c117c9 commit 84ab77c

File tree

2 files changed

+896
-0
lines changed

2 files changed

+896
-0
lines changed

kmip/pie/objects.py

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# under the License.
1515

1616
from abc import abstractmethod
17+
import sqlalchemy
1718
from sqlalchemy import Column, event, ForeignKey, Integer, String, VARBINARY
1819
from sqlalchemy import Boolean
1920
from sqlalchemy.ext.associationproxy import association_proxy
@@ -1051,6 +1052,264 @@ def __ne__(self, other):
10511052
sql.attribute_append_factory("name_index"), retval=False)
10521053

10531054

1055+
class SplitKey(Key):
1056+
"""
1057+
"""
1058+
1059+
__mapper_args__ = {"polymorphic_identity": "SplitKey"}
1060+
__table_args__ = {"sqlite_autoincrement": True}
1061+
__tablename__ = "split_keys"
1062+
1063+
unique_identifier = sqlalchemy.Column(
1064+
"uid",
1065+
sqlalchemy.Integer,
1066+
sqlalchemy.ForeignKey("keys.uid"),
1067+
primary_key=True
1068+
)
1069+
1070+
# Split Key object fields
1071+
_split_key_parts = sqlalchemy.Column(
1072+
"_split_key_parts",
1073+
sqlalchemy.Integer,
1074+
default=None
1075+
)
1076+
_key_part_identifier = sqlalchemy.Column(
1077+
"_key_part_identifier",
1078+
sqlalchemy.Integer,
1079+
default=None
1080+
)
1081+
_split_key_threshold = sqlalchemy.Column(
1082+
"_split_key_threshold",
1083+
sqlalchemy.Integer,
1084+
default=None
1085+
)
1086+
_split_key_method = sqlalchemy.Column(
1087+
"_split_key_method",
1088+
sql.EnumType(enums.SplitKeyMethod),
1089+
default=None
1090+
)
1091+
_prime_field_size = sqlalchemy.Column(
1092+
"_prime_field_size",
1093+
sqlalchemy.BigInteger,
1094+
default=None
1095+
)
1096+
1097+
def __init__(self,
1098+
cryptographic_algorithm=None,
1099+
cryptographic_length=None,
1100+
key_value=None,
1101+
cryptographic_usage_masks=None,
1102+
name="Split Key",
1103+
key_format_type=enums.KeyFormatType.RAW,
1104+
key_wrapping_data=None,
1105+
split_key_parts=None,
1106+
key_part_identifier=None,
1107+
split_key_threshold=None,
1108+
split_key_method=None,
1109+
prime_field_size=None):
1110+
"""
1111+
Create a SplitKey.
1112+
1113+
Args:
1114+
cryptographic_algorithm(enum): A CryptographicAlgorithm enumeration
1115+
identifying the type of algorithm for the split key. Required.
1116+
cryptographic_length(int): The length in bits of the split key.
1117+
Required.
1118+
key_value(bytes): The bytes representing the split key. Required.
1119+
cryptographic_usage_masks(list): A list of CryptographicUsageMask
1120+
enumerations defining how the split key will be used. Optional,
1121+
defaults to None.
1122+
name(string): The string name of the split key. Optional, defaults
1123+
to "Split Key".
1124+
key_format_type (enum): A KeyFormatType enumeration specifying the
1125+
format of the split key. Optional, defaults to Raw.
1126+
key_wrapping_data(dict): A dictionary containing key wrapping data
1127+
settings, describing how the split key has been wrapped.
1128+
Optional, defaults to None.
1129+
split_key_parts (int): An integer specifying the total number of
1130+
parts of the split key. Required.
1131+
key_part_identifier (int): An integer specifying which key part
1132+
of the split key this key object represents. Required.
1133+
split_key_threshold (int): An integer specifying the minimum
1134+
number of key parts required to reconstruct the split key.
1135+
Required.
1136+
split_key_method (enum): A SplitKeyMethod enumeration specifying
1137+
how the key was split. Required.
1138+
prime_field_size (int): A big integer specifying the prime field
1139+
size used for the Polynomial Sharing Prime Field split key
1140+
method. Optional, defaults to None.
1141+
"""
1142+
super(SplitKey, self).__init__(key_wrapping_data=key_wrapping_data)
1143+
1144+
self._object_type = enums.ObjectType.SPLIT_KEY
1145+
1146+
self.key_format_type = key_format_type
1147+
self.value = key_value
1148+
self.cryptographic_algorithm = cryptographic_algorithm
1149+
self.cryptographic_length = cryptographic_length
1150+
self.names = [name]
1151+
1152+
if cryptographic_usage_masks:
1153+
self.cryptographic_usage_masks.extend(cryptographic_usage_masks)
1154+
1155+
self.split_key_parts = split_key_parts
1156+
self.key_part_identifier = key_part_identifier
1157+
self.split_key_threshold = split_key_threshold
1158+
self.split_key_method = split_key_method
1159+
self.prime_field_size = prime_field_size
1160+
1161+
@property
1162+
def split_key_parts(self):
1163+
return self._split_key_parts
1164+
1165+
@split_key_parts.setter
1166+
def split_key_parts(self, value):
1167+
if (value is None) or (isinstance(value, six.integer_types)):
1168+
self._split_key_parts = value
1169+
else:
1170+
raise TypeError("The split key parts must be an integer.")
1171+
1172+
@property
1173+
def key_part_identifier(self):
1174+
return self._key_part_identifier
1175+
1176+
@key_part_identifier.setter
1177+
def key_part_identifier(self, value):
1178+
if (value is None) or (isinstance(value, six.integer_types)):
1179+
self._key_part_identifier = value
1180+
else:
1181+
raise TypeError("The key part identifier must be an integer.")
1182+
1183+
@property
1184+
def split_key_threshold(self):
1185+
return self._split_key_threshold
1186+
1187+
@split_key_threshold.setter
1188+
def split_key_threshold(self, value):
1189+
if (value is None) or (isinstance(value, six.integer_types)):
1190+
self._split_key_threshold = value
1191+
else:
1192+
raise TypeError("The split key threshold must be an integer.")
1193+
1194+
@property
1195+
def split_key_method(self):
1196+
return self._split_key_method
1197+
1198+
@split_key_method.setter
1199+
def split_key_method(self, value):
1200+
if (value is None) or (isinstance(value, enums.SplitKeyMethod)):
1201+
self._split_key_method = value
1202+
else:
1203+
raise TypeError(
1204+
"The split key method must be a SplitKeyMethod enumeration."
1205+
)
1206+
1207+
@property
1208+
def prime_field_size(self):
1209+
return self._prime_field_size
1210+
1211+
@prime_field_size.setter
1212+
def prime_field_size(self, value):
1213+
if (value is None) or (isinstance(value, six.integer_types)):
1214+
self._prime_field_size = value
1215+
else:
1216+
raise TypeError("The prime field size must be an integer.")
1217+
1218+
def __repr__(self):
1219+
cryptographic_algorithm = "cryptographic_algorithm={0}".format(
1220+
self.cryptographic_algorithm
1221+
)
1222+
cryptographic_length = "cryptographic_length={0}".format(
1223+
self.cryptographic_length
1224+
)
1225+
key_value = "key_value={0}".format(binascii.hexlify(self.value))
1226+
key_format_type = "key_format_type={0}".format(self.key_format_type)
1227+
key_wrapping_data = "key_wrapping_data={0}".format(
1228+
self.key_wrapping_data
1229+
)
1230+
cryptographic_usage_masks = "cryptographic_usage_masks={0}".format(
1231+
self.cryptographic_usage_masks
1232+
)
1233+
names = "name={0}".format(self.names)
1234+
split_key_parts = "split_key_parts={0}".format(self.split_key_parts)
1235+
key_part_identifier = "key_part_identifier={0}".format(
1236+
self.key_part_identifier
1237+
)
1238+
split_key_threshold = "split_key_threshold={0}".format(
1239+
self.split_key_threshold
1240+
)
1241+
split_key_method = "split_key_method={0}".format(self.split_key_method)
1242+
prime_field_size = "prime_field_size={0}".format(self.prime_field_size)
1243+
1244+
return "SplitKey({0})".format(
1245+
", ".join(
1246+
[
1247+
cryptographic_algorithm,
1248+
cryptographic_length,
1249+
key_value,
1250+
key_format_type,
1251+
key_wrapping_data,
1252+
cryptographic_usage_masks,
1253+
names,
1254+
split_key_parts,
1255+
key_part_identifier,
1256+
split_key_threshold,
1257+
split_key_method,
1258+
prime_field_size
1259+
]
1260+
)
1261+
)
1262+
1263+
def __str__(self):
1264+
return str(binascii.hexlify(self.value))
1265+
1266+
def __eq__(self, other):
1267+
if isinstance(other, SplitKey):
1268+
if self.value != other.value:
1269+
return False
1270+
elif self.key_format_type != other.key_format_type:
1271+
return False
1272+
elif self.cryptographic_algorithm != other.cryptographic_algorithm:
1273+
return False
1274+
elif self.cryptographic_length != other.cryptographic_length:
1275+
return False
1276+
elif self.key_wrapping_data != other.key_wrapping_data:
1277+
return False
1278+
elif self.cryptographic_usage_masks != \
1279+
other.cryptographic_usage_masks:
1280+
return False
1281+
elif self.names != other.names:
1282+
return False
1283+
elif self.split_key_parts != other.split_key_parts:
1284+
return False
1285+
elif self.key_part_identifier != other.key_part_identifier:
1286+
return False
1287+
elif self.split_key_threshold != other.split_key_threshold:
1288+
return False
1289+
elif self.split_key_method != other.split_key_method:
1290+
return False
1291+
elif self.prime_field_size != other.prime_field_size:
1292+
return False
1293+
else:
1294+
return True
1295+
else:
1296+
return NotImplemented
1297+
1298+
def __ne__(self, other):
1299+
if isinstance(other, SplitKey):
1300+
return not (self == other)
1301+
else:
1302+
return NotImplemented
1303+
1304+
1305+
event.listen(
1306+
SplitKey._names,
1307+
"append",
1308+
sql.attribute_append_factory("name_index"),
1309+
retval=False
1310+
)
1311+
1312+
10541313
class Certificate(CryptographicObject):
10551314
"""
10561315
The Certificate class of the simplified KMIP object hierarchy.

0 commit comments

Comments
 (0)