otdf-python 0.4.0__py3-none-any.whl → 0.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- otdf_python/__init__.py +1 -2
- otdf_python/__main__.py +1 -2
- otdf_python/address_normalizer.py +8 -10
- otdf_python/aesgcm.py +8 -0
- otdf_python/assertion_config.py +21 -0
- otdf_python/asym_crypto.py +18 -22
- otdf_python/auth_headers.py +7 -6
- otdf_python/autoconfigure_utils.py +21 -7
- otdf_python/cli.py +5 -5
- otdf_python/collection_store.py +13 -1
- otdf_python/collection_store_impl.py +5 -0
- otdf_python/config.py +13 -0
- otdf_python/connect_client.py +1 -0
- otdf_python/constants.py +2 -0
- otdf_python/crypto_utils.py +4 -0
- otdf_python/dpop.py +3 -5
- otdf_python/ecc_constants.py +12 -14
- otdf_python/ecc_mode.py +7 -2
- otdf_python/ecdh.py +24 -31
- otdf_python/eckeypair.py +5 -0
- otdf_python/header.py +5 -0
- otdf_python/invalid_zip_exception.py +6 -2
- otdf_python/kas_client.py +66 -55
- otdf_python/kas_connect_rpc_client.py +75 -38
- otdf_python/kas_info.py +4 -3
- otdf_python/kas_key_cache.py +10 -9
- otdf_python/key_type.py +4 -0
- otdf_python/key_type_constants.py +4 -11
- otdf_python/manifest.py +24 -0
- otdf_python/nanotdf.py +30 -28
- otdf_python/nanotdf_ecdsa_struct.py +5 -11
- otdf_python/nanotdf_type.py +13 -1
- otdf_python/policy_binding_serializer.py +6 -4
- otdf_python/policy_info.py +6 -0
- otdf_python/policy_object.py +8 -0
- otdf_python/policy_stub.py +2 -0
- otdf_python/resource_locator.py +22 -13
- otdf_python/sdk.py +51 -73
- otdf_python/sdk_builder.py +60 -47
- otdf_python/sdk_exceptions.py +11 -1
- otdf_python/symmetric_and_payload_config.py +6 -0
- otdf_python/tdf.py +47 -10
- otdf_python/tdf_reader.py +10 -13
- otdf_python/tdf_writer.py +5 -0
- otdf_python/token_source.py +4 -3
- otdf_python/version.py +5 -0
- otdf_python/zip_reader.py +10 -2
- otdf_python/zip_writer.py +11 -0
- {otdf_python-0.4.0.dist-info → otdf_python-0.4.2.dist-info}/METADATA +3 -2
- {otdf_python-0.4.0.dist-info → otdf_python-0.4.2.dist-info}/RECORD +81 -72
- {otdf_python-0.4.0.dist-info → otdf_python-0.4.2.dist-info}/WHEEL +1 -1
- otdf_python_proto/__init__.py +2 -6
- otdf_python_proto/authorization/__init__.py +10 -0
- otdf_python_proto/authorization/authorization_connect.py +250 -0
- otdf_python_proto/authorization/v2/authorization_connect.py +315 -0
- otdf_python_proto/entityresolution/__init__.py +10 -0
- otdf_python_proto/entityresolution/entity_resolution_connect.py +185 -0
- otdf_python_proto/entityresolution/v2/entity_resolution_connect.py +185 -0
- otdf_python_proto/kas/__init__.py +2 -2
- otdf_python_proto/kas/kas_connect.py +259 -0
- otdf_python_proto/policy/actions/__init__.py +11 -0
- otdf_python_proto/policy/actions/actions_connect.py +380 -0
- otdf_python_proto/policy/attributes/__init__.py +11 -0
- otdf_python_proto/policy/attributes/attributes_connect.py +1310 -0
- otdf_python_proto/policy/kasregistry/__init__.py +11 -0
- otdf_python_proto/policy/kasregistry/key_access_server_registry_connect.py +912 -0
- otdf_python_proto/policy/keymanagement/__init__.py +11 -0
- otdf_python_proto/policy/keymanagement/key_management_connect.py +380 -0
- otdf_python_proto/policy/namespaces/__init__.py +11 -0
- otdf_python_proto/policy/namespaces/namespaces_connect.py +648 -0
- otdf_python_proto/policy/registeredresources/__init__.py +11 -0
- otdf_python_proto/policy/registeredresources/registered_resources_connect.py +770 -0
- otdf_python_proto/policy/resourcemapping/__init__.py +11 -0
- otdf_python_proto/policy/resourcemapping/resource_mapping_connect.py +790 -0
- otdf_python_proto/policy/subjectmapping/__init__.py +11 -0
- otdf_python_proto/policy/subjectmapping/subject_mapping_connect.py +851 -0
- otdf_python_proto/policy/unsafe/__init__.py +11 -0
- otdf_python_proto/policy/unsafe/unsafe_connect.py +705 -0
- otdf_python_proto/wellknownconfiguration/__init__.py +10 -0
- otdf_python_proto/wellknownconfiguration/wellknown_configuration_connect.py +124 -0
- otdf_python_proto/authorization/authorization_pb2_connect.py +0 -191
- otdf_python_proto/authorization/v2/authorization_pb2_connect.py +0 -233
- otdf_python_proto/entityresolution/entity_resolution_pb2_connect.py +0 -149
- otdf_python_proto/entityresolution/v2/entity_resolution_pb2_connect.py +0 -149
- otdf_python_proto/kas/kas_pb2_connect.py +0 -192
- otdf_python_proto/policy/actions/actions_pb2_connect.py +0 -275
- otdf_python_proto/policy/attributes/attributes_pb2_connect.py +0 -863
- otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2_connect.py +0 -611
- otdf_python_proto/policy/keymanagement/key_management_pb2_connect.py +0 -275
- otdf_python_proto/policy/namespaces/namespaces_pb2_connect.py +0 -443
- otdf_python_proto/policy/registeredresources/registered_resources_pb2_connect.py +0 -527
- otdf_python_proto/policy/resourcemapping/resource_mapping_pb2_connect.py +0 -527
- otdf_python_proto/policy/subjectmapping/subject_mapping_pb2_connect.py +0 -569
- otdf_python_proto/policy/unsafe/unsafe_pb2_connect.py +0 -485
- otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2_connect.py +0 -107
- {otdf_python-0.4.0.dist-info → otdf_python-0.4.2.dist-info}/licenses/LICENSE +0 -0
otdf_python/ecc_constants.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Elliptic Curve Constants for NanoTDF.
|
|
1
|
+
"""Elliptic Curve Constants for NanoTDF.
|
|
3
2
|
|
|
4
3
|
This module defines shared constants for elliptic curve operations used across
|
|
5
4
|
the SDK, particularly for NanoTDF encryption/decryption.
|
|
@@ -14,8 +13,7 @@ from cryptography.hazmat.primitives.asymmetric import ec
|
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
class ECCConstants:
|
|
17
|
-
"""
|
|
18
|
-
Centralized constants for elliptic curve cryptography operations.
|
|
16
|
+
"""Centralized constants for elliptic curve cryptography operations.
|
|
19
17
|
|
|
20
18
|
This class provides mappings between curve names, curve type integers,
|
|
21
19
|
cryptography curve objects, and compressed public key sizes.
|
|
@@ -67,8 +65,7 @@ class ECCConstants:
|
|
|
67
65
|
|
|
68
66
|
@classmethod
|
|
69
67
|
def get_curve_name(cls, curve_type: int) -> str:
|
|
70
|
-
"""
|
|
71
|
-
Get curve name from curve type integer.
|
|
68
|
+
"""Get curve name from curve type integer.
|
|
72
69
|
|
|
73
70
|
Args:
|
|
74
71
|
curve_type: Curve type (0=secp256r1, 1=secp384r1, 2=secp521r1, 3=secp256k1)
|
|
@@ -78,6 +75,7 @@ class ECCConstants:
|
|
|
78
75
|
|
|
79
76
|
Raises:
|
|
80
77
|
ValueError: If curve_type is not supported
|
|
78
|
+
|
|
81
79
|
"""
|
|
82
80
|
name = cls.CURVE_TYPE_TO_NAME.get(curve_type)
|
|
83
81
|
if name is None:
|
|
@@ -89,8 +87,7 @@ class ECCConstants:
|
|
|
89
87
|
|
|
90
88
|
@classmethod
|
|
91
89
|
def get_curve_type(cls, curve_name: str) -> int:
|
|
92
|
-
"""
|
|
93
|
-
Get curve type integer from curve name.
|
|
90
|
+
"""Get curve type integer from curve name.
|
|
94
91
|
|
|
95
92
|
Args:
|
|
96
93
|
curve_name: Curve name (e.g., "secp256r1")
|
|
@@ -100,6 +97,7 @@ class ECCConstants:
|
|
|
100
97
|
|
|
101
98
|
Raises:
|
|
102
99
|
ValueError: If curve_name is not supported
|
|
100
|
+
|
|
103
101
|
"""
|
|
104
102
|
curve_type = cls.CURVE_NAME_TO_TYPE.get(curve_name.lower())
|
|
105
103
|
if curve_type is None:
|
|
@@ -111,8 +109,7 @@ class ECCConstants:
|
|
|
111
109
|
|
|
112
110
|
@classmethod
|
|
113
111
|
def get_compressed_key_size_by_type(cls, curve_type: int) -> int:
|
|
114
|
-
"""
|
|
115
|
-
Get compressed public key size from curve type integer.
|
|
112
|
+
"""Get compressed public key size from curve type integer.
|
|
116
113
|
|
|
117
114
|
Args:
|
|
118
115
|
curve_type: Curve type (0=secp256r1, 1=secp384r1, 2=secp521r1, 3=secp256k1)
|
|
@@ -122,6 +119,7 @@ class ECCConstants:
|
|
|
122
119
|
|
|
123
120
|
Raises:
|
|
124
121
|
ValueError: If curve_type is not supported
|
|
122
|
+
|
|
125
123
|
"""
|
|
126
124
|
size = cls.COMPRESSED_KEY_SIZE_BY_TYPE.get(curve_type)
|
|
127
125
|
if size is None:
|
|
@@ -133,8 +131,7 @@ class ECCConstants:
|
|
|
133
131
|
|
|
134
132
|
@classmethod
|
|
135
133
|
def get_compressed_key_size_by_name(cls, curve_name: str) -> int:
|
|
136
|
-
"""
|
|
137
|
-
Get compressed public key size from curve name.
|
|
134
|
+
"""Get compressed public key size from curve name.
|
|
138
135
|
|
|
139
136
|
Args:
|
|
140
137
|
curve_name: Curve name (e.g., "secp256r1")
|
|
@@ -144,6 +141,7 @@ class ECCConstants:
|
|
|
144
141
|
|
|
145
142
|
Raises:
|
|
146
143
|
ValueError: If curve_name is not supported
|
|
144
|
+
|
|
147
145
|
"""
|
|
148
146
|
size = cls.COMPRESSED_KEY_SIZE_BY_NAME.get(curve_name.lower())
|
|
149
147
|
if size is None:
|
|
@@ -155,8 +153,7 @@ class ECCConstants:
|
|
|
155
153
|
|
|
156
154
|
@classmethod
|
|
157
155
|
def get_curve_object(cls, curve_name: str) -> ec.EllipticCurve:
|
|
158
|
-
"""
|
|
159
|
-
Get cryptography library curve object from curve name.
|
|
156
|
+
"""Get cryptography library curve object from curve name.
|
|
160
157
|
|
|
161
158
|
Args:
|
|
162
159
|
curve_name: Curve name (e.g., "secp256r1")
|
|
@@ -166,6 +163,7 @@ class ECCConstants:
|
|
|
166
163
|
|
|
167
164
|
Raises:
|
|
168
165
|
ValueError: If curve_name is not supported
|
|
166
|
+
|
|
169
167
|
"""
|
|
170
168
|
curve = cls.CURVE_OBJECTS.get(curve_name.lower())
|
|
171
169
|
if curve is None:
|
otdf_python/ecc_mode.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
"""Elliptic Curve Cryptography mode enumeration."""
|
|
2
|
+
|
|
1
3
|
from otdf_python.ecc_constants import ECCConstants
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
class ECCMode:
|
|
5
|
-
"""
|
|
6
|
-
ECC (Elliptic Curve Cryptography) mode configuration for NanoTDF.
|
|
7
|
+
"""ECC (Elliptic Curve Cryptography) mode configuration for NanoTDF.
|
|
7
8
|
|
|
8
9
|
This class encapsulates the curve type and policy binding mode (GMAC vs ECDSA)
|
|
9
10
|
that are encoded in the NanoTDF header. It delegates to ECCConstants for
|
|
@@ -11,6 +12,7 @@ class ECCMode:
|
|
|
11
12
|
"""
|
|
12
13
|
|
|
13
14
|
def __init__(self, curve_mode: int = 0, use_ecdsa_binding: bool = False):
|
|
15
|
+
"""Initialize ECC mode."""
|
|
14
16
|
self.curve_mode = curve_mode
|
|
15
17
|
self.use_ecdsa_binding = use_ecdsa_binding
|
|
16
18
|
|
|
@@ -34,6 +36,7 @@ class ECCMode:
|
|
|
34
36
|
|
|
35
37
|
Raises:
|
|
36
38
|
ValueError: If curve_mode is not supported
|
|
39
|
+
|
|
37
40
|
"""
|
|
38
41
|
# Delegate to ECCConstants for the authoritative mapping
|
|
39
42
|
return ECCConstants.get_curve_name(self.curve_mode)
|
|
@@ -50,6 +53,7 @@ class ECCMode:
|
|
|
50
53
|
|
|
51
54
|
Raises:
|
|
52
55
|
ValueError: If curve_type is not supported
|
|
56
|
+
|
|
53
57
|
"""
|
|
54
58
|
# Delegate to ECCConstants for the authoritative mapping
|
|
55
59
|
return ECCConstants.get_compressed_key_size_by_type(curve_type)
|
|
@@ -71,6 +75,7 @@ class ECCMode:
|
|
|
71
75
|
|
|
72
76
|
Raises:
|
|
73
77
|
ValueError: If curve_str is not a supported curve or binding type
|
|
78
|
+
|
|
74
79
|
"""
|
|
75
80
|
# Handle policy binding types (always use secp256r1 as default curve)
|
|
76
81
|
if curve_str.lower() == "gmac":
|
otdf_python/ecdh.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
ECDH (Elliptic Curve Diffie-Hellman) key exchange for NanoTDF.
|
|
1
|
+
"""ECDH (Elliptic Curve Diffie-Hellman) key exchange for NanoTDF.
|
|
3
2
|
|
|
4
3
|
This module implements the ECDH key exchange protocol with HKDF key derivation
|
|
5
4
|
as specified in the NanoTDF spec. It supports the following curves:
|
|
@@ -36,24 +35,17 @@ NANOTDF_HKDF_SALT = bytes.fromhex(
|
|
|
36
35
|
class ECDHError(Exception):
|
|
37
36
|
"""Base exception for ECDH operations."""
|
|
38
37
|
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
38
|
|
|
42
39
|
class UnsupportedCurveError(ECDHError):
|
|
43
40
|
"""Raised when an unsupported curve is specified."""
|
|
44
41
|
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
42
|
|
|
48
43
|
class InvalidKeyError(ECDHError):
|
|
49
44
|
"""Raised when a key is invalid or malformed."""
|
|
50
45
|
|
|
51
|
-
pass
|
|
52
|
-
|
|
53
46
|
|
|
54
47
|
def get_curve(curve_name: str) -> ec.EllipticCurve:
|
|
55
|
-
"""
|
|
56
|
-
Get the cryptography curve object for a given curve name.
|
|
48
|
+
"""Get the cryptography curve object for a given curve name.
|
|
57
49
|
|
|
58
50
|
Args:
|
|
59
51
|
curve_name: Name of the curve (e.g., "secp256r1")
|
|
@@ -63,6 +55,7 @@ def get_curve(curve_name: str) -> ec.EllipticCurve:
|
|
|
63
55
|
|
|
64
56
|
Raises:
|
|
65
57
|
UnsupportedCurveError: If the curve is not supported
|
|
58
|
+
|
|
66
59
|
"""
|
|
67
60
|
try:
|
|
68
61
|
# Delegate to ECCConstants for the authoritative mapping
|
|
@@ -72,8 +65,7 @@ def get_curve(curve_name: str) -> ec.EllipticCurve:
|
|
|
72
65
|
|
|
73
66
|
|
|
74
67
|
def get_compressed_key_size(curve_name: str) -> int:
|
|
75
|
-
"""
|
|
76
|
-
Get the size of a compressed public key for a given curve.
|
|
68
|
+
"""Get the size of a compressed public key for a given curve.
|
|
77
69
|
|
|
78
70
|
Args:
|
|
79
71
|
curve_name: Name of the curve (e.g., "secp256r1")
|
|
@@ -83,6 +75,7 @@ def get_compressed_key_size(curve_name: str) -> int:
|
|
|
83
75
|
|
|
84
76
|
Raises:
|
|
85
77
|
UnsupportedCurveError: If the curve is not supported
|
|
78
|
+
|
|
86
79
|
"""
|
|
87
80
|
try:
|
|
88
81
|
# Delegate to ECCConstants for the authoritative mapping
|
|
@@ -94,8 +87,7 @@ def get_compressed_key_size(curve_name: str) -> int:
|
|
|
94
87
|
def generate_ephemeral_keypair(
|
|
95
88
|
curve_name: str,
|
|
96
89
|
) -> tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]:
|
|
97
|
-
"""
|
|
98
|
-
Generate an ephemeral keypair for ECDH.
|
|
90
|
+
"""Generate an ephemeral keypair for ECDH.
|
|
99
91
|
|
|
100
92
|
Args:
|
|
101
93
|
curve_name: Name of the curve (e.g., "secp256r1")
|
|
@@ -105,6 +97,7 @@ def generate_ephemeral_keypair(
|
|
|
105
97
|
|
|
106
98
|
Raises:
|
|
107
99
|
UnsupportedCurveError: If the curve is not supported
|
|
100
|
+
|
|
108
101
|
"""
|
|
109
102
|
curve = get_curve(curve_name)
|
|
110
103
|
private_key = ec.generate_private_key(curve, default_backend())
|
|
@@ -113,14 +106,14 @@ def generate_ephemeral_keypair(
|
|
|
113
106
|
|
|
114
107
|
|
|
115
108
|
def compress_public_key(public_key: ec.EllipticCurvePublicKey) -> bytes:
|
|
116
|
-
"""
|
|
117
|
-
Compress an EC public key to compressed point format.
|
|
109
|
+
"""Compress an EC public key to compressed point format.
|
|
118
110
|
|
|
119
111
|
Args:
|
|
120
112
|
public_key: The EC public key to compress
|
|
121
113
|
|
|
122
114
|
Returns:
|
|
123
115
|
bytes: Compressed public key (33-67 bytes depending on curve)
|
|
116
|
+
|
|
124
117
|
"""
|
|
125
118
|
return public_key.public_bytes(
|
|
126
119
|
encoding=Encoding.X962, format=PublicFormat.CompressedPoint
|
|
@@ -130,8 +123,7 @@ def compress_public_key(public_key: ec.EllipticCurvePublicKey) -> bytes:
|
|
|
130
123
|
def decompress_public_key(
|
|
131
124
|
compressed_key: bytes, curve_name: str
|
|
132
125
|
) -> ec.EllipticCurvePublicKey:
|
|
133
|
-
"""
|
|
134
|
-
Decompress a public key from compressed point format.
|
|
126
|
+
"""Decompress a public key from compressed point format.
|
|
135
127
|
|
|
136
128
|
Args:
|
|
137
129
|
compressed_key: The compressed public key bytes
|
|
@@ -143,6 +135,7 @@ def decompress_public_key(
|
|
|
143
135
|
Raises:
|
|
144
136
|
InvalidKeyError: If the key cannot be decompressed
|
|
145
137
|
UnsupportedCurveError: If the curve is not supported
|
|
138
|
+
|
|
146
139
|
"""
|
|
147
140
|
try:
|
|
148
141
|
curve = get_curve(curve_name)
|
|
@@ -156,14 +149,13 @@ def decompress_public_key(
|
|
|
156
149
|
|
|
157
150
|
return ec.EllipticCurvePublicKey.from_encoded_point(curve, compressed_key)
|
|
158
151
|
except (ValueError, TypeError) as e:
|
|
159
|
-
raise InvalidKeyError(f"Failed to decompress public key: {e}")
|
|
152
|
+
raise InvalidKeyError(f"Failed to decompress public key: {e}") from e
|
|
160
153
|
|
|
161
154
|
|
|
162
155
|
def derive_shared_secret(
|
|
163
156
|
private_key: ec.EllipticCurvePrivateKey, public_key: ec.EllipticCurvePublicKey
|
|
164
157
|
) -> bytes:
|
|
165
|
-
"""
|
|
166
|
-
Derive a shared secret using ECDH.
|
|
158
|
+
"""Derive a shared secret using ECDH.
|
|
167
159
|
|
|
168
160
|
Args:
|
|
169
161
|
private_key: The private key (can be ephemeral or recipient's key)
|
|
@@ -174,12 +166,13 @@ def derive_shared_secret(
|
|
|
174
166
|
|
|
175
167
|
Raises:
|
|
176
168
|
ECDHError: If ECDH fails
|
|
169
|
+
|
|
177
170
|
"""
|
|
178
171
|
try:
|
|
179
172
|
shared_secret = private_key.exchange(ec.ECDH(), public_key)
|
|
180
173
|
return shared_secret
|
|
181
174
|
except Exception as e:
|
|
182
|
-
raise ECDHError(f"Failed to derive shared secret: {e}")
|
|
175
|
+
raise ECDHError(f"Failed to derive shared secret: {e}") from e
|
|
183
176
|
|
|
184
177
|
|
|
185
178
|
def derive_key_from_shared_secret(
|
|
@@ -188,8 +181,7 @@ def derive_key_from_shared_secret(
|
|
|
188
181
|
salt: bytes | None = None,
|
|
189
182
|
info: bytes = b"",
|
|
190
183
|
) -> bytes:
|
|
191
|
-
"""
|
|
192
|
-
Derive a symmetric encryption key from the ECDH shared secret using HKDF.
|
|
184
|
+
"""Derive a symmetric encryption key from the ECDH shared secret using HKDF.
|
|
193
185
|
|
|
194
186
|
Args:
|
|
195
187
|
shared_secret: The raw ECDH shared secret
|
|
@@ -202,6 +194,7 @@ def derive_key_from_shared_secret(
|
|
|
202
194
|
|
|
203
195
|
Raises:
|
|
204
196
|
ECDHError: If key derivation fails
|
|
197
|
+
|
|
205
198
|
"""
|
|
206
199
|
if salt is None:
|
|
207
200
|
salt = NANOTDF_HKDF_SALT
|
|
@@ -216,14 +209,13 @@ def derive_key_from_shared_secret(
|
|
|
216
209
|
)
|
|
217
210
|
return hkdf.derive(shared_secret)
|
|
218
211
|
except Exception as e:
|
|
219
|
-
raise ECDHError(f"Failed to derive key from shared secret: {e}")
|
|
212
|
+
raise ECDHError(f"Failed to derive key from shared secret: {e}") from e
|
|
220
213
|
|
|
221
214
|
|
|
222
215
|
def encrypt_key_with_ecdh(
|
|
223
216
|
recipient_public_key_pem: str, curve_name: str = "secp256r1"
|
|
224
217
|
) -> tuple[bytes, bytes]:
|
|
225
|
-
"""
|
|
226
|
-
High-level function: Generate ephemeral keypair and derive encryption key.
|
|
218
|
+
"""High-level function: Generate ephemeral keypair and derive encryption key.
|
|
227
219
|
|
|
228
220
|
This is used during NanoTDF encryption to derive the key that will be used
|
|
229
221
|
to encrypt the payload. The ephemeral public key must be stored in the
|
|
@@ -242,6 +234,7 @@ def encrypt_key_with_ecdh(
|
|
|
242
234
|
ECDHError: If key derivation fails
|
|
243
235
|
InvalidKeyError: If recipient's public key is invalid
|
|
244
236
|
UnsupportedCurveError: If the curve is not supported
|
|
237
|
+
|
|
245
238
|
"""
|
|
246
239
|
# Load recipient's public key
|
|
247
240
|
try:
|
|
@@ -251,7 +244,7 @@ def encrypt_key_with_ecdh(
|
|
|
251
244
|
if not isinstance(recipient_public_key, ec.EllipticCurvePublicKey):
|
|
252
245
|
raise InvalidKeyError("Recipient's public key is not an EC key")
|
|
253
246
|
except Exception as e:
|
|
254
|
-
raise InvalidKeyError(f"Failed to load recipient's public key: {e}")
|
|
247
|
+
raise InvalidKeyError(f"Failed to load recipient's public key: {e}") from e
|
|
255
248
|
|
|
256
249
|
# Generate ephemeral keypair
|
|
257
250
|
ephemeral_private_key, ephemeral_public_key = generate_ephemeral_keypair(curve_name)
|
|
@@ -273,8 +266,7 @@ def decrypt_key_with_ecdh(
|
|
|
273
266
|
compressed_ephemeral_public_key: bytes,
|
|
274
267
|
curve_name: str = "secp256r1",
|
|
275
268
|
) -> bytes:
|
|
276
|
-
"""
|
|
277
|
-
High-level function: Derive decryption key from ephemeral public key and recipient's private key.
|
|
269
|
+
"""High-level function: Derive decryption key from ephemeral public key and recipient's private key.
|
|
278
270
|
|
|
279
271
|
This is used during NanoTDF decryption to derive the same key that was used
|
|
280
272
|
to encrypt the payload. The ephemeral public key is extracted from the
|
|
@@ -292,6 +284,7 @@ def decrypt_key_with_ecdh(
|
|
|
292
284
|
ECDHError: If key derivation fails
|
|
293
285
|
InvalidKeyError: If keys are invalid
|
|
294
286
|
UnsupportedCurveError: If the curve is not supported
|
|
287
|
+
|
|
295
288
|
"""
|
|
296
289
|
# Load recipient's private key
|
|
297
290
|
try:
|
|
@@ -301,7 +294,7 @@ def decrypt_key_with_ecdh(
|
|
|
301
294
|
if not isinstance(recipient_private_key, ec.EllipticCurvePrivateKey):
|
|
302
295
|
raise InvalidKeyError("Recipient's private key is not an EC key")
|
|
303
296
|
except Exception as e:
|
|
304
|
-
raise InvalidKeyError(f"Failed to load recipient's private key: {e}")
|
|
297
|
+
raise InvalidKeyError(f"Failed to load recipient's private key: {e}") from e
|
|
305
298
|
|
|
306
299
|
# Decompress ephemeral public key
|
|
307
300
|
ephemeral_public_key = decompress_public_key(
|
otdf_python/eckeypair.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Elliptic Curve key pair management."""
|
|
2
|
+
|
|
1
3
|
from cryptography.exceptions import InvalidSignature
|
|
2
4
|
from cryptography.hazmat.backends import default_backend
|
|
3
5
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
@@ -12,7 +14,10 @@ from cryptography.hazmat.primitives.serialization import (
|
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class ECKeyPair:
|
|
17
|
+
"""Elliptic Curve key pair for cryptographic operations."""
|
|
18
|
+
|
|
15
19
|
def __init__(self, curve=None):
|
|
20
|
+
"""Initialize EC key pair."""
|
|
16
21
|
if curve is None:
|
|
17
22
|
curve = ec.SECP256R1()
|
|
18
23
|
self.private_key = ec.generate_private_key(curve, default_backend())
|
otdf_python/header.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""TDF header parsing and serialization."""
|
|
2
|
+
|
|
1
3
|
from otdf_python.constants import MAGIC_NUMBER_AND_VERSION
|
|
2
4
|
from otdf_python.ecc_mode import ECCMode
|
|
3
5
|
from otdf_python.policy_info import PolicyInfo
|
|
@@ -6,10 +8,13 @@ from otdf_python.symmetric_and_payload_config import SymmetricAndPayloadConfig
|
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class Header:
|
|
11
|
+
"""TDF header with encryption and policy information."""
|
|
12
|
+
|
|
9
13
|
# Size of GMAC (Galois Message Authentication Code) for policy binding
|
|
10
14
|
GMAC_SIZE = 8
|
|
11
15
|
|
|
12
16
|
def __init__(self):
|
|
17
|
+
"""Initialize TDF header."""
|
|
13
18
|
self.kas_locator: ResourceLocator | None = None
|
|
14
19
|
self.ecc_mode: ECCMode | None = None
|
|
15
20
|
self.payload_config: SymmetricAndPayloadConfig | None = None
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
"""Exception for invalid ZIP file errors."""
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class InvalidZipException(Exception):
|
|
2
|
-
"""
|
|
3
|
-
|
|
5
|
+
"""Raised when a ZIP file is invalid or corrupted.
|
|
6
|
+
|
|
4
7
|
Based on Java implementation.
|
|
5
8
|
"""
|
|
6
9
|
|
|
7
10
|
def __init__(self, message: str):
|
|
11
|
+
"""Initialize exception."""
|
|
8
12
|
super().__init__(message)
|