@@ -120,19 +120,14 @@ def get_signature_algorithm(padding: AsymmetricPadding, algorithm: HashAlgorithm
120
120
class KeyVaultRSAPublicKey (RSAPublicKey ):
121
121
"""An `RSAPublicKey` implementation based on a key managed by Key Vault.
122
122
123
- Only synchronous clients and operations are supported at this time.
123
+ This class should not be instantiated directly. Instead, use the
124
+ :func:`~azure.keyvault.keys.crypto.CryptographyClient.create_rsa_public_key` method to create a key based on the
125
+ client's key. Only synchronous clients and operations are supported at this time.
124
126
"""
125
127
126
- def __init__ (self , client : "CryptographyClient" , key_material : JsonWebKey ) -> None :
127
- """Creates a `KeyVaultRSAPublicKey` from a `CryptographyClient` and key.
128
-
129
- :param client: The client that will be used to communicate with Key Vault.
130
- :type client: ~azure.keyvault.keys.crypto.CryptographyClient
131
- :param key_material: They Key Vault key's material, as a `JsonWebKey`.
132
- :type key_material: ~azure.keyvault.keys.JsonWebKey
133
- """
128
+ def __init__ (self , client : "CryptographyClient" , key_material : Optional [JsonWebKey ] = None ) -> None :
134
129
self ._client : "CryptographyClient" = client
135
- self ._key : JsonWebKey = key_material
130
+ self ._key : Optional [ JsonWebKey ] = key_material
136
131
137
132
def encrypt (self , plaintext : bytes , padding : AsymmetricPadding ) -> bytes :
138
133
"""Encrypts the given plaintext.
@@ -156,7 +151,15 @@ def key_size(self) -> int:
156
151
157
152
:returns: The key's size.
158
153
:rtype: int
154
+
155
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
159
156
"""
157
+ if self ._key is None :
158
+ raise ValueError (
159
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
160
+ "(encrypt, verify) can be performed."
161
+ )
162
+
160
163
public_key = self .public_numbers ().public_key ()
161
164
return public_key .key_size
162
165
@@ -165,7 +168,15 @@ def public_numbers(self) -> RSAPublicNumbers:
165
168
166
169
:returns: The public numbers of the key.
167
170
:rtype: RSAPublicNumbers
171
+
172
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
168
173
"""
174
+ if self ._key is None :
175
+ raise ValueError (
176
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
177
+ "(encrypt, verify) can be performed."
178
+ )
179
+
169
180
e = int .from_bytes (self ._key .e , "big" ) # type: ignore[attr-defined]
170
181
n = int .from_bytes (self ._key .n , "big" ) # type: ignore[attr-defined]
171
182
return RSAPublicNumbers (e , n )
@@ -184,7 +195,15 @@ def public_bytes(self, encoding: Encoding, format: PublicFormat) -> bytes:
184
195
185
196
:returns: The serialized key.
186
197
:rtype: bytes
198
+
199
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
187
200
"""
201
+ if self ._key is None :
202
+ raise ValueError (
203
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
204
+ "(encrypt, verify) can be performed."
205
+ )
206
+
188
207
public_key = self .public_numbers ().public_key ()
189
208
return public_key .public_bytes (encoding = encoding , format = format )
190
209
@@ -250,12 +269,18 @@ def recover_data_from_signature(
250
269
251
270
:returns: The signed data.
252
271
:rtype: bytes
253
- :raises:
254
- NotImplementedError if the local version of `cryptography` doesn't support this method.
255
- :class:`~cryptography.exceptions.InvalidSignature` if the signature is invalid.
256
- :class:`~cryptography.exceptions.UnsupportedAlgorithm` if the signature data recovery is not supported with
272
+ :raises NotImplementedError: if the local version of `cryptography` doesn't support this method.
273
+ :raises ~cryptography.exceptions.InvalidSignature: if the signature is invalid.
274
+ :raises ~cryptography.exceptions.UnsupportedAlgorithm: if the signature data recovery is not supported with
257
275
the provided `padding` type.
276
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
258
277
"""
278
+ if self ._key is None :
279
+ raise ValueError (
280
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
281
+ "(encrypt, verify) can be performed."
282
+ )
283
+
259
284
public_key = self .public_numbers ().public_key ()
260
285
try :
261
286
return public_key .recover_data_from_signature (signature = signature , padding = padding , algorithm = algorithm )
@@ -270,9 +295,13 @@ def __eq__(self, other: object) -> bool:
270
295
:param object other: Another object to compare with this instance. Currently, only comparisons with
271
296
`KeyVaultRSAPrivateKey` or `JsonWebKey` instances are supported.
272
297
273
- :returns: True if the objects are equal; False otherwise.
298
+ :returns: True if the objects are equal; False if the objects are unequal or if key material can't be obtained
299
+ from Key Vault for comparison.
274
300
:rtype: bool
275
301
"""
302
+ if self ._key is None :
303
+ return False
304
+
276
305
if isinstance (other , KeyVaultRSAPublicKey ):
277
306
return all (getattr (self ._key , field ) == getattr (other ._key , field ) for field in self ._key ._FIELDS )
278
307
if isinstance (other , JsonWebKey ):
@@ -289,19 +318,14 @@ def verifier( # pylint:disable=docstring-missing-param,docstring-missing-return
289
318
class KeyVaultRSAPrivateKey (RSAPrivateKey ):
290
319
"""An `RSAPrivateKey` implementation based on a key managed by Key Vault.
291
320
292
- Only synchronous clients and operations are supported at this time.
321
+ This class should not be instantiated directly. Instead, use the
322
+ :func:`~azure.keyvault.keys.crypto.CryptographyClient.create_rsa_private_key` method to create a key based on the
323
+ client's key. Only synchronous clients and operations are supported at this time.
293
324
"""
294
325
295
- def __init__ (self , client : "CryptographyClient" , key_material : JsonWebKey ) -> None :
296
- """Creates a `KeyVaultRSAPrivateKey` from a `CryptographyClient` and key.
297
-
298
- :param client: The client that will be used to communicate with Key Vault.
299
- :type client: ~azure.keyvault.keys.crypto.CryptographyClient
300
- :param key_material: They Key Vault key's material, as a `JsonWebKey`.
301
- :type key_material: ~azure.keyvault.keys.JsonWebKey
302
- """
326
+ def __init__ (self , client : "CryptographyClient" , key_material : Optional [JsonWebKey ]) -> None :
303
327
self ._client : "CryptographyClient" = client
304
- self ._key : JsonWebKey = key_material
328
+ self ._key : Optional [ JsonWebKey ] = key_material
305
329
306
330
def decrypt (self , ciphertext : bytes , padding : AsymmetricPadding ) -> bytes :
307
331
"""Decrypts the provided ciphertext.
@@ -325,7 +349,15 @@ def key_size(self) -> int:
325
349
326
350
:returns: The key's size.
327
351
:rtype: int
352
+
353
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
328
354
"""
355
+ if self ._key is None :
356
+ raise ValueError (
357
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
358
+ "(decrypt, sign) can be performed."
359
+ )
360
+
329
361
# Key size only requires public modulus, which we can always get
330
362
# Relying on private numbers instead would cause issues for keys stored in KV (which doesn't return private key)
331
363
return self .public_key ().key_size
@@ -374,7 +406,15 @@ def private_numbers(self) -> RSAPrivateNumbers:
374
406
375
407
:returns: The private numbers of the key.
376
408
:rtype: ~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers
409
+
410
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
377
411
"""
412
+ if self ._key is None :
413
+ raise ValueError (
414
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
415
+ "(decrypt, sign) can be performed."
416
+ )
417
+
378
418
# Fetch public numbers from JWK
379
419
e = int .from_bytes (self ._key .e , "big" ) # type: ignore[attr-defined]
380
420
n = int .from_bytes (self ._key .n , "big" ) # type: ignore[attr-defined]
@@ -420,7 +460,15 @@ def private_bytes(
420
460
421
461
:returns: The serialized key.
422
462
:rtype: bytes
463
+
464
+ :raises ValueError: if the client is unable to obtain the key material from Key Vault.
423
465
"""
466
+ if self ._key is None :
467
+ raise ValueError (
468
+ "Key material could not be obtained from Key Vault. Only remote cryptographic operations "
469
+ "(decrypt, sign) can be performed."
470
+ )
471
+
424
472
try :
425
473
private_numbers = self .private_numbers ()
426
474
except ValueError as exc :
0 commit comments