Skip to content

Commit 9cbc08c

Browse files
authored
[Key Vault] Align keys with other languages (Azure#18765)
1 parent 97c4a93 commit 9cbc08c

15 files changed

+340
-61
lines changed

sdk/keyvault/azure-keyvault-keys/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Release History
22

33
## 4.4.0b5 (Unreleased)
4+
### Added
5+
- `KeyClient` has a `create_oct_key` method for creating symmetric keys
46

7+
### Breaking Changes
8+
- `parse_key_vault_key_id` and `KeyVaultResourceId` have been replaced by a
9+
`KeyVaultKeyIdentifier` class, which can be initialized with a key ID
510

611
## 4.4.0b4 (2021-04-06)
7-
812
### Added
913
- `CryptographyClient` can perform AES-CBCPAD encryption and decryption locally
1014
([#17762](https://github.com/Azure/azure-sdk-for-python/pull/17762))

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,21 @@
33
# Licensed under the MIT License.
44
# -------------------------------------
55
from ._enums import KeyCurveName, KeyOperation, KeyType
6-
from ._parse_id import parse_key_vault_key_id
76
from ._shared.client_base import ApiVersion
8-
from ._shared import KeyVaultResourceId
9-
from ._models import DeletedKey, JsonWebKey, KeyProperties, KeyVaultKey
7+
from ._models import DeletedKey, JsonWebKey, KeyProperties, KeyVaultKey, KeyVaultKeyIdentifier
108
from ._client import KeyClient
119

1210
__all__ = [
1311
"ApiVersion",
1412
"KeyClient",
1513
"JsonWebKey",
1614
"KeyVaultKey",
15+
"KeyVaultKeyIdentifier",
1716
"KeyCurveName",
1817
"KeyOperation",
1918
"KeyType",
2019
"DeletedKey",
21-
"KeyProperties",
22-
"parse_key_vault_key_id",
23-
"KeyVaultResourceId"
20+
"KeyProperties"
2421
]
2522

2623
from ._version import VERSION

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_client.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717

1818
if TYPE_CHECKING:
1919
# pylint:disable=unused-import
20-
from typing import Any, List, Optional, Union
21-
from datetime import datetime
20+
from typing import Any, Optional, Union
2221
from azure.core.paging import ItemPaged
2322
from ._models import JsonWebKey
2423

@@ -55,8 +54,8 @@ def create_key(self, name, key_type, **kwargs):
5554
:param str name: The name of the new key.
5655
:param key_type: The type of key to create
5756
:type key_type: ~azure.keyvault.keys.KeyType or str
58-
:keyword int size: RSA key size in bits, for example 2048, 3072, or 4096. Applies only to RSA keys. To
59-
create an RSA key, consider using :func:`create_rsa_key` instead.
57+
:keyword int size: Key size in bits. Applies only to RSA and symmetric keys. Consider using
58+
:func:`create_rsa_key` or :func:`create_oct_key` instead.
6059
:keyword curve: Elliptic curve name. Applies only to elliptic curve keys. Defaults to the NIST P-256
6160
elliptic curve. To create an elliptic curve key, consider using :func:`create_ec_key` instead.
6261
:paramtype curve: ~azure.keyvault.keys.KeyCurveName or str
@@ -175,6 +174,39 @@ def create_ec_key(self, name, **kwargs):
175174
hsm = kwargs.pop("hardware_protected", False)
176175
return self.create_key(name, key_type="EC-HSM" if hsm else "EC", **kwargs)
177176

177+
@distributed_trace
178+
def create_oct_key(self, name, **kwargs):
179+
# type: (str, **Any) -> KeyVaultKey
180+
"""Create a new octet sequence (symmetric) key or, if `name` is already in use, create a new version of the key.
181+
182+
Requires the keys/create permission.
183+
184+
:param str name: The name for the new key.
185+
:keyword int size: Key size in bits, for example 128, 192, or 256.
186+
:keyword key_operations: Allowed key operations.
187+
:paramtype key_operations: list[~azure.keyvault.keys.KeyOperation or str]
188+
:keyword bool hardware_protected: Whether the key should be created in a hardware security module.
189+
Defaults to ``False``.
190+
:keyword bool enabled: Whether the key is enabled for use.
191+
:keyword tags: Application specific metadata in the form of key-value pairs.
192+
:paramtype tags: dict[str, str]
193+
:keyword ~datetime.datetime not_before: Not before date of the key in UTC
194+
:keyword ~datetime.datetime expires_on: Expiry date of the key in UTC
195+
:returns: The created key
196+
:rtype: ~azure.keyvault.keys.KeyVaultKey
197+
:raises: :class:`~azure.core.exceptions.HttpResponseError`
198+
199+
Example:
200+
.. literalinclude:: ../tests/test_samples_keys.py
201+
:start-after: [START create_oct_key]
202+
:end-before: [END create_oct_key]
203+
:language: python
204+
:caption: Create an octet sequence (symmetric) key
205+
:dedent: 8
206+
"""
207+
hsm = kwargs.pop("hardware_protected", False)
208+
return self.create_key(name, key_type="oct-HSM" if hsm else "oct", **kwargs)
209+
178210
@distributed_trace
179211
def begin_delete_key(self, name, **kwargs):
180212
# type: (str, **Any) -> DeletedKey

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_models.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def __init__(self, key_id, attributes=None, **kwargs):
6868
# type: (str, Optional[_models.KeyAttributes], **Any) -> None
6969
self._attributes = attributes
7070
self._id = key_id
71-
self._vault_id = parse_key_vault_id(key_id)
71+
self._vault_id = KeyVaultKeyIdentifier(key_id)
7272
self._managed = kwargs.get("managed", None)
7373
self._tags = kwargs.get("tags", None)
7474

@@ -325,6 +325,45 @@ def key_operations(self):
325325
return self._key_material.key_ops # pylint:disable=no-member
326326

327327

328+
class KeyVaultKeyIdentifier(object):
329+
"""Information about a KeyVaultKey parsed from a key ID.
330+
331+
:param str id: the full original identifier of a key
332+
:raises ValueError: if the key ID is improperly formatted
333+
Example:
334+
.. literalinclude:: ../tests/test_parse_id.py
335+
:start-after: [START parse_key_vault_key_id]
336+
:end-before: [END parse_key_vault_key_id]
337+
:language: python
338+
:caption: Parse a key's ID
339+
:dedent: 8
340+
"""
341+
342+
def __init__(self, id): # pylint: disable=W0622
343+
# type: (str) -> None
344+
self._resource_id = parse_key_vault_id(id)
345+
346+
@property
347+
def source_id(self):
348+
# type: () -> str
349+
return self._resource_id.source_id
350+
351+
@property
352+
def vault_url(self):
353+
# type: () -> str
354+
return self._resource_id.vault_url
355+
356+
@property
357+
def name(self):
358+
# type: () -> str
359+
return self._resource_id.name
360+
361+
@property
362+
def version(self):
363+
# type: () -> Optional[str]
364+
return self._resource_id.version
365+
366+
328367
class DeletedKey(KeyVaultKey):
329368
"""A deleted key's properties, cryptographic material and its deletion information. If soft-delete
330369
is enabled, returns information about its recovery as well."""

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_parse_id.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/_client.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515

1616
if TYPE_CHECKING:
1717
# pylint:disable=ungrouped-imports
18-
from datetime import datetime
1918
from azure.core.async_paging import AsyncItemPaged
20-
from typing import Any, Optional, List, Union
19+
from typing import Any, Optional, Union
2120
from .. import KeyType
2221

2322

@@ -53,8 +52,8 @@ async def create_key(self, name: str, key_type: "Union[str, KeyType]", **kwargs:
5352
:param str name: The name of the new key.
5453
:param key_type: The type of key to create
5554
:type key_type: ~azure.keyvault.keys.KeyType or str
56-
:keyword int size: RSA key size in bits, for example 2048, 3072, or 4096. Applies only to RSA keys. To
57-
create an RSA key, consider using :func:`create_rsa_key` instead.
55+
:keyword int size: Key size in bits. Applies only to RSA and symmetric keys. Consider using
56+
:func:`create_rsa_key` or :func:`create_oct_key` instead.
5857
:keyword curve: Elliptic curve name. Applies only to elliptic curve keys. Defaults to the NIST P-256
5958
elliptic curve. To create an elliptic curve key, consider using :func:`create_ec_key` instead.
6059
:paramtype curve: ~azure.keyvault.keys.KeyCurveName or str
@@ -172,6 +171,38 @@ async def create_ec_key(self, name: str, **kwargs: "Any") -> KeyVaultKey:
172171
hsm = kwargs.pop("hardware_protected", False)
173172
return await self.create_key(name, key_type="EC-HSM" if hsm else "EC", **kwargs)
174173

174+
@distributed_trace_async
175+
async def create_oct_key(self, name: str, **kwargs: "Any") -> KeyVaultKey:
176+
"""Create a new octet sequence (symmetric) key or, if `name` is already in use, create a new version of the key.
177+
178+
Requires the keys/create permission.
179+
180+
:param str name: The name for the new key.
181+
:keyword int size: Key size in bits, for example 128, 192, or 256.
182+
:keyword key_operations: Allowed key operations.
183+
:paramtype key_operations: list[~azure.keyvault.keys.KeyOperation or str]
184+
:keyword bool hardware_protected: Whether the key should be created in a hardware security module.
185+
Defaults to ``False``.
186+
:keyword bool enabled: Whether the key is enabled for use.
187+
:keyword tags: Application specific metadata in the form of key-value pairs.
188+
:paramtype tags: dict[str, str]
189+
:keyword ~datetime.datetime not_before: Not before date of the key in UTC
190+
:keyword ~datetime.datetime expires_on: Expiry date of the key in UTC
191+
:returns: The created key
192+
:rtype: ~azure.keyvault.keys.KeyVaultKey
193+
:raises: :class:`~azure.core.exceptions.HttpResponseError`
194+
195+
Example:
196+
.. literalinclude:: ../tests/test_samples_keys_async.py
197+
:start-after: [START create_oct_key]
198+
:end-before: [END create_oct_key]
199+
:language: python
200+
:caption: Create an octet sequence (symmetric) key
201+
:dedent: 8
202+
"""
203+
hsm = kwargs.pop("hardware_protected", False)
204+
return await self.create_key(name, key_type="oct-HSM" if hsm else "oct", **kwargs)
205+
175206
@distributed_trace_async
176207
async def delete_key(self, name: str, **kwargs: "Any") -> DeletedKey:
177208
"""Delete all versions of a key and its cryptographic material. Requires keys/delete permission.

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/crypto/_client.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ def _validate_arguments(operation, algorithm, **kwargs):
4747
raise ValueError(
4848
"iv should only be provided with AES-CBC algorithms; {} does not accept an iv".format(algorithm)
4949
)
50+
if iv is None and "CBC" in algorithm:
51+
raise ValueError("iv is a required parameter for encryption with AES-CBC algorithms.")
5052
if aad and not ("CBC" in algorithm or "GCM" in algorithm):
5153
raise ValueError(
5254
"additional_authenticated_data should only be provided with AES algorithms; {} does not accept "
@@ -58,12 +60,16 @@ def _validate_arguments(operation, algorithm, **kwargs):
5860
raise ValueError(
5961
"iv should only be provided with AES algorithms; {} does not accept an iv".format(algorithm)
6062
)
63+
if iv is None and ("CBC" in algorithm or "GCM" in algorithm):
64+
raise ValueError("iv is a required parameter for decryption with AES algorithms.")
6165
if tag and "GCM" not in algorithm:
6266
raise ValueError(
6367
"authentication_tag should only be provided with AES-GCM algorithms; {} does not accept a tag".format(
6468
algorithm
6569
)
6670
)
71+
if tag is None and "GCM" in algorithm:
72+
raise ValueError("authentication_tag is a required parameter for AES-GCM decryption.")
6773
if aad and not ("CBC" in algorithm or "GCM" in algorithm):
6874
raise ValueError(
6975
"additional_authenticated_data should only be provided with AES algorithms; {} does not accept "
@@ -211,7 +217,7 @@ def encrypt(self, algorithm, plaintext, **kwargs):
211217
:param algorithm: encryption algorithm to use
212218
:type algorithm: :class:`~azure.keyvault.keys.crypto.EncryptionAlgorithm`
213219
:param bytes plaintext: bytes to encrypt
214-
:keyword bytes iv: optional initialization vector. For use with AES-CBC encryption.
220+
:keyword bytes iv: initialization vector. Required for only AES-CBC(PAD) encryption.
215221
:keyword bytes additional_authenticated_data: optional data that is authenticated but not encrypted. For use
216222
with AES-GCM encryption.
217223
:rtype: :class:`~azure.keyvault.keys.crypto.EncryptResult`
@@ -269,11 +275,11 @@ def decrypt(self, algorithm, ciphertext, **kwargs):
269275
:param algorithm: encryption algorithm to use
270276
:type algorithm: :class:`~azure.keyvault.keys.crypto.EncryptionAlgorithm`
271277
:param bytes ciphertext: encrypted bytes to decrypt
272-
:keyword bytes iv: the initialization vector used during encryption. For use with AES encryption.
273-
:keyword bytes authentication_tag: the authentication tag generated during encryption. For use with AES-GCM
274-
encryption.
278+
:keyword bytes iv: the initialization vector used during encryption. Required for AES decryption.
279+
:keyword bytes authentication_tag: the authentication tag generated during encryption. Required for only AES-GCM
280+
decryption.
275281
:keyword bytes additional_authenticated_data: optional data that is authenticated but not encrypted. For use
276-
with AES-GCM encryption.
282+
with AES-GCM decryption.
277283
:rtype: :class:`~azure.keyvault.keys.crypto.DecryptResult`
278284
:raises ValueError: if parameters that are incompatible with the specified algorithm are provided.
279285

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/crypto/aio/_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ async def encrypt(self, algorithm: "EncryptionAlgorithm", plaintext: bytes, **kw
160160
:param algorithm: encryption algorithm to use
161161
:type algorithm: :class:`~azure.keyvault.keys.crypto.EncryptionAlgorithm`
162162
:param bytes plaintext: bytes to encrypt
163-
:keyword bytes iv: optional initialization vector. For use with AES-CBC encryption.
163+
:keyword bytes iv: initialization vector. Required for only AES-CBC(PAD) encryption.
164164
:keyword bytes additional_authenticated_data: optional data that is authenticated but not encrypted. For use
165165
with AES-GCM encryption.
166166
:rtype: :class:`~azure.keyvault.keys.crypto.EncryptResult`
@@ -217,11 +217,11 @@ async def decrypt(self, algorithm: "EncryptionAlgorithm", ciphertext: bytes, **k
217217
:param algorithm: encryption algorithm to use
218218
:type algorithm: :class:`~azure.keyvault.keys.crypto.EncryptionAlgorithm`
219219
:param bytes ciphertext: encrypted bytes to decrypt
220-
:keyword bytes iv: the initialization vector used during encryption. For use with AES encryption.
221-
:keyword bytes authentication_tag: the authentication tag generated during encryption. For use with AES-GCM
222-
encryption.
220+
:keyword bytes iv: the initialization vector used during encryption. Required for AES decryption.
221+
:keyword bytes authentication_tag: the authentication tag generated during encryption. Required for only AES-GCM
222+
decryption.
223223
:keyword bytes additional_authenticated_data: optional data that is authenticated but not encrypted. For use
224-
with AES-GCM encryption.
224+
with AES-GCM decryption.
225225
:rtype: :class:`~azure.keyvault.keys.crypto.DecryptResult`
226226
:raises ValueError: if parameters that are incompatible with the specified algorithm are provided.
227227

0 commit comments

Comments
 (0)