From 47db620327388c98c966883864a5928319711282 Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Wed, 11 May 2022 14:44:10 -0700 Subject: [PATCH 01/13] Start implementation of Encryption V2 for Queue --- .../azure/storage/queue/_message_encoding.py | 6 +- .../azure/storage/queue/_queue_client.py | 1 + .../storage/queue/_queue_service_client.py | 5 +- .../storage/queue/_shared/base_client.py | 1 + .../azure/storage/queue/_shared/encryption.py | 191 ++++++++++++++---- .../tests/test_queue_encryption.py | 18 ++ 6 files changed, 178 insertions(+), 44 deletions(-) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py index e9b4f88eb0c7..1204b81c8edb 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py @@ -18,6 +18,7 @@ class MessageEncodePolicy(object): def __init__(self): self.require_encryption = False + self.encryption_algorithm = None self.key_encryption_key = None self.resolver = None @@ -25,11 +26,12 @@ def __call__(self, content): if content: content = self.encode(content) if self.key_encryption_key is not None: - content = encrypt_queue_message(content, self.key_encryption_key) + content = encrypt_queue_message(content, self.key_encryption_key, self.encryption_algorithm) return content - def configure(self, require_encryption, key_encryption_key, resolver): + def configure(self, require_encryption, encryption_algorithm, key_encryption_key, resolver): self.require_encryption = require_encryption + self.encryption_algorithm = encryption_algorithm self.key_encryption_key = key_encryption_key self.resolver = resolver if self.require_encryption and not self.key_encryption_key: diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py index cd19c17a1b9a..3adc5ee3e640 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py @@ -479,6 +479,7 @@ def send_message( timeout = kwargs.pop('timeout', None) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, + encryption_algorithm=self.encryption_algorithm, key_encryption_key=self.key_encryption_key, resolver=self.key_resolver_function) encoded_content = self._config.message_encode_policy(content) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py index 374b71a54f8b..e68eec62f5db 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py @@ -433,5 +433,6 @@ def get_queue_client(self, return QueueClient( self.url, queue_name=queue_name, credential=self.credential, key_resolver_function=self.key_resolver_function, require_encryption=self.require_encryption, - key_encryption_key=self.key_encryption_key, api_version=self.api_version, _pipeline=_pipeline, - _configuration=self._config, _location_mode=self._location_mode, _hosts=self._hosts, **kwargs) + encryption_algorithm=self.encryption_algorithm, key_encryption_key=self.key_encryption_key, + api_version=self.api_version, _pipeline=_pipeline, _configuration=self._config, + _location_mode=self._location_mode, _hosts=self._hosts, **kwargs) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py index f8fae9e6acc5..45342d9cf5b2 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py @@ -104,6 +104,7 @@ def __init__( self._hosts = {LocationMode.PRIMARY: primary_hostname, LocationMode.SECONDARY: secondary_hostname} self.require_encryption = kwargs.get("require_encryption", False) + self.encryption_algorithm = kwargs.get("encryption_algorithm", "AES_CBC_256") self.key_encryption_key = kwargs.get("key_encryption_key") self.key_resolver_function = kwargs.get("key_resolver_function") self._config, self._pipeline = self._create_pipeline(self.credential, storage_sdk=service, **kwargs) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index 439db5be42ae..b2c627d0c23f 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -14,6 +14,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.padding import PKCS7 @@ -25,6 +26,9 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' +_ENCRYPTION_PROTOCOL_V2 = '2.0' +_GCM_BLOCK_SIZE = 4 * 1024 * 1024 +_GCM_NONCE_LENGTH = 12 _ERROR_OBJECT_INVALID = \ '{0} does not define a complete interface. Value of {1} is either missing or invalid.' @@ -49,6 +53,7 @@ class _EncryptionAlgorithm(object): Specifies which client encryption algorithm is used. ''' AES_CBC_256 = 'AES_CBC_256' + AES_GCM_256 = 'AES_GCM_256' class _WrappedContentKey: @@ -75,6 +80,26 @@ def __init__(self, algorithm, encrypted_key, key_id): self.key_id = key_id +class _AuthenticationBlockInfo: + ''' + Represents the length of encryption elements. + This is only used for AES-GCM. + ''' + + def __init__(self, ciphertext_length, nonce_length): + ''' + :param int ciphertext_length: + The length of the ciphertext block. + :param str nonce_length: + The length of nonce used when encrypting. + ''' + _validate_not_none('ciphertext_length', ciphertext_length) + _validate_not_none('nonce_length', nonce_length) + + self.ciphertext_length = ciphertext_length + self.nonce_length = nonce_length + + class _EncryptionAgent: ''' Represents the encryption agent stored on the service. @@ -101,11 +126,20 @@ class _EncryptionData: Represents the encryption data that is stored on the service. ''' - def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, - key_wrapping_metadata): + def __init__( + self, + content_encryption_IV, + authentication_block_info, + encryption_agent, + wrapped_content_key, + key_wrapping_metadata): ''' - :param bytes content_encryption_IV: + :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. + Required for AES-CBC. + :param Optional[_AuthenticationBlockInfo] authentication_block_info: + The info about the autenticated block sizes. + Required for AES-GCM. :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -115,23 +149,32 @@ def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, A dict containing metadata related to the key wrapping. ''' - _validate_not_none('content_encryption_IV', content_encryption_IV) _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) + # Validate we have the right info for the specified algorithm + if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + _validate_not_none('content_encryption_IV', content_encryption_IV) + elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + _validate_not_none('authentication_block_info', authentication_block_info) + else: + raise ValueError("Invalid encryption algorithm.") + self.content_encryption_IV = content_encryption_IV + self.authentication_block_info = authentication_block_info self.encryption_agent = encryption_agent self.wrapped_content_key = wrapped_content_key self.key_wrapping_metadata = key_wrapping_metadata -def _generate_encryption_data_dict(kek, cek, iv): +def _generate_encryption_data_dict(kek, cek, iv, algorithm): ''' Generates and returns the encryption metadata as a dict. :param object kek: The key encryption key. See calling functions for more information. :param bytes cek: The content encryption key. - :param bytes iv: The initialization vector. + :param Optional[bytes] iv: The initialization vector. Only required for AES-CBC. + :param str algorithm: The client encryption algorithm used. :return: A dict containing all the encryption metadata. :rtype: dict ''' @@ -146,13 +189,25 @@ def _generate_encryption_data_dict(kek, cek, iv): wrapped_content_key['Algorithm'] = kek.get_key_wrap_algorithm() encryption_agent = OrderedDict() - encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V1 - encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + encryption_agent['EncryptionAlgorithm'] = algorithm + + if algorithm == _EncryptionAlgorithm.AES_CBC_256: + encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V1 + + elif algorithm == _EncryptionAlgorithm.AES_GCM_256: + encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V2 + + authentication_block_info = OrderedDict() + authentication_block_info['CiphertextLength'] = _GCM_BLOCK_SIZE + authentication_block_info['NonceLength'] = _GCM_NONCE_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key encryption_data_dict['EncryptionAgent'] = encryption_agent - encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + if algorithm == _EncryptionAlgorithm.AES_CBC_256: + encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + elif algorithm == _EncryptionAlgorithm.AES_GCM_256: + encryption_data_dict['AuthenticationBlockInfo'] = authentication_block_info encryption_data_dict['KeyWrappingMetadata'] = {'EncryptionLibrary': 'Python ' + VERSION} return encryption_data_dict @@ -169,7 +224,8 @@ def _dict_to_encryption_data(encryption_data_dict): :rtype: _EncryptionData ''' try: - if encryption_data_dict['EncryptionAgent']['Protocol'] != _ENCRYPTION_PROTOCOL_V1: + protocol = encryption_data_dict['EncryptionAgent']['Protocol'] + if protocol not in [_ENCRYPTION_PROTOCOL_V1, _ENCRYPTION_PROTOCOL_V2]: raise ValueError("Unsupported encryption version.") except KeyError: raise ValueError("Unsupported encryption version.") @@ -187,7 +243,20 @@ def _dict_to_encryption_data(encryption_data_dict): else: key_wrapping_metadata = None - encryption_data = _EncryptionData(decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']), + # AES-CBC only + encryption_iv = None + if 'ContentEncryptionIV' in encryption_data_dict: + encryption_iv = decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']) + + # AES-GCM only + block_info = None + if 'AuthenticationBlockInfo' in encryption_data_dict: + authentication_block_info = encryption_data_dict['AuthenticationBlockInfo'] + block_info = _AuthenticationBlockInfo(authentication_block_info['CiphertextLength'], + authentication_block_info['NonceLength']) + + encryption_data = _EncryptionData(encryption_iv, + block_info, encryption_agent, wrapped_content_key, key_wrapping_metadata) @@ -227,11 +296,15 @@ def _validate_and_unwrap_cek(encryption_data, key_encryption_key=None, key_resol :rtype: bytes[] ''' - _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) _validate_not_none('encrypted_key', encryption_data.wrapped_content_key.encrypted_key) - if _ENCRYPTION_PROTOCOL_V1 != encryption_data.encryption_agent.protocol: - raise ValueError('Encryption version is not supported.') + # Validate we have the right info for the specified algorithm + if encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) + elif encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + _validate_not_none('authentication_block_info', encryption_data.authentication_block_info) + else: + raise ValueError('Specified encryption algorithm is not supported.') content_encryption_key = None @@ -279,19 +352,37 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver _validate_not_none('message', message) content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, resolver) - if _EncryptionAlgorithm.AES_CBC_256 != encryption_data.encryption_agent.encryption_algorithm: - raise ValueError('Specified encryption algorithm is not supported.') + if encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + if not encryption_data.content_encryption_IV: + raise ValueError("Missing required metadata for decryption.") - cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) + cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) - # decrypt data - decrypted_data = message - decryptor = cipher.decryptor() - decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + # decrypt data + decrypted_data = message + decryptor = cipher.decryptor() + decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + + # unpad data + unpadder = PKCS7(128).unpadder() + decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) - # unpad data - unpadder = PKCS7(128).unpadder() - decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + elif encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + block_info = encryption_data.authentication_block_info + if not block_info or not block_info.nonce_length: + raise ValueError("Missing required metadata for decryption.") + + nonce_length = encryption_data.authentication_block_info.nonce_length + + # First bytes are the nonce + nonce = message[:nonce_length] + ciphertext_with_tag = message[nonce_length:] + + aesgcm = AESGCM(content_encryption_key) + decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) + + else: + raise ValueError('Specified encryption algorithm is not supported.') return decrypted_data @@ -333,7 +424,7 @@ def encrypt_blob(blob, key_encryption_key): encryptor = cipher.encryptor() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' return dumps(encryption_data), encrypted_data @@ -358,7 +449,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, + _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' encryption_data = dumps(encryption_data) @@ -452,9 +544,9 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): return encryptor, padder -def encrypt_queue_message(message, key_encryption_key): +def encrypt_queue_message(message, key_encryption_key, algorithm): ''' - Encrypts the given plain text message using AES256 in CBC mode with 128 bit padding. + Encrypts the given plain text message using the given algorithm. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. @@ -465,6 +557,7 @@ def encrypt_queue_message(message, key_encryption_key): wrap_key(key)--wraps the specified key using an algorithm of the user's choice. get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key. get_kid()--returns a string key id for this key-encryption-key. + :param str algorithm: The client encryption algorithm to use. :return: A json-formatted string containing the encrypted message and the encryption metadata. :rtype: str ''' @@ -473,29 +566,47 @@ def encrypt_queue_message(message, key_encryption_key): _validate_not_none('key_encryption_key', key_encryption_key) _validate_key_encryption_key_wrap(key_encryption_key) - # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = os.urandom(32) - initialization_vector = os.urandom(16) - # Queue encoding functions all return unicode strings, and encryption should # operate on binary strings. message = message.encode('utf-8') - cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) + if algorithm == _EncryptionAlgorithm.AES_CBC_256: + # AES256 CBC uses 256 bit (32 byte) keys and always with 16 byte blocks + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) - # PKCS7 with 16 byte blocks ensures compatibility with AES. - padder = PKCS7(128).padder() - padded_data = padder.update(message) + padder.finalize() + cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) - # Encrypt the data. - encryptor = cipher.encryptor() - encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + # PKCS7 with 16 byte blocks ensures compatibility with AES. + padder = PKCS7(128).padder() + padded_data = padder.update(message) + padder.finalize() + + # Encrypt the data. + encryptor = cipher.encryptor() + encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + + elif algorithm == _EncryptionAlgorithm.AES_GCM_256: + # AES256 GCM uses 256 bit (32 byte) keys and a 12 byte nonce. + content_encryption_key = AESGCM.generate_key(bit_length=256) + initialization_vector = None + + # The nonce MUST be different for each key + nonce = os.urandom(12) + aesgcm = AESGCM(content_encryption_key) + + # Returns ciphertext + tag + cipertext_with_tag = aesgcm.encrypt(nonce, message, None) + encrypted_data = nonce + cipertext_with_tag + + else: + raise ValueError("Invalid encryption algorithm.") # Build the dictionary structure. queue_message = {'EncryptedMessageContents': encode_base64(encrypted_data), 'EncryptionData': _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector)} + initialization_vector, + algorithm)} return dumps(queue_message) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index 9c70488c9b5b..a055b5e40c1c 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -475,6 +475,24 @@ def test_encryption_nonmatching_kid(self, storage_account_name, storage_account_ assert "Decryption failed." in str(e.exception) + @QueuePreparer() + def test_encryption_v2(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_algorithm='AES_GCM_256', + key_encryption_key=KeyWrapper('key1')) + queue = self._create_queue(qsc, 'v2-') + content = "Hello Crypto World!" + + # Act + queue.send_message(content) + message = queue.receive_message() + + self.assertEqual(content, message.content) + # ------------------------------------------------------------------------------ if __name__ == '__main__': From aa21c4ae2ccbdb17fa6c321ff523bdf5250303b9 Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Wed, 18 May 2022 15:15:02 -0700 Subject: [PATCH 02/13] Updates and tests --- .../azure/storage/queue/_message_encoding.py | 8 +- .../azure/storage/queue/_queue_client.py | 3 +- .../storage/queue/_queue_service_client.py | 2 +- .../storage/queue/_shared/base_client.py | 2 +- .../azure/storage/queue/_shared/encryption.py | 44 ++-- ...ion.test_get_message_encrypted_kek_v2.yaml | 129 +++++++++++ ...est_get_message_encrypted_resolver_v2.yaml | 129 +++++++++++ ...tion.test_update_encrypted_message_v2.yaml | 219 ++++++++++++++++++ .../tests/test_queue_encryption.py | 79 ++++++- 9 files changed, 582 insertions(+), 33 deletions(-) create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py index 1204b81c8edb..30fb79e14055 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py @@ -18,7 +18,7 @@ class MessageEncodePolicy(object): def __init__(self): self.require_encryption = False - self.encryption_algorithm = None + self.encryption_version = None self.key_encryption_key = None self.resolver = None @@ -26,12 +26,12 @@ def __call__(self, content): if content: content = self.encode(content) if self.key_encryption_key is not None: - content = encrypt_queue_message(content, self.key_encryption_key, self.encryption_algorithm) + content = encrypt_queue_message(content, self.key_encryption_key, self.encryption_version) return content - def configure(self, require_encryption, encryption_algorithm, key_encryption_key, resolver): + def configure(self, require_encryption, encryption_version, key_encryption_key, resolver): self.require_encryption = require_encryption - self.encryption_algorithm = encryption_algorithm + self.encryption_version = encryption_version self.key_encryption_key = key_encryption_key self.resolver = resolver if self.require_encryption and not self.key_encryption_key: diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py index 3adc5ee3e640..71968d035b89 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py @@ -479,7 +479,7 @@ def send_message( timeout = kwargs.pop('timeout', None) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, - encryption_algorithm=self.encryption_algorithm, + encryption_version=self.encryption_version, key_encryption_key=self.key_encryption_key, resolver=self.key_resolver_function) encoded_content = self._config.message_encode_policy(content) @@ -714,6 +714,7 @@ def update_message(self, if message_text is not None: self._config.message_encode_policy.configure( self.require_encryption, + self.encryption_version, self.key_encryption_key, self.key_resolver_function) encoded_message_text = self._config.message_encode_policy(message_text) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py index e68eec62f5db..e58b348c5e39 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_service_client.py @@ -433,6 +433,6 @@ def get_queue_client(self, return QueueClient( self.url, queue_name=queue_name, credential=self.credential, key_resolver_function=self.key_resolver_function, require_encryption=self.require_encryption, - encryption_algorithm=self.encryption_algorithm, key_encryption_key=self.key_encryption_key, + encryption_version=self.encryption_version, key_encryption_key=self.key_encryption_key, api_version=self.api_version, _pipeline=_pipeline, _configuration=self._config, _location_mode=self._location_mode, _hosts=self._hosts, **kwargs) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py index 45342d9cf5b2..fa50b1a0780e 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py @@ -104,7 +104,7 @@ def __init__( self._hosts = {LocationMode.PRIMARY: primary_hostname, LocationMode.SECONDARY: secondary_hostname} self.require_encryption = kwargs.get("require_encryption", False) - self.encryption_algorithm = kwargs.get("encryption_algorithm", "AES_CBC_256") + self.encryption_version = kwargs.get("encryption_version", "1.0") self.key_encryption_key = kwargs.get("key_encryption_key") self.key_resolver_function = kwargs.get("key_resolver_function") self._config, self._pipeline = self._create_pipeline(self.credential, storage_sdk=service, **kwargs) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index b2c627d0c23f..226e9ac74a47 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -167,14 +167,14 @@ def __init__( self.key_wrapping_metadata = key_wrapping_metadata -def _generate_encryption_data_dict(kek, cek, iv, algorithm): +def _generate_encryption_data_dict(kek, cek, iv, version): ''' Generates and returns the encryption metadata as a dict. :param object kek: The key encryption key. See calling functions for more information. :param bytes cek: The content encryption key. :param Optional[bytes] iv: The initialization vector. Only required for AES-CBC. - :param str algorithm: The client encryption algorithm used. + :param str version: The client encryption version used. :return: A dict containing all the encryption metadata. :rtype: dict ''' @@ -189,13 +189,13 @@ def _generate_encryption_data_dict(kek, cek, iv, algorithm): wrapped_content_key['Algorithm'] = kek.get_key_wrap_algorithm() encryption_agent = OrderedDict() - encryption_agent['EncryptionAlgorithm'] = algorithm + encryption_agent['Protocol'] = version - if algorithm == _EncryptionAlgorithm.AES_CBC_256: - encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V1 + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 - elif algorithm == _EncryptionAlgorithm.AES_GCM_256: - encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V2 + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 authentication_block_info = OrderedDict() authentication_block_info['CiphertextLength'] = _GCM_BLOCK_SIZE @@ -204,9 +204,9 @@ def _generate_encryption_data_dict(kek, cek, iv, algorithm): encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key encryption_data_dict['EncryptionAgent'] = encryption_agent - if algorithm == _EncryptionAlgorithm.AES_CBC_256: + if version == _ENCRYPTION_PROTOCOL_V1: encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) - elif algorithm == _EncryptionAlgorithm.AES_GCM_256: + elif version == _ENCRYPTION_PROTOCOL_V2: encryption_data_dict['AuthenticationBlockInfo'] = authentication_block_info encryption_data_dict['KeyWrappingMetadata'] = {'EncryptionLibrary': 'Python ' + VERSION} @@ -298,13 +298,13 @@ def _validate_and_unwrap_cek(encryption_data, key_encryption_key=None, key_resol _validate_not_none('encrypted_key', encryption_data.wrapped_content_key.encrypted_key) - # Validate we have the right info for the specified algorithm - if encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + # Validate we have the right info for the specified version + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) - elif encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: _validate_not_none('authentication_block_info', encryption_data.authentication_block_info) else: - raise ValueError('Specified encryption algorithm is not supported.') + raise ValueError('Specified encryption version is not supported.') content_encryption_key = None @@ -352,7 +352,7 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver _validate_not_none('message', message) content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, resolver) - if encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: if not encryption_data.content_encryption_IV: raise ValueError("Missing required metadata for decryption.") @@ -367,7 +367,7 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver unpadder = PKCS7(128).unpadder() decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) - elif encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: block_info = encryption_data.authentication_block_info if not block_info or not block_info.nonce_length: raise ValueError("Missing required metadata for decryption.") @@ -382,7 +382,7 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) else: - raise ValueError('Specified encryption algorithm is not supported.') + raise ValueError('Specified encryption version is not supported.') return decrypted_data @@ -544,7 +544,7 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): return encryptor, padder -def encrypt_queue_message(message, key_encryption_key, algorithm): +def encrypt_queue_message(message, key_encryption_key, version): ''' Encrypts the given plain text message using the given algorithm. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). @@ -557,7 +557,7 @@ def encrypt_queue_message(message, key_encryption_key, algorithm): wrap_key(key)--wraps the specified key using an algorithm of the user's choice. get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key. get_kid()--returns a string key id for this key-encryption-key. - :param str algorithm: The client encryption algorithm to use. + :param str version: The client encryption version to use. :return: A json-formatted string containing the encrypted message and the encryption metadata. :rtype: str ''' @@ -570,7 +570,7 @@ def encrypt_queue_message(message, key_encryption_key, algorithm): # operate on binary strings. message = message.encode('utf-8') - if algorithm == _EncryptionAlgorithm.AES_CBC_256: + if version == _ENCRYPTION_PROTOCOL_V1: # AES256 CBC uses 256 bit (32 byte) keys and always with 16 byte blocks content_encryption_key = os.urandom(32) initialization_vector = os.urandom(16) @@ -585,7 +585,7 @@ def encrypt_queue_message(message, key_encryption_key, algorithm): encryptor = cipher.encryptor() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() - elif algorithm == _EncryptionAlgorithm.AES_GCM_256: + elif version == _ENCRYPTION_PROTOCOL_V2: # AES256 GCM uses 256 bit (32 byte) keys and a 12 byte nonce. content_encryption_key = AESGCM.generate_key(bit_length=256) initialization_vector = None @@ -599,14 +599,14 @@ def encrypt_queue_message(message, key_encryption_key, algorithm): encrypted_data = nonce + cipertext_with_tag else: - raise ValueError("Invalid encryption algorithm.") + raise ValueError("Invalid encryption version specified.") # Build the dictionary structure. queue_message = {'EncryptedMessageContents': encode_base64(encrypted_data), 'EncryptionData': _generate_encryption_data_dict(key_encryption_key, content_encryption_key, initialization_vector, - algorithm)} + version)} return dumps(queue_message) diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml new file mode 100644 index 000000000000..9e1fa559a228 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml @@ -0,0 +1,129 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:06 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Wed, 18 May 2022 22:14:07 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: ' + + {"EncryptedMessageContents": "qxyi5OuH2yZcLOMAQtQ5EHpXMvpyVLL3oGh2Ek1Afuefv9k87b3xW5OLOcRDVEoQfkk=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "mbsZsJLjLGSrANshgPsWyjgpiqt/ntflTH46bKiqo54XBsmAfny9vA==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '572' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:07 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e/messages + response: + body: + string: "\uFEFFa08d898b-309c-4283-ac84-d7493a1f0c4fWed, + 18 May 2022 22:14:07 GMTWed, 25 May 2022 22:14:07 + GMTAgAAAAMAAAAAAAAAgVF+lwRr2AE=Wed, + 18 May 2022 22:14:07 GMT" + headers: + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:07 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:07 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e/messages?numofmessages=1 + response: + body: + string: "\uFEFFa08d898b-309c-4283-ac84-d7493a1f0c4fWed, + 18 May 2022 22:14:07 GMTWed, 25 May 2022 22:14:07 + GMTAgAAAAMAAAAAAAAAEbdpqQRr2AE=Wed, + 18 May 2022 22:14:37 GMT1{\"EncryptedMessageContents\": + \"qxyi5OuH2yZcLOMAQtQ5EHpXMvpyVLL3oGh2Ek1Afuefv9k87b3xW5OLOcRDVEoQfkk=\", + \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": + \"mbsZsJLjLGSrANshgPsWyjgpiqt/ntflTH46bKiqo54XBsmAfny9vA==\", \"Algorithm\": + \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, + \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python + 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:07 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml new file mode 100644 index 000000000000..c763b1edfd97 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml @@ -0,0 +1,129 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:13 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5 + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Wed, 18 May 2022 22:14:12 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: ' + + {"EncryptedMessageContents": "SeZehCQQttR4YAyRxXjJU7bewv6m+T2PLvpY/b6SYFzOEfJDb4xVSa/E1YQnld6qZuQ=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "2FaM3epFq1ByKyLO18FBwylh8gvl4Z6AVSlRKwwUXfQHReiXt12ffg==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '572' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:13 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5/messages + response: + body: + string: "\uFEFF88611993-c960-4826-b9b5-98e25f3523f9Wed, + 18 May 2022 22:14:13 GMTWed, 25 May 2022 22:14:13 + GMTAgAAAAMAAAAAAAAAVoFumwRr2AE=Wed, + 18 May 2022 22:14:13 GMT" + headers: + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:13 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:13 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5/messages?numofmessages=1 + response: + body: + string: "\uFEFF88611993-c960-4826-b9b5-98e25f3523f9Wed, + 18 May 2022 22:14:13 GMTWed, 25 May 2022 22:14:13 + GMTAgAAAAMAAAAAAAAAIqparQRr2AE=Wed, + 18 May 2022 22:14:43 GMT1{\"EncryptedMessageContents\": + \"SeZehCQQttR4YAyRxXjJU7bewv6m+T2PLvpY/b6SYFzOEfJDb4xVSa/E1YQnld6qZuQ=\", + \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": + \"2FaM3epFq1ByKyLO18FBwylh8gvl4Z6AVSlRKwwUXfQHReiXt12ffg==\", \"Algorithm\": + \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, + \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python + 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:13 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml new file mode 100644 index 000000000000..d2e98093c2fb --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml @@ -0,0 +1,219 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:34 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637 + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Wed, 18 May 2022 22:14:34 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: ' + + {"EncryptedMessageContents": "HSuqa05/iqhx16IyJDYhHnpakZ52aizKxevtN06XJ3uYgzP3vw==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "RUhlsk1+tW0cGtOBly1Q+8cVmeDzbIKnMZGZ8xJCEa1W6KD5qiPyvw==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '556' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:34 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages + response: + body: + string: "\uFEFF8dea69cf-45e9-45c3-b3f2-c416d9e177a0Wed, + 18 May 2022 22:14:34 GMTWed, 25 May 2022 22:14:34 + GMTAgAAAAMAAAAAAAAAkJDgpwRr2AE=Wed, + 18 May 2022 22:14:34 GMT" + headers: + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:34 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:34 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages?numofmessages=1 + response: + body: + string: "\uFEFF8dea69cf-45e9-45c3-b3f2-c416d9e177a0Wed, + 18 May 2022 22:14:34 GMTWed, 25 May 2022 22:14:34 + GMTAgAAAAMAAAAAAAAAeC7NuQRr2AE=Wed, + 18 May 2022 22:15:04 GMT1{\"EncryptedMessageContents\": + \"HSuqa05/iqhx16IyJDYhHnpakZ52aizKxevtN06XJ3uYgzP3vw==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"RUhlsk1+tW0cGtOBly1Q+8cVmeDzbIKnMZGZ8xJCEa1W6KD5qiPyvw==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, + \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python + 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:34 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +- request: + body: ' + + {"EncryptedMessageContents": "u1O+0236fUl1y+ddHZjI93uAX3k2tuExQw3crQFUnGPrpAw=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "Z6sFMumKNFwpbuIsCQyiHFqpglMNlxa0ogJgtO43kvq14/g/fawVMA==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '552' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:34 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages/8dea69cf-45e9-45c3-b3f2-c416d9e177a0?popreceipt=AgAAAAMAAAAAAAAAeC7NuQRr2AE%3D&visibilitytimeout=0 + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Wed, 18 May 2022 22:14:34 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-popreceipt: + - AwAAAAMAAAAAAAAA9Kj4pwRr2AEBAAAA + x-ms-time-next-visible: + - Wed, 18 May 2022 22:14:34 GMT + x-ms-version: + - '2021-02-12' + status: + code: 204 + message: No Content +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 22:14:34 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages?numofmessages=1 + response: + body: + string: "\uFEFF8dea69cf-45e9-45c3-b3f2-c416d9e177a0Wed, + 18 May 2022 22:14:34 GMTWed, 25 May 2022 22:14:34 + GMTAgAAAAMAAAAAAAAAFzHmuQRr2AE=Wed, + 18 May 2022 22:15:05 GMT2{\"EncryptedMessageContents\": + \"u1O+0236fUl1y+ddHZjI93uAX3k2tuExQw3crQFUnGPrpAw=\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"Z6sFMumKNFwpbuIsCQyiHFqpglMNlxa0ogJgtO43kvq14/g/fawVMA==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, + \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python + 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Wed, 18 May 2022 22:14:34 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index a055b5e40c1c..1c2b2ad9a059 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -476,23 +476,94 @@ def test_encryption_nonmatching_kid(self, storage_account_name, storage_account_ assert "Decryption failed." in str(e.exception) @QueuePreparer() - def test_encryption_v2(self, storage_account_name, storage_account_key): + def test_get_message_encrypted_kek_v2(self, storage_account_name, storage_account_key): # Arrange qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, requires_encryption=True, - encryption_algorithm='AES_GCM_256', + encryption_version='2.0', key_encryption_key=KeyWrapper('key1')) - queue = self._create_queue(qsc, 'v2-') - content = "Hello Crypto World!" + queue = self._create_queue(qsc) + content = 'Hello World Encrypted!' + + # Act + queue.send_message(content) + message = queue.receive_message() + + # Assert + self.assertEqual(content, message.content) + + @QueuePreparer() + def test_get_message_encrypted_resolver_v2(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) + key_resolver = KeyResolver() + key_resolver.put_key(qsc.key_encryption_key) + + queue = self._create_queue(qsc) + content = 'Hello World Encrypted!' # Act queue.send_message(content) + queue.key_resolver_function = key_resolver.resolve_key + queue.key_encryption_key = None # Ensure that the resolver is used + message = queue.receive_message() + # Assert self.assertEqual(content, message.content) + @pytest.mark.live_test_only + @QueuePreparer() + def test_get_message_encrypted_kek_RSA_v2(self, storage_account_name, storage_account_key): + # We can only generate random RSA keys, so this must be run live or + # the playback test will fail due to a change in kek values. + + # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=RSAKeyWrapper('key2')) + queue = self._create_queue(qsc) + content = 'Hello World Encrypted!' + + # Act + queue.send_message(content) + message = queue.receive_message() + + # Assert + self.assertEqual(content, message.content) + + @QueuePreparer() + def test_update_encrypted_message_v2(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) + queue = self._create_queue(qsc) + queue.send_message('Update Me') + + message = queue.receive_message() + message.content = 'Updated' + + # Act + queue.update_message(message) + message = queue.receive_message() + + # Assert + self.assertEqual('Updated', message.content) + # ------------------------------------------------------------------------------ if __name__ == '__main__': From 8956ad9531714f7509f86eb0d00119f6d3a89ac1 Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Wed, 18 May 2022 17:23:05 -0700 Subject: [PATCH 03/13] Update metadat, add manual decrypt test --- .../azure/storage/queue/_shared/encryption.py | 58 ++++---- ...ncryption.test_validate_encryption_v2.yaml | 130 ++++++++++++++++++ .../tests/test_queue_encryption.py | 85 +++++++++++- 3 files changed, 245 insertions(+), 28 deletions(-) create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index 226e9ac74a47..048426ccecf2 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -27,8 +27,10 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' _ENCRYPTION_PROTOCOL_V2 = '2.0' -_GCM_BLOCK_SIZE = 4 * 1024 * 1024 +_GCM_REGION_LENGTH = 4 * 1024 * 1024 _GCM_NONCE_LENGTH = 12 +_GCM_TAG_LENGTH = 16 + _ERROR_OBJECT_INVALID = \ '{0} does not define a complete interface. Value of {1} is either missing or invalid.' @@ -80,24 +82,28 @@ def __init__(self, algorithm, encrypted_key, key_id): self.key_id = key_id -class _AuthenticationBlockInfo: +class _EncryptedRegionInfo: ''' Represents the length of encryption elements. - This is only used for AES-GCM. + This is only used for Encryption V2. ''' - def __init__(self, ciphertext_length, nonce_length): + def __init__(self, encrypted_region_data_length, nonce_length, tag_length): ''' - :param int ciphertext_length: - The length of the ciphertext block. + :param int encrypted_region_data_length: + The length of the encryption region data (not including nonce + tag). :param str nonce_length: The length of nonce used when encrypting. + :param int tag_length: + The length of the encryption tag. ''' - _validate_not_none('ciphertext_length', ciphertext_length) + _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) _validate_not_none('nonce_length', nonce_length) + _validate_not_none('tag_length', tag_length) - self.ciphertext_length = ciphertext_length + self.encrypted_region_data_length = encrypted_region_data_length self.nonce_length = nonce_length + self.tag_length = tag_length class _EncryptionAgent: @@ -129,7 +135,7 @@ class _EncryptionData: def __init__( self, content_encryption_IV, - authentication_block_info, + encrypted_region_info, encryption_agent, wrapped_content_key, key_wrapping_metadata): @@ -137,7 +143,7 @@ def __init__( :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. Required for AES-CBC. - :param Optional[_AuthenticationBlockInfo] authentication_block_info: + :param Optional[_EncryptedRegionInfo] encrypted_region_info: The info about the autenticated block sizes. Required for AES-GCM. :param _EncryptionAgent encryption_agent: @@ -156,12 +162,12 @@ def __init__( if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: _validate_not_none('content_encryption_IV', content_encryption_IV) elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: - _validate_not_none('authentication_block_info', authentication_block_info) + _validate_not_none('encrypted_region_info', encrypted_region_info) else: raise ValueError("Invalid encryption algorithm.") self.content_encryption_IV = content_encryption_IV - self.authentication_block_info = authentication_block_info + self.encrypted_region_info = encrypted_region_info self.encryption_agent = encryption_agent self.wrapped_content_key = wrapped_content_key self.key_wrapping_metadata = key_wrapping_metadata @@ -197,9 +203,10 @@ def _generate_encryption_data_dict(kek, cek, iv, version): elif version == _ENCRYPTION_PROTOCOL_V2: encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 - authentication_block_info = OrderedDict() - authentication_block_info['CiphertextLength'] = _GCM_BLOCK_SIZE - authentication_block_info['NonceLength'] = _GCM_NONCE_LENGTH + encrypted_region_info = OrderedDict() + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH + encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key @@ -207,7 +214,7 @@ def _generate_encryption_data_dict(kek, cek, iv, version): if version == _ENCRYPTION_PROTOCOL_V1: encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) elif version == _ENCRYPTION_PROTOCOL_V2: - encryption_data_dict['AuthenticationBlockInfo'] = authentication_block_info + encryption_data_dict['EncryptedRegionInfo'] = encrypted_region_info encryption_data_dict['KeyWrappingMetadata'] = {'EncryptionLibrary': 'Python ' + VERSION} return encryption_data_dict @@ -249,14 +256,15 @@ def _dict_to_encryption_data(encryption_data_dict): encryption_iv = decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']) # AES-GCM only - block_info = None - if 'AuthenticationBlockInfo' in encryption_data_dict: - authentication_block_info = encryption_data_dict['AuthenticationBlockInfo'] - block_info = _AuthenticationBlockInfo(authentication_block_info['CiphertextLength'], - authentication_block_info['NonceLength']) + region_info = None + if 'EncryptedRegionInfo' in encryption_data_dict: + encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] + region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['NonceLength'], + encrypted_region_info['TagLength']) encryption_data = _EncryptionData(encryption_iv, - block_info, + region_info, encryption_agent, wrapped_content_key, key_wrapping_metadata) @@ -302,7 +310,7 @@ def _validate_and_unwrap_cek(encryption_data, key_encryption_key=None, key_resol if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: - _validate_not_none('authentication_block_info', encryption_data.authentication_block_info) + _validate_not_none('encrypted_region_info', encryption_data.encrypted_region_info) else: raise ValueError('Specified encryption version is not supported.') @@ -368,11 +376,11 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: - block_info = encryption_data.authentication_block_info + block_info = encryption_data.encrypted_region_info if not block_info or not block_info.nonce_length: raise ValueError("Missing required metadata for decryption.") - nonce_length = encryption_data.authentication_block_info.nonce_length + nonce_length = encryption_data.encrypted_region_info.nonce_length # First bytes are the nonce nonce = message[:nonce_length] diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml new file mode 100644 index 000000000000..965c0e1f3b48 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml @@ -0,0 +1,130 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 23:32:00 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueueff191437 + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Wed, 18 May 2022 23:32:00 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: ' + + {"EncryptedMessageContents": "LZMk+/EnPnROVSdHRPKIfP4vPjdPdfCljG1jnsnPuckgji4b3g2ud3JK/SWd/snwG7k=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "kAeH26jizVN0Y+WwuhSs/6UejUuJCqa5lFSq4KxtJFTrp2mRw9L8og==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '594' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 23:32:00 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueueff191437/messages + response: + body: + string: "\uFEFFc9557b24-f3cc-4d72-b4d7-d83b8e895c99Wed, + 18 May 2022 23:32:00 GMTWed, 25 May 2022 23:32:00 + GMTAgAAAAMAAAAAAAAAOE4weQ9r2AE=Wed, + 18 May 2022 23:32:00 GMT" + headers: + content-type: + - application/xml + date: + - Wed, 18 May 2022 23:32:00 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Wed, 18 May 2022 23:32:00 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueueff191437/messages?numofmessages=1 + response: + body: + string: "\uFEFFc9557b24-f3cc-4d72-b4d7-d83b8e895c99Wed, + 18 May 2022 23:32:00 GMTWed, 25 May 2022 23:32:00 + GMTAgAAAAMAAAAAAAAAVa8diw9r2AE=Wed, + 18 May 2022 23:32:31 GMT1{\"EncryptedMessageContents\": + \"LZMk+/EnPnROVSdHRPKIfP4vPjdPdfCljG1jnsnPuckgji4b3g2ud3JK/SWd/snwG7k=\", + \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": + \"kAeH26jizVN0Y+WwuhSs/6UejUuJCqa5lFSq4KxtJFTrp2mRw9L8og==\", \"Algorithm\": + \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Wed, 18 May 2022 23:32:00 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index 1c2b2ad9a059..f11255fcdafe 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -16,6 +16,7 @@ from cryptography.hazmat import backends from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.padding import PKCS7 @@ -23,9 +24,14 @@ from azure.storage.queue._shared import decode_base64_to_bytes from azure.storage.queue._shared.encryption import ( _ERROR_OBJECT_INVALID, - _WrappedContentKey, + _GCM_REGION_LENGTH, + _GCM_NONCE_LENGTH, + _GCM_TAG_LENGTH, + _EncryptedRegionInfo, _EncryptionAgent, + _EncryptionAlgorithm, _EncryptionData, + _WrappedContentKey, ) from azure.storage.queue import ( @@ -45,8 +51,6 @@ # ------------------------------------------------------------------------------ TEST_QUEUE_PREFIX = 'encryptionqueue' - - # ------------------------------------------------------------------------------ def _decode_base64_to_bytes(data): @@ -382,6 +386,7 @@ def test_validate_encryption(self, storage_account_name, storage_account_key): encryption_data = _EncryptionData( b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), + None, encryption_agent, wrapped_content_key, {'EncryptionLibrary': VERSION}) @@ -564,6 +569,80 @@ def test_update_encrypted_message_v2(self, storage_account_name, storage_account # Assert self.assertEqual('Updated', message.content) + @QueuePreparer() + def test_validate_encryption_v2(self, storage_account_name, storage_account_key): + # Arrange + kek = KeyWrapper('key1') + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=kek) + queue = self._create_queue(qsc) + content = 'Hello World Encrypted!' + queue.send_message(content) + + # Act + queue.requires_encryption = False + queue.key_encryption_key = None # Message will not be decrypted + message = queue.receive_message().content + message = loads(message) + + encryption_data = message['EncryptionData'] + self.assertIsNotNone(encryption_data) + + wrapped_content_key = encryption_data['WrappedContentKey'] + wrapped_content_key = _WrappedContentKey( + wrapped_content_key['Algorithm'], + b64decode(wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), + wrapped_content_key['KeyId']) + self.assertEqual(kek.get_key_wrap_algorithm(), wrapped_content_key.algorithm) + self.assertEqual(kek.get_kid(), wrapped_content_key.key_id) + + encryption_agent = encryption_data['EncryptionAgent'] + encryption_agent = _EncryptionAgent( + encryption_agent['EncryptionAlgorithm'], + encryption_agent['Protocol']) + self.assertEqual(_EncryptionAlgorithm.AES_GCM_256, encryption_agent.encryption_algorithm) + self.assertEqual('2.0', encryption_agent.protocol) + + encrypted_region_info = encryption_data['EncryptedRegionInfo'] + encrypted_region_info = _EncryptedRegionInfo( + encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['NonceLength'], + encrypted_region_info['TagLength']) + self.assertEqual(_GCM_REGION_LENGTH, encrypted_region_info.encrypted_region_data_length) + self.assertEqual(_GCM_NONCE_LENGTH, encrypted_region_info.nonce_length) + self.assertEqual(_GCM_TAG_LENGTH, encrypted_region_info.tag_length) + + encryption_data = _EncryptionData( + None, + encrypted_region_info, + encryption_agent, + wrapped_content_key, + {'EncryptionLibrary': VERSION}) + + message = message['EncryptedMessageContents'] + message = decode_base64_to_bytes(message) + content_encryption_key = kek.unwrap_key( + encryption_data.wrapped_content_key.encrypted_key, + encryption_data.wrapped_content_key.algorithm) + + nonce_length = encryption_data.encrypted_region_info.nonce_length + + # First bytes are the nonce + nonce = message[:nonce_length] + ciphertext_with_tag = message[nonce_length:] + + aesgcm = AESGCM(content_encryption_key) + decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) + + decrypted_data = decrypted_data.decode(encoding='utf-8') + + # Assert + self.assertEqual(content, decrypted_data) + # ------------------------------------------------------------------------------ if __name__ == '__main__': From 421a7de06fb1381d6d0a9c24cfc65f94e204fb2c Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Wed, 18 May 2022 18:10:00 -0700 Subject: [PATCH 04/13] Add async support --- .../storage/queue/aio/_queue_client_async.py | 12 +- .../queue/aio/_queue_service_client_async.py | 6 +- ...ync.test_get_message_encrypted_kek_v2.yaml | 104 +++ ...est_get_message_encrypted_resolver_v2.yaml | 104 +++ ...sync.test_update_encrypted_message_v2.yaml | 177 ++++ ...ion_async.test_validate_encryption_v2.yaml | 104 +++ .../tests/test_queue_encryption_async.py | 881 +++++++++++------- 7 files changed, 1024 insertions(+), 364 deletions(-) create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py index fffd153325b3..d48274f86e1a 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py @@ -19,12 +19,6 @@ TYPE_CHECKING, ) -try: - from urllib.parse import urlparse, quote, unquote # pylint: disable=unused-import -except ImportError: - from urlparse import urlparse # type: ignore - from urllib2 import quote, unquote # type: ignore - from azure.core.exceptions import HttpResponseError from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async @@ -379,6 +373,7 @@ async def send_message( # type: ignore timeout = kwargs.pop('timeout', None) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, + encryption_version=self.encryption_version, key_encryption_key=self.key_encryption_key, resolver=self.key_resolver_function ) @@ -607,7 +602,10 @@ async def update_message( raise ValueError("pop_receipt must be present") if message_text is not None: self._config.message_encode_policy.configure( - self.require_encryption, self.key_encryption_key, self.key_resolver_function + self.require_encryption, + self.encryption_version, + self.key_encryption_key, + self.key_resolver_function ) encoded_message_text = self._config.message_encode_policy(message_text) updated = GenQueueMessage(message_text=encoded_message_text) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_service_client_async.py b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_service_client_async.py index 3b84577bfcd0..f286504c83aa 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_service_client_async.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_service_client_async.py @@ -382,6 +382,6 @@ def get_queue_client(self, queue, **kwargs): return QueueClient( self.url, queue_name=queue_name, credential=self.credential, key_resolver_function=self.key_resolver_function, require_encryption=self.require_encryption, - key_encryption_key=self.key_encryption_key, api_version=self.api_version, _pipeline=_pipeline, - _configuration=self._config, _location_mode=self._location_mode, - _hosts=self._hosts, loop=self._loop, **kwargs) + encryption_version=self.encryption_version, key_encryption_key=self.key_encryption_key, + api_version=self.api_version, _pipeline=_pipeline, _configuration=self._config, + _location_mode=self._location_mode, _hosts=self._hosts, **kwargs) diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml new file mode 100644 index 000000000000..6364da44de25 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml @@ -0,0 +1,104 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:19 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue1399190b + response: + body: + string: '' + headers: + content-length: '0' + date: Thu, 19 May 2022 01:00:19 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue1399190b +- request: + body: ' + + {"EncryptedMessageContents": "uLBuNGG6qQEuOIJd3wntSh6/nzcGiwPlPhNDUu6jJagbdtiecLc0M0d5j0hq93EbPJM=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "gCtdxVuhFGW6SKuoCxR/UClrH3EHgvilAClPfhLQ/pm+eV0uvJXXCA==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '594' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueue1399190b/messages + response: + body: + string: "\uFEFF80ea2ce8-be91-4d48-981b-aa0be666c325Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAA/ePCzxtr2AE=Thu, + 19 May 2022 01:00:20 GMT" + headers: + content-type: application/xml + date: Thu, 19 May 2022 01:00:19 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue1399190b/messages +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue1399190b/messages?numofmessages=1 + response: + body: + string: "\uFEFF80ea2ce8-be91-4d48-981b-aa0be666c325Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAA69ir4Rtr2AE=Thu, + 19 May 2022 01:00:50 GMT1{\"EncryptedMessageContents\": + \"uLBuNGG6qQEuOIJd3wntSh6/nzcGiwPlPhNDUu6jJagbdtiecLc0M0d5j0hq93EbPJM=\", + \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": + \"gCtdxVuhFGW6SKuoCxR/UClrH3EHgvilAClPfhLQ/pm+eV0uvJXXCA==\", \"Algorithm\": + \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Thu, 19 May 2022 01:00:19 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue1399190b/messages?numofmessages=1 +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml new file mode 100644 index 000000000000..6d92afc11355 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml @@ -0,0 +1,104 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue99331b42 + response: + body: + string: '' + headers: + content-length: '0' + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue99331b42 +- request: + body: ' + + {"EncryptedMessageContents": "V4LMKSSg3MaHErdJ7D5C6FrO+cMJRpD4B3cN98AHvcx1e8IPgDXbvAyM7lfsy1tYDeI=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "nGBJ1BtjaTN+gfv0FZR4jjiC4BhWb6+L+QJqsExaczQqUZPP/sqPzg==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '594' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueue99331b42/messages + response: + body: + string: "\uFEFF3541ef37-698b-4c51-8fc1-d35df0d0dca4Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAAhyH2zxtr2AE=Thu, + 19 May 2022 01:00:20 GMT" + headers: + content-type: application/xml + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue99331b42/messages +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue99331b42/messages?numofmessages=1 + response: + body: + string: "\uFEFF3541ef37-698b-4c51-8fc1-d35df0d0dca4Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAAhT3f4Rtr2AE=Thu, + 19 May 2022 01:00:50 GMT1{\"EncryptedMessageContents\": + \"V4LMKSSg3MaHErdJ7D5C6FrO+cMJRpD4B3cN98AHvcx1e8IPgDXbvAyM7lfsy1tYDeI=\", + \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": + \"nGBJ1BtjaTN+gfv0FZR4jjiC4BhWb6+L+QJqsExaczQqUZPP/sqPzg==\", \"Algorithm\": + \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue99331b42/messages?numofmessages=1 +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml new file mode 100644 index 000000000000..362ce8b103cd --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml @@ -0,0 +1,177 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4 + response: + body: + string: '' + headers: + content-length: '0' + date: Thu, 19 May 2022 01:00:19 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4 +- request: + body: ' + + {"EncryptedMessageContents": "PFeC6fjF8gaPXMUB70Z3HslvgPB7q+3L1qjOd4Va4HrqgODwAw==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "cNmXaFo4CCk5AjXzm4evZke/4eSiAwl0Hbit9CCz4ghuFP0HeYLmFg==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '578' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages + response: + body: + string: "\uFEFF76b3b8c2-7ad2-46e6-ac93-48f1c1446e69Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAAwCYo0Btr2AE=Thu, + 19 May 2022 01:00:20 GMT" + headers: + content-type: application/xml + date: Thu, 19 May 2022 01:00:19 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4/messages +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages?numofmessages=1 + response: + body: + string: "\uFEFF76b3b8c2-7ad2-46e6-ac93-48f1c1446e69Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAA7H4Z4htr2AE=Thu, + 19 May 2022 01:00:50 GMT1{\"EncryptedMessageContents\": + \"PFeC6fjF8gaPXMUB70Z3HslvgPB7q+3L1qjOd4Va4HrqgODwAw==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"cNmXaFo4CCk5AjXzm4evZke/4eSiAwl0Hbit9CCz4ghuFP0HeYLmFg==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4/messages?numofmessages=1 +- request: + body: ' + + {"EncryptedMessageContents": "eVsLrQTkmmx3/KVv0KIqEXSaX6vbQTcN+YNWgeTWIJpS81A=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "2BO5GkR7F3fG80brOOeOwxh/lo02EnwfISlAMmeLNkkZ2at2twvzaQ==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '574' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages/76b3b8c2-7ad2-46e6-ac93-48f1c1446e69?popreceipt=AgAAAAMAAAAAAAAA7H4Z4htr2AE%3D&visibilitytimeout=0 + response: + body: + string: '' + headers: + content-length: '0' + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-popreceipt: AwAAAAMAAAAAAAAAS9tA0Btr2AEBAAAA + x-ms-time-next-visible: Thu, 19 May 2022 01:00:20 GMT + x-ms-version: '2021-02-12' + status: + code: 204 + message: No Content + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4/messages/76b3b8c2-7ad2-46e6-ac93-48f1c1446e69?popreceipt=AgAAAAMAAAAAAAAA7H4Z4htr2AE%3D&visibilitytimeout=0 +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:20 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages?numofmessages=1 + response: + body: + string: "\uFEFF76b3b8c2-7ad2-46e6-ac93-48f1c1446e69Thu, + 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 + GMTAgAAAAMAAAAAAAAAcJMq4htr2AE=Thu, + 19 May 2022 01:00:51 GMT2{\"EncryptedMessageContents\": + \"eVsLrQTkmmx3/KVv0KIqEXSaX6vbQTcN+YNWgeTWIJpS81A=\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"2BO5GkR7F3fG80brOOeOwxh/lo02EnwfISlAMmeLNkkZ2at2twvzaQ==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4/messages?numofmessages=1 +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml new file mode 100644 index 000000000000..dbd7b4993f47 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml @@ -0,0 +1,104 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:21 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue830316b4 + response: + body: + string: '' + headers: + content-length: '0' + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue830316b4 +- request: + body: ' + + {"EncryptedMessageContents": "T/cvNkyRHKCiO8pH54fAQefSktJFh8vM9w5ji5D5GG3KMOZkLHDB7rp7rCe3AmkFg94=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "inxs+p2MHYWDKKw+3BmYh1DMSGvI4+lB81rxomHLPvJysqmpiu1g8w==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '594' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:21 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueue830316b4/messages + response: + body: + string: "\uFEFF302a481a-775b-48df-819c-8841d1ca1f3dThu, + 19 May 2022 01:00:21 GMTThu, 26 May 2022 01:00:21 + GMTAgAAAAMAAAAAAAAAplVz0Btr2AE=Thu, + 19 May 2022 01:00:21 GMT" + headers: + content-type: application/xml + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue830316b4/messages +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Thu, 19 May 2022 01:00:21 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue830316b4/messages?numofmessages=1 + response: + body: + string: "\uFEFF302a481a-775b-48df-819c-8841d1ca1f3dThu, + 19 May 2022 01:00:21 GMTThu, 26 May 2022 01:00:21 + GMTAgAAAAMAAAAAAAAAtL9c4htr2AE=Thu, + 19 May 2022 01:00:51 GMT1{\"EncryptedMessageContents\": + \"T/cvNkyRHKCiO8pH54fAQefSktJFh8vM9w5ji5D5GG3KMOZkLHDB7rp7rCe3AmkFg94=\", + \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": + \"inxs+p2MHYWDKKw+3BmYh1DMSGvI4+lB81rxomHLPvJysqmpiu1g8w==\", \"Algorithm\": + \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Thu, 19 May 2022 01:00:20 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueue830316b4/messages?numofmessages=1 +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py index 94d8c2d2c0b3..8813deda1493 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py @@ -17,6 +17,7 @@ from cryptography.hazmat import backends from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.padding import PKCS7 @@ -26,9 +27,14 @@ from multidict import CIMultiDict, CIMultiDictProxy from azure.storage.queue._shared.encryption import ( _ERROR_OBJECT_INVALID, - _WrappedContentKey, + _GCM_REGION_LENGTH, + _GCM_NONCE_LENGTH, + _GCM_TAG_LENGTH, + _EncryptedRegionInfo, _EncryptionAgent, + _EncryptionAlgorithm, _EncryptionData, + _WrappedContentKey, ) from azure.core.pipeline.transport import AioHttpTransport from azure.storage.queue import ( @@ -52,7 +58,6 @@ # ------------------------------------------------------------------------------ TEST_QUEUE_PREFIX = 'encryptionqueue' - # ------------------------------------------------------------------------------ def _decode_base64_to_bytes(data): @@ -86,443 +91,611 @@ async def _create_queue(self, qsc, prefix=TEST_QUEUE_PREFIX, **kwargs): pass return queue # -------------------------------------------------------------------------- + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_get_messages_encrypted_kek(self, storage_account_name, storage_account_key): + # # Arrange + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # qsc.key_encryption_key = KeyWrapper('key1') + # queue = await self._create_queue(qsc) + # await queue.send_message(u'encrypted_message_2') + + # # Act + # li = None + # async for m in queue.receive_messages(): + # li = m + + # # Assert + # self.assertEqual(li.content, u'encrypted_message_2') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_get_messages_encrypted_resolver(self, storage_account_name, storage_account_key): + # # Arrange + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # qsc.key_encryption_key = KeyWrapper('key1') + # queue = await self._create_queue(qsc) + # await queue.send_message(u'encrypted_message_2') + # key_resolver = KeyResolver() + # key_resolver.put_key(qsc.key_encryption_key) + # queue.key_resolver_function = key_resolver.resolve_key + # queue.key_encryption_key = None # Ensure that the resolver is used + + # # Act + # li = None + # async for m in queue.receive_messages(): + # li = m + + # # Assert + # self.assertEqual(li.content, u'encrypted_message_2') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_peek_messages_encrypted_kek(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # qsc.key_encryption_key = KeyWrapper('key1') + # queue = await self._create_queue(qsc) + # await queue.send_message(u'encrypted_message_3') + + # # Act + # li = await queue.peek_messages() + + # # Assert + # self.assertEqual(li[0].content, u'encrypted_message_3') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_peek_messages_encrypted_resolver(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # qsc.key_encryption_key = KeyWrapper('key1') + # queue = await self._create_queue(qsc) + # await queue.send_message(u'encrypted_message_4') + # key_resolver = KeyResolver() + # key_resolver.put_key(qsc.key_encryption_key) + # queue.key_resolver_function = key_resolver.resolve_key + # queue.key_encryption_key = None # Ensure that the resolver is used + + # # Act + # li = await queue.peek_messages() + + # # Assert + # self.assertEqual(li[0].content, u'encrypted_message_4') + + # @pytest.mark.live_test_only + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_peek_messages_encrypted_kek_RSA(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # We can only generate random RSA keys, so this must be run live or + # # the playback test will fail due to a change in kek values. + + # # Arrange + # qsc.key_encryption_key = RSAKeyWrapper('key2') + # queue = await self._create_queue(qsc) + # await queue.send_message(u'encrypted_message_3') + + # # Act + # li = await queue.peek_messages() + + # # Assert + # self.assertEqual(li[0].content, u'encrypted_message_3') + + # @pytest.mark.live_test_only + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_update_encrypted_message(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # TODO: Recording doesn't work + # # Arrange + # queue = await self._create_queue(qsc) + # queue.key_encryption_key = KeyWrapper('key1') + # await queue.send_message(u'Update Me') + + # messages = [] + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result1 = messages[0] + # list_result1.content = u'Updated' + + # # Act + # message = await queue.update_message(list_result1) + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result2 = messages[0] + + # # Assert + # self.assertEqual(u'Updated', list_result2.content) + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_update_encrypted_binary_message(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc, message_encode_policy=BinaryBase64EncodePolicy(), message_decode_policy=BinaryBase64DecodePolicy()) + # queue.key_encryption_key = KeyWrapper('key1') + + # binary_message = self.get_random_bytes(100) + # await queue.send_message(binary_message) + # messages = [] + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result1 = messages[0] + + # # Act + # binary_message = self.get_random_bytes(100) + # list_result1.content = binary_message + # await queue.update_message(list_result1) + + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result2 = messages[0] + + # # Assert + # self.assertEqual(binary_message, list_result2.content) + + # @pytest.mark.live_test_only + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_update_encrypted_raw_text_message(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # TODO: Recording doesn't work + # # Arrange + # queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) + # queue.key_encryption_key = KeyWrapper('key1') + + # raw_text = u'Update Me' + # await queue.send_message(raw_text) + # messages = [] + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result1 = messages[0] + + # # Act + # raw_text = u'Updated' + # list_result1.content = raw_text + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result2 = messages[0] + + # # Assert + # self.assertEqual(raw_text, list_result2.content) + + # @pytest.mark.live_test_only + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_update_encrypted_json_message(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # TODO: Recording doesn't work + # # Arrange + # queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) + # queue.key_encryption_key = KeyWrapper('key1') + + # message_dict = {'val1': 1, 'val2': '2'} + # json_text = dumps(message_dict) + # await queue.send_message(json_text) + # messages = [] + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result1 = messages[0] + + # # Act + # message_dict['val1'] = 0 + # message_dict['val2'] = 'updated' + # json_text = dumps(message_dict) + # list_result1.content = json_text + # await queue.update_message(list_result1) + + # async for m in queue.receive_messages(): + # messages.append(m) + # list_result2 = messages[0] + + # # Assert + # self.assertEqual(message_dict, loads(list_result2.content)) + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_invalid_value_kek_wrap(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # queue.key_encryption_key = KeyWrapper('key1') + # queue.key_encryption_key.get_kid = None + + # with self.assertRaises(AttributeError) as e: + # await queue.send_message(u'message') + + # self.assertEqual(str(e.exception), _ERROR_OBJECT_INVALID.format('key encryption key', 'get_kid')) + + # queue.key_encryption_key = KeyWrapper('key1') + # queue.key_encryption_key.get_kid = None + # with self.assertRaises(AttributeError): + # await queue.send_message(u'message') + + # queue.key_encryption_key = KeyWrapper('key1') + # queue.key_encryption_key.wrap_key = None + # with self.assertRaises(AttributeError): + # await queue.send_message(u'message') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_missing_attribute_kek_wrap(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + + # valid_key = KeyWrapper('key1') + + # # Act + # invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object + # invalid_key_1.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm + # invalid_key_1.get_kid = valid_key.get_kid + # # No attribute wrap_key + # queue.key_encryption_key = invalid_key_1 + # with self.assertRaises(AttributeError): + # await queue.send_message(u'message') + + # invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object + # invalid_key_2.wrap_key = valid_key.wrap_key + # invalid_key_2.get_kid = valid_key.get_kid + # # No attribute get_key_wrap_algorithm + # queue.key_encryption_key = invalid_key_2 + # with self.assertRaises(AttributeError): + # await queue.send_message(u'message') + + # invalid_key_3 = lambda: None # functions are objects, so this effectively creates an empty object + # invalid_key_3.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm + # invalid_key_3.wrap_key = valid_key.wrap_key + # # No attribute get_kid + # queue.key_encryption_key = invalid_key_3 + # with self.assertRaises(AttributeError): + # await queue.send_message(u'message') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_invalid_value_kek_unwrap(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # queue.key_encryption_key = KeyWrapper('key1') + # await queue.send_message(u'message') + + # # Act + # queue.key_encryption_key.unwrap_key = None + # with self.assertRaises(HttpResponseError): + # await queue.peek_messages() + + # queue.key_encryption_key.get_kid = None + # with self.assertRaises(HttpResponseError): + # await queue.peek_messages() + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_missing_attribute_kek_unrwap(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # queue.key_encryption_key = KeyWrapper('key1') + # await queue.send_message(u'message') + + # # Act + # valid_key = KeyWrapper('key1') + # invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object + # invalid_key_1.unwrap_key = valid_key.unwrap_key + # # No attribute get_kid + # queue.key_encryption_key = invalid_key_1 + # with self.assertRaises(HttpResponseError) as e: + # await queue.peek_messages() + + # assert "Decryption failed." in str(e.exception) + + # invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object + # invalid_key_2.get_kid = valid_key.get_kid + # # No attribute unwrap_key + # queue.key_encryption_key = invalid_key_2 + # with self.assertRaises(HttpResponseError): + # await queue.peek_messages() + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_validate_encryption(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # kek = KeyWrapper('key1') + # queue.key_encryption_key = kek + # await queue.send_message(u'message') + + # # Act + # queue.key_encryption_key = None # Message will not be decrypted + # li = await queue.peek_messages() + # message = li[0].content + # message = loads(message) + + # encryption_data = message['EncryptionData'] + + # wrapped_content_key = encryption_data['WrappedContentKey'] + # wrapped_content_key = _WrappedContentKey( + # wrapped_content_key['Algorithm'], + # b64decode(wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), + # wrapped_content_key['KeyId']) + + # encryption_agent = encryption_data['EncryptionAgent'] + # encryption_agent = _EncryptionAgent( + # encryption_agent['EncryptionAlgorithm'], + # encryption_agent['Protocol']) + + # encryption_data = _EncryptionData( + # b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), + # encryption_agent, + # wrapped_content_key, + # {'EncryptionLibrary': VERSION}) + + # message = message['EncryptedMessageContents'] + # content_encryption_key = kek.unwrap_key( + # encryption_data.wrapped_content_key.encrypted_key, + # encryption_data.wrapped_content_key.algorithm) + + # # Create decryption cipher + # backend = backends.default_backend() + # algorithm = AES(content_encryption_key) + # mode = CBC(encryption_data.content_encryption_IV) + # cipher = Cipher(algorithm, mode, backend) + + # # decode and decrypt data + # decrypted_data = _decode_base64_to_bytes(message) + # decryptor = cipher.decryptor() + # decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + + # # unpad data + # unpadder = PKCS7(128).unpadder() + # decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + + # decrypted_data = decrypted_data.decode(encoding='utf-8') + + # # Assert + # self.assertEqual(decrypted_data, u'message') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_put_with_strict_mode(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # kek = KeyWrapper('key1') + # queue.key_encryption_key = kek + # queue.require_encryption = True + + # await queue.send_message(u'message') + # queue.key_encryption_key = None + + # # Assert + # with self.assertRaises(ValueError) as e: + # await queue.send_message(u'message') + + # self.assertEqual(str(e.exception), "Encryption required but no key was provided.") + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_get_with_strict_mode(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # await queue.send_message(u'message') + + # queue.require_encryption = True + # queue.key_encryption_key = KeyWrapper('key1') + # with self.assertRaises(ValueError) as e: + # messages = [] + # async for m in queue.receive_messages(): + # messages.append(m) + # _ = messages[0] + # self.assertEqual(str(e.exception), 'Message was not encrypted.') + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_encryption_add_encrypted_64k_message(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # message = u'a' * 1024 * 64 + + # # Act + # await queue.send_message(message) + + # # Assert + # queue.key_encryption_key = KeyWrapper('key1') + # with self.assertRaises(HttpResponseError): + # await queue.send_message(message) + + # @QueuePreparer() + # @AsyncStorageTestCase.await_prepared_test + # async def test_encryption_nonmatching_kid(self, storage_account_name, storage_account_key): + # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # # Arrange + # queue = await self._create_queue(qsc) + # queue.key_encryption_key = KeyWrapper('key1') + # await queue.send_message(u'message') + + # # Act + # queue.key_encryption_key.kid = 'Invalid' + + # # Assert + # with self.assertRaises(HttpResponseError) as e: + # messages = [] + # async for m in queue.receive_messages(): + # messages.append(m) + + # assert "Decryption failed." in str(e.exception) + @QueuePreparer() @AsyncStorageTestCase.await_prepared_test - async def test_get_messages_encrypted_kek(self, storage_account_name, storage_account_key): + async def test_get_message_encrypted_kek_v2(self, storage_account_name, storage_account_key): # Arrange - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - qsc.key_encryption_key = KeyWrapper('key1') + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) queue = await self._create_queue(qsc) - await queue.send_message(u'encrypted_message_2') + content = 'Hello World Encrypted!' # Act - li = None - async for m in queue.receive_messages(): - li = m + await queue.send_message(content) + message = await queue.receive_message() # Assert - self.assertEqual(li.content, u'encrypted_message_2') + self.assertEqual(content, message.content) @QueuePreparer() @AsyncStorageTestCase.await_prepared_test - async def test_get_messages_encrypted_resolver(self, storage_account_name, storage_account_key): + async def test_get_message_encrypted_resolver_v2(self, storage_account_name, storage_account_key): # Arrange - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - qsc.key_encryption_key = KeyWrapper('key1') - queue = await self._create_queue(qsc) - await queue.send_message(u'encrypted_message_2') + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) key_resolver = KeyResolver() key_resolver.put_key(qsc.key_encryption_key) - queue.key_resolver_function = key_resolver.resolve_key - queue.key_encryption_key = None # Ensure that the resolver is used - - # Act - li = None - async for m in queue.receive_messages(): - li = m - - # Assert - self.assertEqual(li.content, u'encrypted_message_2') - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_peek_messages_encrypted_kek(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - qsc.key_encryption_key = KeyWrapper('key1') queue = await self._create_queue(qsc) - await queue.send_message(u'encrypted_message_3') + content = 'Hello World Encrypted!' # Act - li = await queue.peek_messages() - - # Assert - self.assertEqual(li[0].content, u'encrypted_message_3') - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_peek_messages_encrypted_resolver(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - qsc.key_encryption_key = KeyWrapper('key1') - queue = await self._create_queue(qsc) - await queue.send_message(u'encrypted_message_4') - key_resolver = KeyResolver() - key_resolver.put_key(qsc.key_encryption_key) + await queue.send_message(content) queue.key_resolver_function = key_resolver.resolve_key queue.key_encryption_key = None # Ensure that the resolver is used - # Act - li = await queue.peek_messages() + message = await queue.receive_message() # Assert - self.assertEqual(li[0].content, u'encrypted_message_4') + self.assertEqual(content, message.content) @pytest.mark.live_test_only @QueuePreparer() @AsyncStorageTestCase.await_prepared_test - async def test_peek_messages_encrypted_kek_RSA(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + async def test_get_message_encrypted_kek_RSA_v2(self, storage_account_name, storage_account_key): # We can only generate random RSA keys, so this must be run live or # the playback test will fail due to a change in kek values. # Arrange - qsc.key_encryption_key = RSAKeyWrapper('key2') + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=RSAKeyWrapper('key2')) queue = await self._create_queue(qsc) - await queue.send_message(u'encrypted_message_3') + content = 'Hello World Encrypted!' # Act - li = await queue.peek_messages() + await queue.send_message(content) + message = await queue.receive_message() # Assert - self.assertEqual(li[0].content, u'encrypted_message_3') + self.assertEqual(content, message.content) - @pytest.mark.live_test_only @QueuePreparer() @AsyncStorageTestCase.await_prepared_test - async def test_update_encrypted_message(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # TODO: Recording doesn't work + async def test_update_encrypted_message_v2(self, storage_account_name, storage_account_key): # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) queue = await self._create_queue(qsc) - queue.key_encryption_key = KeyWrapper('key1') - await queue.send_message(u'Update Me') + await queue.send_message('Update Me') - messages = [] - async for m in queue.receive_messages(): - messages.append(m) - list_result1 = messages[0] - list_result1.content = u'Updated' + message = await queue.receive_message() + message.content = 'Updated' # Act - message = await queue.update_message(list_result1) - async for m in queue.receive_messages(): - messages.append(m) - list_result2 = messages[0] + await queue.update_message(message) + message = await queue.receive_message() # Assert - self.assertEqual(u'Updated', list_result2.content) + self.assertEqual('Updated', message.content) @QueuePreparer() @AsyncStorageTestCase.await_prepared_test - async def test_update_encrypted_binary_message(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + async def test_validate_encryption_v2(self, storage_account_name, storage_account_key): # Arrange - queue = await self._create_queue(qsc, message_encode_policy=BinaryBase64EncodePolicy(), message_decode_policy=BinaryBase64DecodePolicy()) - queue.key_encryption_key = KeyWrapper('key1') - - binary_message = self.get_random_bytes(100) - await queue.send_message(binary_message) - messages = [] - async for m in queue.receive_messages(): - messages.append(m) - list_result1 = messages[0] - - # Act - binary_message = self.get_random_bytes(100) - list_result1.content = binary_message - await queue.update_message(list_result1) - - async for m in queue.receive_messages(): - messages.append(m) - list_result2 = messages[0] - - # Assert - self.assertEqual(binary_message, list_result2.content) - - @pytest.mark.live_test_only - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_update_encrypted_raw_text_message(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # TODO: Recording doesn't work - # Arrange - queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) - queue.key_encryption_key = KeyWrapper('key1') - - raw_text = u'Update Me' - await queue.send_message(raw_text) - messages = [] - async for m in queue.receive_messages(): - messages.append(m) - list_result1 = messages[0] - - # Act - raw_text = u'Updated' - list_result1.content = raw_text - async for m in queue.receive_messages(): - messages.append(m) - list_result2 = messages[0] - - # Assert - self.assertEqual(raw_text, list_result2.content) - - @pytest.mark.live_test_only - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_update_encrypted_json_message(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # TODO: Recording doesn't work - # Arrange - queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) - queue.key_encryption_key = KeyWrapper('key1') - - message_dict = {'val1': 1, 'val2': '2'} - json_text = dumps(message_dict) - await queue.send_message(json_text) - messages = [] - async for m in queue.receive_messages(): - messages.append(m) - list_result1 = messages[0] - - # Act - message_dict['val1'] = 0 - message_dict['val2'] = 'updated' - json_text = dumps(message_dict) - list_result1.content = json_text - await queue.update_message(list_result1) - - async for m in queue.receive_messages(): - messages.append(m) - list_result2 = messages[0] - - # Assert - self.assertEqual(message_dict, loads(list_result2.content)) - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_invalid_value_kek_wrap(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - queue.key_encryption_key = KeyWrapper('key1') - queue.key_encryption_key.get_kid = None - - with self.assertRaises(AttributeError) as e: - await queue.send_message(u'message') - - self.assertEqual(str(e.exception), _ERROR_OBJECT_INVALID.format('key encryption key', 'get_kid')) - - queue.key_encryption_key = KeyWrapper('key1') - queue.key_encryption_key.get_kid = None - with self.assertRaises(AttributeError): - await queue.send_message(u'message') - - queue.key_encryption_key = KeyWrapper('key1') - queue.key_encryption_key.wrap_key = None - with self.assertRaises(AttributeError): - await queue.send_message(u'message') - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_missing_attribute_kek_wrap(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - - valid_key = KeyWrapper('key1') - - # Act - invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object - invalid_key_1.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm - invalid_key_1.get_kid = valid_key.get_kid - # No attribute wrap_key - queue.key_encryption_key = invalid_key_1 - with self.assertRaises(AttributeError): - await queue.send_message(u'message') - - invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object - invalid_key_2.wrap_key = valid_key.wrap_key - invalid_key_2.get_kid = valid_key.get_kid - # No attribute get_key_wrap_algorithm - queue.key_encryption_key = invalid_key_2 - with self.assertRaises(AttributeError): - await queue.send_message(u'message') - - invalid_key_3 = lambda: None # functions are objects, so this effectively creates an empty object - invalid_key_3.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm - invalid_key_3.wrap_key = valid_key.wrap_key - # No attribute get_kid - queue.key_encryption_key = invalid_key_3 - with self.assertRaises(AttributeError): - await queue.send_message(u'message') - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_invalid_value_kek_unwrap(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - queue.key_encryption_key = KeyWrapper('key1') - await queue.send_message(u'message') - - # Act - queue.key_encryption_key.unwrap_key = None - with self.assertRaises(HttpResponseError): - await queue.peek_messages() - - queue.key_encryption_key.get_kid = None - with self.assertRaises(HttpResponseError): - await queue.peek_messages() - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_missing_attribute_kek_unrwap(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - queue.key_encryption_key = KeyWrapper('key1') - await queue.send_message(u'message') - - # Act - valid_key = KeyWrapper('key1') - invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object - invalid_key_1.unwrap_key = valid_key.unwrap_key - # No attribute get_kid - queue.key_encryption_key = invalid_key_1 - with self.assertRaises(HttpResponseError) as e: - await queue.peek_messages() - - assert "Decryption failed." in str(e.exception) - - invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object - invalid_key_2.get_kid = valid_key.get_kid - # No attribute unwrap_key - queue.key_encryption_key = invalid_key_2 - with self.assertRaises(HttpResponseError): - await queue.peek_messages() - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_validate_encryption(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) kek = KeyWrapper('key1') - queue.key_encryption_key = kek - await queue.send_message(u'message') + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=kek) + queue = await self._create_queue(qsc) + content = 'Hello World Encrypted!' + await queue.send_message(content) # Act + queue.requires_encryption = False queue.key_encryption_key = None # Message will not be decrypted - li = await queue.peek_messages() - message = li[0].content + message = (await queue.receive_message()).content message = loads(message) encryption_data = message['EncryptionData'] + self.assertIsNotNone(encryption_data) wrapped_content_key = encryption_data['WrappedContentKey'] wrapped_content_key = _WrappedContentKey( wrapped_content_key['Algorithm'], b64decode(wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), wrapped_content_key['KeyId']) + self.assertEqual(kek.get_key_wrap_algorithm(), wrapped_content_key.algorithm) + self.assertEqual(kek.get_kid(), wrapped_content_key.key_id) encryption_agent = encryption_data['EncryptionAgent'] encryption_agent = _EncryptionAgent( encryption_agent['EncryptionAlgorithm'], encryption_agent['Protocol']) + self.assertEqual(_EncryptionAlgorithm.AES_GCM_256, encryption_agent.encryption_algorithm) + self.assertEqual('2.0', encryption_agent.protocol) + + encrypted_region_info = encryption_data['EncryptedRegionInfo'] + encrypted_region_info = _EncryptedRegionInfo( + encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['NonceLength'], + encrypted_region_info['TagLength']) + self.assertEqual(_GCM_REGION_LENGTH, encrypted_region_info.encrypted_region_data_length) + self.assertEqual(_GCM_NONCE_LENGTH, encrypted_region_info.nonce_length) + self.assertEqual(_GCM_TAG_LENGTH, encrypted_region_info.tag_length) encryption_data = _EncryptionData( - b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), + None, + encrypted_region_info, encryption_agent, wrapped_content_key, {'EncryptionLibrary': VERSION}) message = message['EncryptedMessageContents'] + message = _decode_base64_to_bytes(message) content_encryption_key = kek.unwrap_key( encryption_data.wrapped_content_key.encrypted_key, encryption_data.wrapped_content_key.algorithm) - # Create decryption cipher - backend = backends.default_backend() - algorithm = AES(content_encryption_key) - mode = CBC(encryption_data.content_encryption_IV) - cipher = Cipher(algorithm, mode, backend) + nonce_length = encryption_data.encrypted_region_info.nonce_length - # decode and decrypt data - decrypted_data = _decode_base64_to_bytes(message) - decryptor = cipher.decryptor() - decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + # First bytes are the nonce + nonce = message[:nonce_length] + ciphertext_with_tag = message[nonce_length:] - # unpad data - unpadder = PKCS7(128).unpadder() - decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + aesgcm = AESGCM(content_encryption_key) + decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) decrypted_data = decrypted_data.decode(encoding='utf-8') # Assert - self.assertEqual(decrypted_data, u'message') - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_put_with_strict_mode(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - kek = KeyWrapper('key1') - queue.key_encryption_key = kek - queue.require_encryption = True - - await queue.send_message(u'message') - queue.key_encryption_key = None - - # Assert - with self.assertRaises(ValueError) as e: - await queue.send_message(u'message') - - self.assertEqual(str(e.exception), "Encryption required but no key was provided.") - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_get_with_strict_mode(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - await queue.send_message(u'message') - - queue.require_encryption = True - queue.key_encryption_key = KeyWrapper('key1') - with self.assertRaises(ValueError) as e: - messages = [] - async for m in queue.receive_messages(): - messages.append(m) - _ = messages[0] - self.assertEqual(str(e.exception), 'Message was not encrypted.') - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_encryption_add_encrypted_64k_message(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - message = u'a' * 1024 * 64 - - # Act - await queue.send_message(message) - - # Assert - queue.key_encryption_key = KeyWrapper('key1') - with self.assertRaises(HttpResponseError): - await queue.send_message(message) - - @QueuePreparer() - @AsyncStorageTestCase.await_prepared_test - async def test_encryption_nonmatching_kid(self, storage_account_name, storage_account_key): - qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # Arrange - queue = await self._create_queue(qsc) - queue.key_encryption_key = KeyWrapper('key1') - await queue.send_message(u'message') - - # Act - queue.key_encryption_key.kid = 'Invalid' - - # Assert - with self.assertRaises(HttpResponseError) as e: - messages = [] - async for m in queue.receive_messages(): - messages.append(m) - - assert "Decryption failed." in str(e.exception) + self.assertEqual(content, decrypted_data) # ------------------------------------------------------------------------------ if __name__ == '__main__': From 9a6279434b053473a4eb094afb3b83c9f274f33e Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Thu, 19 May 2022 11:53:07 -0700 Subject: [PATCH 05/13] Adjust error message and fix tests --- .../azure/storage/queue/_shared/encryption.py | 7 +- ...ion.test_get_message_encrypted_kek_v2.yaml | 49 +++++----- ...est_get_message_encrypted_resolver_v2.yaml | 49 +++++----- ...tion.test_update_encrypted_message_v2.yaml | 92 ++++++++++--------- ...ncryption.test_validate_encryption_v2.yaml | 36 ++++---- .../tests/test_queue_encryption.py | 10 +- .../tests/test_queue_encryption_async.py | 12 +-- 7 files changed, 131 insertions(+), 124 deletions(-) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index 048426ccecf2..9158d1bf556d 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -648,9 +648,12 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ decoded_data = decode_base64_to_bytes(message['EncryptedMessageContents']) except (KeyError, ValueError): # Message was not json formatted and so was not encrypted - # or the user provided a json formatted message. + # or the user provided a json formatted message + # or the metadata was malformed. if require_encryption: - raise ValueError('Message was not encrypted.') + raise ValueError( + 'Encryption required, but received message does not contain appropriate metatadata. ' + \ + 'Message was either not encrypted or metadata was incorrect.') return message try: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml index 9e1fa559a228..e80f5c210635 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml @@ -13,7 +13,7 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:06 GMT + - Thu, 19 May 2022 18:51:06 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Wed, 18 May 2022 22:14:07 GMT + - Thu, 19 May 2022 18:51:06 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,11 +36,12 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "qxyi5OuH2yZcLOMAQtQ5EHpXMvpyVLL3oGh2Ek1Afuefv9k87b3xW5OLOcRDVEoQfkk=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "mbsZsJLjLGSrANshgPsWyjgpiqt/ntflTH46bKiqo54XBsmAfny9vA==", + {"EncryptedMessageContents": "E3T4ukeab6hVsYz9c0VKbKDD02Ogw9OvVvERUltFuGHC/89t8JKKYDxKp6Wt34/wCY4=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "XIRlkoc9x6tIaC3HoL4ekUOrf5OT/MDR4BzwUgksctPcUMxAf0/MIQ==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": - 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' headers: Accept: - application/xml @@ -49,28 +50,28 @@ interactions: Connection: - keep-alive Content-Length: - - '572' + - '594' Content-Type: - application/xml User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:07 GMT + - Thu, 19 May 2022 18:51:06 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e/messages response: body: - string: "\uFEFFa08d898b-309c-4283-ac84-d7493a1f0c4fWed, - 18 May 2022 22:14:07 GMTWed, 25 May 2022 22:14:07 - GMTAgAAAAMAAAAAAAAAgVF+lwRr2AE=Wed, - 18 May 2022 22:14:07 GMT" + string: "\uFEFFaf147b8c-241e-46cc-bfee-388ae280f233Thu, + 19 May 2022 18:51:06 GMTThu, 26 May 2022 18:51:06 + GMTAgAAAAMAAAAAAAAAT7LSZbFr2AE=Thu, + 19 May 2022 18:51:06 GMT" headers: content-type: - application/xml date: - - Wed, 18 May 2022 22:14:07 GMT + - Thu, 19 May 2022 18:51:06 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -92,31 +93,31 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:07 GMT + - Thu, 19 May 2022 18:51:06 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e/messages?numofmessages=1 response: body: - string: "\uFEFFa08d898b-309c-4283-ac84-d7493a1f0c4fWed, - 18 May 2022 22:14:07 GMTWed, 25 May 2022 22:14:07 - GMTAgAAAAMAAAAAAAAAEbdpqQRr2AE=Wed, - 18 May 2022 22:14:37 GMT1{\"EncryptedMessageContents\": - \"qxyi5OuH2yZcLOMAQtQ5EHpXMvpyVLL3oGh2Ek1Afuefv9k87b3xW5OLOcRDVEoQfkk=\", + string: "\uFEFFaf147b8c-241e-46cc-bfee-388ae280f233Thu, + 19 May 2022 18:51:06 GMTThu, 26 May 2022 18:51:06 + GMTAgAAAAMAAAAAAAAAW+y/d7Fr2AE=Thu, + 19 May 2022 18:51:36 GMT1{\"EncryptedMessageContents\": + \"E3T4ukeab6hVsYz9c0VKbKDD02Ogw9OvVvERUltFuGHC/89t8JKKYDxKp6Wt34/wCY4=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"mbsZsJLjLGSrANshgPsWyjgpiqt/ntflTH46bKiqo54XBsmAfny9vA==\", \"Algorithm\": + \"XIRlkoc9x6tIaC3HoL4ekUOrf5OT/MDR4BzwUgksctPcUMxAf0/MIQ==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, - \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python - 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Wed, 18 May 2022 22:14:07 GMT + - Thu, 19 May 2022 18:51:06 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml index c763b1edfd97..1f6960ebb731 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml @@ -13,7 +13,7 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:13 GMT + - Thu, 19 May 2022 18:51:13 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Wed, 18 May 2022 22:14:12 GMT + - Thu, 19 May 2022 18:51:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,11 +36,12 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "SeZehCQQttR4YAyRxXjJU7bewv6m+T2PLvpY/b6SYFzOEfJDb4xVSa/E1YQnld6qZuQ=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "2FaM3epFq1ByKyLO18FBwylh8gvl4Z6AVSlRKwwUXfQHReiXt12ffg==", + {"EncryptedMessageContents": "O22FsY56u5vWzpOeudz7R5bQjt/ENv78cTs67AsS33025V1P5zN2/ixal62c3iEoUZc=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "5d1yKp0goG7ktjqO5srexNKBkaZ8QnYSv7zL+gmaRz5MoyGdsustlg==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": - 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' headers: Accept: - application/xml @@ -49,28 +50,28 @@ interactions: Connection: - keep-alive Content-Length: - - '572' + - '594' Content-Type: - application/xml User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:13 GMT + - Thu, 19 May 2022 18:51:13 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5/messages response: body: - string: "\uFEFF88611993-c960-4826-b9b5-98e25f3523f9Wed, - 18 May 2022 22:14:13 GMTWed, 25 May 2022 22:14:13 - GMTAgAAAAMAAAAAAAAAVoFumwRr2AE=Wed, - 18 May 2022 22:14:13 GMT" + string: "\uFEFF1df01551-628e-4f5e-b4d0-90a67833d682Thu, + 19 May 2022 18:51:13 GMTThu, 26 May 2022 18:51:13 + GMTAgAAAAMAAAAAAAAAse7eabFr2AE=Thu, + 19 May 2022 18:51:13 GMT" headers: content-type: - application/xml date: - - Wed, 18 May 2022 22:14:13 GMT + - Thu, 19 May 2022 18:51:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -92,31 +93,31 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:13 GMT + - Thu, 19 May 2022 18:51:13 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5/messages?numofmessages=1 response: body: - string: "\uFEFF88611993-c960-4826-b9b5-98e25f3523f9Wed, - 18 May 2022 22:14:13 GMTWed, 25 May 2022 22:14:13 - GMTAgAAAAMAAAAAAAAAIqparQRr2AE=Wed, - 18 May 2022 22:14:43 GMT1{\"EncryptedMessageContents\": - \"SeZehCQQttR4YAyRxXjJU7bewv6m+T2PLvpY/b6SYFzOEfJDb4xVSa/E1YQnld6qZuQ=\", + string: "\uFEFF1df01551-628e-4f5e-b4d0-90a67833d682Thu, + 19 May 2022 18:51:13 GMTThu, 26 May 2022 18:51:13 + GMTAgAAAAMAAAAAAAAAchfLe7Fr2AE=Thu, + 19 May 2022 18:51:43 GMT1{\"EncryptedMessageContents\": + \"O22FsY56u5vWzpOeudz7R5bQjt/ENv78cTs67AsS33025V1P5zN2/ixal62c3iEoUZc=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"2FaM3epFq1ByKyLO18FBwylh8gvl4Z6AVSlRKwwUXfQHReiXt12ffg==\", \"Algorithm\": + \"5d1yKp0goG7ktjqO5srexNKBkaZ8QnYSv7zL+gmaRz5MoyGdsustlg==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, - \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python - 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Wed, 18 May 2022 22:14:13 GMT + - Thu, 19 May 2022 18:51:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml index d2e98093c2fb..142e09f79065 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml @@ -13,7 +13,7 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,11 +36,12 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "HSuqa05/iqhx16IyJDYhHnpakZ52aizKxevtN06XJ3uYgzP3vw==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "RUhlsk1+tW0cGtOBly1Q+8cVmeDzbIKnMZGZ8xJCEa1W6KD5qiPyvw==", + {"EncryptedMessageContents": "QhN6VveqAIg4qjG1Vofe4RaFqfCLvGC9yBbIYBUUrBlkawIS2Q==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "h34o7hhucQOC/Ne3HiPrHOaxh0pvkyiZyUyzgzJPyQSVykLenUSB4Q==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": - 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' headers: Accept: - application/xml @@ -49,28 +50,28 @@ interactions: Connection: - keep-alive Content-Length: - - '556' + - '578' Content-Type: - application/xml User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages response: body: - string: "\uFEFF8dea69cf-45e9-45c3-b3f2-c416d9e177a0Wed, - 18 May 2022 22:14:34 GMTWed, 25 May 2022 22:14:34 - GMTAgAAAAMAAAAAAAAAkJDgpwRr2AE=Wed, - 18 May 2022 22:14:34 GMT" + string: "\uFEFF6eed6f93-76f4-4293-b0bb-250b6d4e314aThu, + 19 May 2022 18:51:21 GMTThu, 26 May 2022 18:51:21 + GMTAgAAAAMAAAAAAAAAHZDMbrFr2AE=Thu, + 19 May 2022 18:51:21 GMT" headers: content-type: - application/xml date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -92,30 +93,30 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages?numofmessages=1 response: body: - string: "\uFEFF8dea69cf-45e9-45c3-b3f2-c416d9e177a0Wed, - 18 May 2022 22:14:34 GMTWed, 25 May 2022 22:14:34 - GMTAgAAAAMAAAAAAAAAeC7NuQRr2AE=Wed, - 18 May 2022 22:15:04 GMT1{\"EncryptedMessageContents\": - \"HSuqa05/iqhx16IyJDYhHnpakZ52aizKxevtN06XJ3uYgzP3vw==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"RUhlsk1+tW0cGtOBly1Q+8cVmeDzbIKnMZGZ8xJCEa1W6KD5qiPyvw==\", + string: "\uFEFF6eed6f93-76f4-4293-b0bb-250b6d4e314aThu, + 19 May 2022 18:51:21 GMTThu, 26 May 2022 18:51:21 + GMTAgAAAAMAAAAAAAAARBi6gLFr2AE=Thu, + 19 May 2022 18:51:52 GMT1{\"EncryptedMessageContents\": + \"QhN6VveqAIg4qjG1Vofe4RaFqfCLvGC9yBbIYBUUrBlkawIS2Q==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"h34o7hhucQOC/Ne3HiPrHOaxh0pvkyiZyUyzgzJPyQSVykLenUSB4Q==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, - \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python - 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -128,11 +129,12 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "u1O+0236fUl1y+ddHZjI93uAX3k2tuExQw3crQFUnGPrpAw=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "Z6sFMumKNFwpbuIsCQyiHFqpglMNlxa0ogJgtO43kvq14/g/fawVMA==", + {"EncryptedMessageContents": "vahQtIo3YQpazOCCOhzHaJZ3Ly/Ralhj6lCQhYN0ixNS/HM=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "EB4xgA5rns3W8gqRpnonBwko3D3J3WykqgCNoeg3zGhYTCzL1TK5zg==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "AuthenticationBlockInfo": {"CiphertextLength": 4194304, "NonceLength": - 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' headers: Accept: - application/xml @@ -141,17 +143,17 @@ interactions: Connection: - keep-alive Content-Length: - - '552' + - '574' Content-Type: - application/xml User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:22 GMT x-ms-version: - '2021-02-12' method: PUT - uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages/8dea69cf-45e9-45c3-b3f2-c416d9e177a0?popreceipt=AgAAAAMAAAAAAAAAeC7NuQRr2AE%3D&visibilitytimeout=0 + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages/6eed6f93-76f4-4293-b0bb-250b6d4e314a?popreceipt=AgAAAAMAAAAAAAAARBi6gLFr2AE%3D&visibilitytimeout=0 response: body: string: '' @@ -159,13 +161,13 @@ interactions: content-length: - '0' date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-popreceipt: - - AwAAAAMAAAAAAAAA9Kj4pwRr2AEBAAAA + - AwAAAAMAAAAAAAAAWTPkbrFr2AEBAAAA x-ms-time-next-visible: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:22 GMT x-ms-version: - '2021-02-12' status: @@ -183,30 +185,30 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:22 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages?numofmessages=1 response: body: - string: "\uFEFF8dea69cf-45e9-45c3-b3f2-c416d9e177a0Wed, - 18 May 2022 22:14:34 GMTWed, 25 May 2022 22:14:34 - GMTAgAAAAMAAAAAAAAAFzHmuQRr2AE=Wed, - 18 May 2022 22:15:05 GMT2{\"EncryptedMessageContents\": - \"u1O+0236fUl1y+ddHZjI93uAX3k2tuExQw3crQFUnGPrpAw=\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"Z6sFMumKNFwpbuIsCQyiHFqpglMNlxa0ogJgtO43kvq14/g/fawVMA==\", + string: "\uFEFF6eed6f93-76f4-4293-b0bb-250b6d4e314aThu, + 19 May 2022 18:51:21 GMTThu, 26 May 2022 18:51:21 + GMTAgAAAAMAAAAAAAAAAg7QgLFr2AE=Thu, + 19 May 2022 18:51:52 GMT2{\"EncryptedMessageContents\": + \"vahQtIo3YQpazOCCOhzHaJZ3Ly/Ralhj6lCQhYN0ixNS/HM=\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"EB4xgA5rns3W8gqRpnonBwko3D3J3WykqgCNoeg3zGhYTCzL1TK5zg==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"AuthenticationBlockInfo\": {\"CiphertextLength\": 4194304, - \"NonceLength\": 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python - 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Wed, 18 May 2022 22:14:34 GMT + - Thu, 19 May 2022 18:51:21 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml index 965c0e1f3b48..4af9a11584a4 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml @@ -13,7 +13,7 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 23:32:00 GMT + - Thu, 19 May 2022 18:51:28 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Wed, 18 May 2022 23:32:00 GMT + - Thu, 19 May 2022 18:51:28 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,8 +36,8 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "LZMk+/EnPnROVSdHRPKIfP4vPjdPdfCljG1jnsnPuckgji4b3g2ud3JK/SWd/snwG7k=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "kAeH26jizVN0Y+WwuhSs/6UejUuJCqa5lFSq4KxtJFTrp2mRw9L8og==", + {"EncryptedMessageContents": "TW0KXP7iPilhFkyATnyeBzPefISC6GKCTW87k2YtUDOhiKhCo3heBOkU2tYWws0aFUI=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "KfM6hR89EAb3m44zFFLSEvpB5pn1p5f0hbN+CeyarMx6ijuDgTACwg==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": @@ -56,22 +56,22 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 23:32:00 GMT + - Thu, 19 May 2022 18:51:28 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueueff191437/messages response: body: - string: "\uFEFFc9557b24-f3cc-4d72-b4d7-d83b8e895c99Wed, - 18 May 2022 23:32:00 GMTWed, 25 May 2022 23:32:00 - GMTAgAAAAMAAAAAAAAAOE4weQ9r2AE=Wed, - 18 May 2022 23:32:00 GMT" + string: "\uFEFF37a2248f-010b-4c9a-b701-6808057cec56Thu, + 19 May 2022 18:51:28 GMTThu, 26 May 2022 18:51:28 + GMTAgAAAAMAAAAAAAAAVCumcrFr2AE=Thu, + 19 May 2022 18:51:28 GMT" headers: content-type: - application/xml date: - - Wed, 18 May 2022 23:32:00 GMT + - Thu, 19 May 2022 18:51:28 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -93,20 +93,20 @@ interactions: User-Agent: - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Wed, 18 May 2022 23:32:00 GMT + - Thu, 19 May 2022 18:51:28 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueueff191437/messages?numofmessages=1 response: body: - string: "\uFEFFc9557b24-f3cc-4d72-b4d7-d83b8e895c99Wed, - 18 May 2022 23:32:00 GMTWed, 25 May 2022 23:32:00 - GMTAgAAAAMAAAAAAAAAVa8diw9r2AE=Wed, - 18 May 2022 23:32:31 GMT1{\"EncryptedMessageContents\": - \"LZMk+/EnPnROVSdHRPKIfP4vPjdPdfCljG1jnsnPuckgji4b3g2ud3JK/SWd/snwG7k=\", + string: "\uFEFF37a2248f-010b-4c9a-b701-6808057cec56Thu, + 19 May 2022 18:51:28 GMTThu, 26 May 2022 18:51:28 + GMTAgAAAAMAAAAAAAAADlSShLFr2AE=Thu, + 19 May 2022 18:51:58 GMT1{\"EncryptedMessageContents\": + \"TW0KXP7iPilhFkyATnyeBzPefISC6GKCTW87k2YtUDOhiKhCo3heBOkU2tYWws0aFUI=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"kAeH26jizVN0Y+WwuhSs/6UejUuJCqa5lFSq4KxtJFTrp2mRw9L8og==\", \"Algorithm\": + \"KfM6hR89EAb3m44zFFLSEvpB5pn1p5f0hbN+CeyarMx6ijuDgTACwg==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": @@ -117,7 +117,7 @@ interactions: content-type: - application/xml date: - - Wed, 18 May 2022 23:32:00 GMT + - Thu, 19 May 2022 18:51:28 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index f11255fcdafe..d09e99ed32f5 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -486,7 +486,7 @@ def test_get_message_encrypted_kek_v2(self, storage_account_name, storage_accoun qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=KeyWrapper('key1')) queue = self._create_queue(qsc) @@ -505,7 +505,7 @@ def test_get_message_encrypted_resolver_v2(self, storage_account_name, storage_a qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=KeyWrapper('key1')) key_resolver = KeyResolver() @@ -534,7 +534,7 @@ def test_get_message_encrypted_kek_RSA_v2(self, storage_account_name, storage_ac qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=RSAKeyWrapper('key2')) queue = self._create_queue(qsc) @@ -576,7 +576,7 @@ def test_validate_encryption_v2(self, storage_account_name, storage_account_key) qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=kek) queue = self._create_queue(qsc) @@ -584,7 +584,7 @@ def test_validate_encryption_v2(self, storage_account_name, storage_account_key) queue.send_message(content) # Act - queue.requires_encryption = False + queue.require_encryption = False queue.key_encryption_key = None # Message will not be decrypted message = queue.receive_message().content message = loads(message) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py index 8813deda1493..269fbd45dcbb 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py @@ -536,7 +536,7 @@ async def test_get_message_encrypted_kek_v2(self, storage_account_name, storage_ qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=KeyWrapper('key1')) queue = await self._create_queue(qsc) @@ -556,7 +556,7 @@ async def test_get_message_encrypted_resolver_v2(self, storage_account_name, sto qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=KeyWrapper('key1')) key_resolver = KeyResolver() @@ -586,7 +586,7 @@ async def test_get_message_encrypted_kek_RSA_v2(self, storage_account_name, stor qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=RSAKeyWrapper('key2')) queue = await self._create_queue(qsc) @@ -606,7 +606,7 @@ async def test_update_encrypted_message_v2(self, storage_account_name, storage_a qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=KeyWrapper('key1')) queue = await self._create_queue(qsc) @@ -630,7 +630,7 @@ async def test_validate_encryption_v2(self, storage_account_name, storage_accoun qsc = QueueServiceClient( self.account_url(storage_account_name, "queue"), storage_account_key, - requires_encryption=True, + require_encryption=True, encryption_version='2.0', key_encryption_key=kek) queue = await self._create_queue(qsc) @@ -638,7 +638,7 @@ async def test_validate_encryption_v2(self, storage_account_name, storage_accoun await queue.send_message(content) # Act - queue.requires_encryption = False + queue.require_encryption = False queue.key_encryption_key = None # Message will not be decrypted message = (await queue.receive_message()).content message = loads(message) From 3ff87733841f60f5667c863bf7149a1f78caa97b Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Thu, 19 May 2022 16:49:42 -0700 Subject: [PATCH 06/13] Update shared code, fix test --- .../azure/storage/blob/_shared/encryption.py | 207 ++++- .../filedatalake/_shared/encryption.py | 207 ++++- .../storage/fileshare/_shared/encryption.py | 207 ++++- .../tests/test_queue_encryption.py | 2 +- .../tests/test_queue_encryption_async.py | 874 +++++++++--------- 5 files changed, 933 insertions(+), 564 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py index 62607cc0cf85..9158d1bf556d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py @@ -14,6 +14,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.padding import PKCS7 @@ -25,6 +26,11 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' +_ENCRYPTION_PROTOCOL_V2 = '2.0' +_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_NONCE_LENGTH = 12 +_GCM_TAG_LENGTH = 16 + _ERROR_OBJECT_INVALID = \ '{0} does not define a complete interface. Value of {1} is either missing or invalid.' @@ -49,6 +55,7 @@ class _EncryptionAlgorithm(object): Specifies which client encryption algorithm is used. ''' AES_CBC_256 = 'AES_CBC_256' + AES_GCM_256 = 'AES_GCM_256' class _WrappedContentKey: @@ -75,6 +82,30 @@ def __init__(self, algorithm, encrypted_key, key_id): self.key_id = key_id +class _EncryptedRegionInfo: + ''' + Represents the length of encryption elements. + This is only used for Encryption V2. + ''' + + def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + ''' + :param int encrypted_region_data_length: + The length of the encryption region data (not including nonce + tag). + :param str nonce_length: + The length of nonce used when encrypting. + :param int tag_length: + The length of the encryption tag. + ''' + _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('nonce_length', nonce_length) + _validate_not_none('tag_length', tag_length) + + self.encrypted_region_data_length = encrypted_region_data_length + self.nonce_length = nonce_length + self.tag_length = tag_length + + class _EncryptionAgent: ''' Represents the encryption agent stored on the service. @@ -101,11 +132,20 @@ class _EncryptionData: Represents the encryption data that is stored on the service. ''' - def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, - key_wrapping_metadata): + def __init__( + self, + content_encryption_IV, + encrypted_region_info, + encryption_agent, + wrapped_content_key, + key_wrapping_metadata): ''' - :param bytes content_encryption_IV: + :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. + Required for AES-CBC. + :param Optional[_EncryptedRegionInfo] encrypted_region_info: + The info about the autenticated block sizes. + Required for AES-GCM. :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -115,23 +155,32 @@ def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, A dict containing metadata related to the key wrapping. ''' - _validate_not_none('content_encryption_IV', content_encryption_IV) _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) + # Validate we have the right info for the specified algorithm + if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + _validate_not_none('content_encryption_IV', content_encryption_IV) + elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + _validate_not_none('encrypted_region_info', encrypted_region_info) + else: + raise ValueError("Invalid encryption algorithm.") + self.content_encryption_IV = content_encryption_IV + self.encrypted_region_info = encrypted_region_info self.encryption_agent = encryption_agent self.wrapped_content_key = wrapped_content_key self.key_wrapping_metadata = key_wrapping_metadata -def _generate_encryption_data_dict(kek, cek, iv): +def _generate_encryption_data_dict(kek, cek, iv, version): ''' Generates and returns the encryption metadata as a dict. :param object kek: The key encryption key. See calling functions for more information. :param bytes cek: The content encryption key. - :param bytes iv: The initialization vector. + :param Optional[bytes] iv: The initialization vector. Only required for AES-CBC. + :param str version: The client encryption version used. :return: A dict containing all the encryption metadata. :rtype: dict ''' @@ -146,13 +195,26 @@ def _generate_encryption_data_dict(kek, cek, iv): wrapped_content_key['Algorithm'] = kek.get_key_wrap_algorithm() encryption_agent = OrderedDict() - encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V1 - encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + encryption_agent['Protocol'] = version + + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 + + encrypted_region_info = OrderedDict() + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH + encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key encryption_data_dict['EncryptionAgent'] = encryption_agent - encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_data_dict['EncryptedRegionInfo'] = encrypted_region_info encryption_data_dict['KeyWrappingMetadata'] = {'EncryptionLibrary': 'Python ' + VERSION} return encryption_data_dict @@ -169,7 +231,8 @@ def _dict_to_encryption_data(encryption_data_dict): :rtype: _EncryptionData ''' try: - if encryption_data_dict['EncryptionAgent']['Protocol'] != _ENCRYPTION_PROTOCOL_V1: + protocol = encryption_data_dict['EncryptionAgent']['Protocol'] + if protocol not in [_ENCRYPTION_PROTOCOL_V1, _ENCRYPTION_PROTOCOL_V2]: raise ValueError("Unsupported encryption version.") except KeyError: raise ValueError("Unsupported encryption version.") @@ -187,7 +250,21 @@ def _dict_to_encryption_data(encryption_data_dict): else: key_wrapping_metadata = None - encryption_data = _EncryptionData(decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']), + # AES-CBC only + encryption_iv = None + if 'ContentEncryptionIV' in encryption_data_dict: + encryption_iv = decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']) + + # AES-GCM only + region_info = None + if 'EncryptedRegionInfo' in encryption_data_dict: + encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] + region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['NonceLength'], + encrypted_region_info['TagLength']) + + encryption_data = _EncryptionData(encryption_iv, + region_info, encryption_agent, wrapped_content_key, key_wrapping_metadata) @@ -227,11 +304,15 @@ def _validate_and_unwrap_cek(encryption_data, key_encryption_key=None, key_resol :rtype: bytes[] ''' - _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) _validate_not_none('encrypted_key', encryption_data.wrapped_content_key.encrypted_key) - if _ENCRYPTION_PROTOCOL_V1 != encryption_data.encryption_agent.protocol: - raise ValueError('Encryption version is not supported.') + # Validate we have the right info for the specified version + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: + _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: + _validate_not_none('encrypted_region_info', encryption_data.encrypted_region_info) + else: + raise ValueError('Specified encryption version is not supported.') content_encryption_key = None @@ -279,19 +360,37 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver _validate_not_none('message', message) content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, resolver) - if _EncryptionAlgorithm.AES_CBC_256 != encryption_data.encryption_agent.encryption_algorithm: - raise ValueError('Specified encryption algorithm is not supported.') + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: + if not encryption_data.content_encryption_IV: + raise ValueError("Missing required metadata for decryption.") - cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) + cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) - # decrypt data - decrypted_data = message - decryptor = cipher.decryptor() - decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + # decrypt data + decrypted_data = message + decryptor = cipher.decryptor() + decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + + # unpad data + unpadder = PKCS7(128).unpadder() + decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: + block_info = encryption_data.encrypted_region_info + if not block_info or not block_info.nonce_length: + raise ValueError("Missing required metadata for decryption.") - # unpad data - unpadder = PKCS7(128).unpadder() - decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + nonce_length = encryption_data.encrypted_region_info.nonce_length + + # First bytes are the nonce + nonce = message[:nonce_length] + ciphertext_with_tag = message[nonce_length:] + + aesgcm = AESGCM(content_encryption_key) + decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) + + else: + raise ValueError('Specified encryption version is not supported.') return decrypted_data @@ -333,7 +432,7 @@ def encrypt_blob(blob, key_encryption_key): encryptor = cipher.encryptor() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' return dumps(encryption_data), encrypted_data @@ -358,7 +457,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, + _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' encryption_data = dumps(encryption_data) @@ -452,9 +552,9 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): return encryptor, padder -def encrypt_queue_message(message, key_encryption_key): +def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using AES256 in CBC mode with 128 bit padding. + Encrypts the given plain text message using the given algorithm. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. @@ -465,6 +565,7 @@ def encrypt_queue_message(message, key_encryption_key): wrap_key(key)--wraps the specified key using an algorithm of the user's choice. get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key. get_kid()--returns a string key id for this key-encryption-key. + :param str version: The client encryption version to use. :return: A json-formatted string containing the encrypted message and the encryption metadata. :rtype: str ''' @@ -473,29 +574,47 @@ def encrypt_queue_message(message, key_encryption_key): _validate_not_none('key_encryption_key', key_encryption_key) _validate_key_encryption_key_wrap(key_encryption_key) - # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = os.urandom(32) - initialization_vector = os.urandom(16) - # Queue encoding functions all return unicode strings, and encryption should # operate on binary strings. message = message.encode('utf-8') - cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) + if version == _ENCRYPTION_PROTOCOL_V1: + # AES256 CBC uses 256 bit (32 byte) keys and always with 16 byte blocks + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) - # PKCS7 with 16 byte blocks ensures compatibility with AES. - padder = PKCS7(128).padder() - padded_data = padder.update(message) + padder.finalize() + cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) - # Encrypt the data. - encryptor = cipher.encryptor() - encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + # PKCS7 with 16 byte blocks ensures compatibility with AES. + padder = PKCS7(128).padder() + padded_data = padder.update(message) + padder.finalize() + + # Encrypt the data. + encryptor = cipher.encryptor() + encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + + elif version == _ENCRYPTION_PROTOCOL_V2: + # AES256 GCM uses 256 bit (32 byte) keys and a 12 byte nonce. + content_encryption_key = AESGCM.generate_key(bit_length=256) + initialization_vector = None + + # The nonce MUST be different for each key + nonce = os.urandom(12) + aesgcm = AESGCM(content_encryption_key) + + # Returns ciphertext + tag + cipertext_with_tag = aesgcm.encrypt(nonce, message, None) + encrypted_data = nonce + cipertext_with_tag + + else: + raise ValueError("Invalid encryption version specified.") # Build the dictionary structure. queue_message = {'EncryptedMessageContents': encode_base64(encrypted_data), 'EncryptionData': _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector)} + initialization_vector, + version)} return dumps(queue_message) @@ -520,6 +639,7 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ :return: The plain text message from the queue message. :rtype: str ''' + response = response.http_response try: message = loads(message) @@ -528,9 +648,12 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ decoded_data = decode_base64_to_bytes(message['EncryptedMessageContents']) except (KeyError, ValueError): # Message was not json formatted and so was not encrypted - # or the user provided a json formatted message. + # or the user provided a json formatted message + # or the metadata was malformed. if require_encryption: - raise ValueError('Message was not encrypted.') + raise ValueError( + 'Encryption required, but received message does not contain appropriate metatadata. ' + \ + 'Message was either not encrypted or metadata was incorrect.') return message try: diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py index 62607cc0cf85..9158d1bf556d 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py @@ -14,6 +14,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.padding import PKCS7 @@ -25,6 +26,11 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' +_ENCRYPTION_PROTOCOL_V2 = '2.0' +_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_NONCE_LENGTH = 12 +_GCM_TAG_LENGTH = 16 + _ERROR_OBJECT_INVALID = \ '{0} does not define a complete interface. Value of {1} is either missing or invalid.' @@ -49,6 +55,7 @@ class _EncryptionAlgorithm(object): Specifies which client encryption algorithm is used. ''' AES_CBC_256 = 'AES_CBC_256' + AES_GCM_256 = 'AES_GCM_256' class _WrappedContentKey: @@ -75,6 +82,30 @@ def __init__(self, algorithm, encrypted_key, key_id): self.key_id = key_id +class _EncryptedRegionInfo: + ''' + Represents the length of encryption elements. + This is only used for Encryption V2. + ''' + + def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + ''' + :param int encrypted_region_data_length: + The length of the encryption region data (not including nonce + tag). + :param str nonce_length: + The length of nonce used when encrypting. + :param int tag_length: + The length of the encryption tag. + ''' + _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('nonce_length', nonce_length) + _validate_not_none('tag_length', tag_length) + + self.encrypted_region_data_length = encrypted_region_data_length + self.nonce_length = nonce_length + self.tag_length = tag_length + + class _EncryptionAgent: ''' Represents the encryption agent stored on the service. @@ -101,11 +132,20 @@ class _EncryptionData: Represents the encryption data that is stored on the service. ''' - def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, - key_wrapping_metadata): + def __init__( + self, + content_encryption_IV, + encrypted_region_info, + encryption_agent, + wrapped_content_key, + key_wrapping_metadata): ''' - :param bytes content_encryption_IV: + :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. + Required for AES-CBC. + :param Optional[_EncryptedRegionInfo] encrypted_region_info: + The info about the autenticated block sizes. + Required for AES-GCM. :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -115,23 +155,32 @@ def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, A dict containing metadata related to the key wrapping. ''' - _validate_not_none('content_encryption_IV', content_encryption_IV) _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) + # Validate we have the right info for the specified algorithm + if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + _validate_not_none('content_encryption_IV', content_encryption_IV) + elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + _validate_not_none('encrypted_region_info', encrypted_region_info) + else: + raise ValueError("Invalid encryption algorithm.") + self.content_encryption_IV = content_encryption_IV + self.encrypted_region_info = encrypted_region_info self.encryption_agent = encryption_agent self.wrapped_content_key = wrapped_content_key self.key_wrapping_metadata = key_wrapping_metadata -def _generate_encryption_data_dict(kek, cek, iv): +def _generate_encryption_data_dict(kek, cek, iv, version): ''' Generates and returns the encryption metadata as a dict. :param object kek: The key encryption key. See calling functions for more information. :param bytes cek: The content encryption key. - :param bytes iv: The initialization vector. + :param Optional[bytes] iv: The initialization vector. Only required for AES-CBC. + :param str version: The client encryption version used. :return: A dict containing all the encryption metadata. :rtype: dict ''' @@ -146,13 +195,26 @@ def _generate_encryption_data_dict(kek, cek, iv): wrapped_content_key['Algorithm'] = kek.get_key_wrap_algorithm() encryption_agent = OrderedDict() - encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V1 - encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + encryption_agent['Protocol'] = version + + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 + + encrypted_region_info = OrderedDict() + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH + encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key encryption_data_dict['EncryptionAgent'] = encryption_agent - encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_data_dict['EncryptedRegionInfo'] = encrypted_region_info encryption_data_dict['KeyWrappingMetadata'] = {'EncryptionLibrary': 'Python ' + VERSION} return encryption_data_dict @@ -169,7 +231,8 @@ def _dict_to_encryption_data(encryption_data_dict): :rtype: _EncryptionData ''' try: - if encryption_data_dict['EncryptionAgent']['Protocol'] != _ENCRYPTION_PROTOCOL_V1: + protocol = encryption_data_dict['EncryptionAgent']['Protocol'] + if protocol not in [_ENCRYPTION_PROTOCOL_V1, _ENCRYPTION_PROTOCOL_V2]: raise ValueError("Unsupported encryption version.") except KeyError: raise ValueError("Unsupported encryption version.") @@ -187,7 +250,21 @@ def _dict_to_encryption_data(encryption_data_dict): else: key_wrapping_metadata = None - encryption_data = _EncryptionData(decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']), + # AES-CBC only + encryption_iv = None + if 'ContentEncryptionIV' in encryption_data_dict: + encryption_iv = decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']) + + # AES-GCM only + region_info = None + if 'EncryptedRegionInfo' in encryption_data_dict: + encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] + region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['NonceLength'], + encrypted_region_info['TagLength']) + + encryption_data = _EncryptionData(encryption_iv, + region_info, encryption_agent, wrapped_content_key, key_wrapping_metadata) @@ -227,11 +304,15 @@ def _validate_and_unwrap_cek(encryption_data, key_encryption_key=None, key_resol :rtype: bytes[] ''' - _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) _validate_not_none('encrypted_key', encryption_data.wrapped_content_key.encrypted_key) - if _ENCRYPTION_PROTOCOL_V1 != encryption_data.encryption_agent.protocol: - raise ValueError('Encryption version is not supported.') + # Validate we have the right info for the specified version + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: + _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: + _validate_not_none('encrypted_region_info', encryption_data.encrypted_region_info) + else: + raise ValueError('Specified encryption version is not supported.') content_encryption_key = None @@ -279,19 +360,37 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver _validate_not_none('message', message) content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, resolver) - if _EncryptionAlgorithm.AES_CBC_256 != encryption_data.encryption_agent.encryption_algorithm: - raise ValueError('Specified encryption algorithm is not supported.') + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: + if not encryption_data.content_encryption_IV: + raise ValueError("Missing required metadata for decryption.") - cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) + cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) - # decrypt data - decrypted_data = message - decryptor = cipher.decryptor() - decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + # decrypt data + decrypted_data = message + decryptor = cipher.decryptor() + decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + + # unpad data + unpadder = PKCS7(128).unpadder() + decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: + block_info = encryption_data.encrypted_region_info + if not block_info or not block_info.nonce_length: + raise ValueError("Missing required metadata for decryption.") - # unpad data - unpadder = PKCS7(128).unpadder() - decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + nonce_length = encryption_data.encrypted_region_info.nonce_length + + # First bytes are the nonce + nonce = message[:nonce_length] + ciphertext_with_tag = message[nonce_length:] + + aesgcm = AESGCM(content_encryption_key) + decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) + + else: + raise ValueError('Specified encryption version is not supported.') return decrypted_data @@ -333,7 +432,7 @@ def encrypt_blob(blob, key_encryption_key): encryptor = cipher.encryptor() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' return dumps(encryption_data), encrypted_data @@ -358,7 +457,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, + _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' encryption_data = dumps(encryption_data) @@ -452,9 +552,9 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): return encryptor, padder -def encrypt_queue_message(message, key_encryption_key): +def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using AES256 in CBC mode with 128 bit padding. + Encrypts the given plain text message using the given algorithm. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. @@ -465,6 +565,7 @@ def encrypt_queue_message(message, key_encryption_key): wrap_key(key)--wraps the specified key using an algorithm of the user's choice. get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key. get_kid()--returns a string key id for this key-encryption-key. + :param str version: The client encryption version to use. :return: A json-formatted string containing the encrypted message and the encryption metadata. :rtype: str ''' @@ -473,29 +574,47 @@ def encrypt_queue_message(message, key_encryption_key): _validate_not_none('key_encryption_key', key_encryption_key) _validate_key_encryption_key_wrap(key_encryption_key) - # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = os.urandom(32) - initialization_vector = os.urandom(16) - # Queue encoding functions all return unicode strings, and encryption should # operate on binary strings. message = message.encode('utf-8') - cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) + if version == _ENCRYPTION_PROTOCOL_V1: + # AES256 CBC uses 256 bit (32 byte) keys and always with 16 byte blocks + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) - # PKCS7 with 16 byte blocks ensures compatibility with AES. - padder = PKCS7(128).padder() - padded_data = padder.update(message) + padder.finalize() + cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) - # Encrypt the data. - encryptor = cipher.encryptor() - encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + # PKCS7 with 16 byte blocks ensures compatibility with AES. + padder = PKCS7(128).padder() + padded_data = padder.update(message) + padder.finalize() + + # Encrypt the data. + encryptor = cipher.encryptor() + encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + + elif version == _ENCRYPTION_PROTOCOL_V2: + # AES256 GCM uses 256 bit (32 byte) keys and a 12 byte nonce. + content_encryption_key = AESGCM.generate_key(bit_length=256) + initialization_vector = None + + # The nonce MUST be different for each key + nonce = os.urandom(12) + aesgcm = AESGCM(content_encryption_key) + + # Returns ciphertext + tag + cipertext_with_tag = aesgcm.encrypt(nonce, message, None) + encrypted_data = nonce + cipertext_with_tag + + else: + raise ValueError("Invalid encryption version specified.") # Build the dictionary structure. queue_message = {'EncryptedMessageContents': encode_base64(encrypted_data), 'EncryptionData': _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector)} + initialization_vector, + version)} return dumps(queue_message) @@ -520,6 +639,7 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ :return: The plain text message from the queue message. :rtype: str ''' + response = response.http_response try: message = loads(message) @@ -528,9 +648,12 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ decoded_data = decode_base64_to_bytes(message['EncryptedMessageContents']) except (KeyError, ValueError): # Message was not json formatted and so was not encrypted - # or the user provided a json formatted message. + # or the user provided a json formatted message + # or the metadata was malformed. if require_encryption: - raise ValueError('Message was not encrypted.') + raise ValueError( + 'Encryption required, but received message does not contain appropriate metatadata. ' + \ + 'Message was either not encrypted or metadata was incorrect.') return message try: diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py index 62607cc0cf85..9158d1bf556d 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py @@ -14,6 +14,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.padding import PKCS7 @@ -25,6 +26,11 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' +_ENCRYPTION_PROTOCOL_V2 = '2.0' +_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_NONCE_LENGTH = 12 +_GCM_TAG_LENGTH = 16 + _ERROR_OBJECT_INVALID = \ '{0} does not define a complete interface. Value of {1} is either missing or invalid.' @@ -49,6 +55,7 @@ class _EncryptionAlgorithm(object): Specifies which client encryption algorithm is used. ''' AES_CBC_256 = 'AES_CBC_256' + AES_GCM_256 = 'AES_GCM_256' class _WrappedContentKey: @@ -75,6 +82,30 @@ def __init__(self, algorithm, encrypted_key, key_id): self.key_id = key_id +class _EncryptedRegionInfo: + ''' + Represents the length of encryption elements. + This is only used for Encryption V2. + ''' + + def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + ''' + :param int encrypted_region_data_length: + The length of the encryption region data (not including nonce + tag). + :param str nonce_length: + The length of nonce used when encrypting. + :param int tag_length: + The length of the encryption tag. + ''' + _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('nonce_length', nonce_length) + _validate_not_none('tag_length', tag_length) + + self.encrypted_region_data_length = encrypted_region_data_length + self.nonce_length = nonce_length + self.tag_length = tag_length + + class _EncryptionAgent: ''' Represents the encryption agent stored on the service. @@ -101,11 +132,20 @@ class _EncryptionData: Represents the encryption data that is stored on the service. ''' - def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, - key_wrapping_metadata): + def __init__( + self, + content_encryption_IV, + encrypted_region_info, + encryption_agent, + wrapped_content_key, + key_wrapping_metadata): ''' - :param bytes content_encryption_IV: + :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. + Required for AES-CBC. + :param Optional[_EncryptedRegionInfo] encrypted_region_info: + The info about the autenticated block sizes. + Required for AES-GCM. :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -115,23 +155,32 @@ def __init__(self, content_encryption_IV, encryption_agent, wrapped_content_key, A dict containing metadata related to the key wrapping. ''' - _validate_not_none('content_encryption_IV', content_encryption_IV) _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) + # Validate we have the right info for the specified algorithm + if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: + _validate_not_none('content_encryption_IV', content_encryption_IV) + elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: + _validate_not_none('encrypted_region_info', encrypted_region_info) + else: + raise ValueError("Invalid encryption algorithm.") + self.content_encryption_IV = content_encryption_IV + self.encrypted_region_info = encrypted_region_info self.encryption_agent = encryption_agent self.wrapped_content_key = wrapped_content_key self.key_wrapping_metadata = key_wrapping_metadata -def _generate_encryption_data_dict(kek, cek, iv): +def _generate_encryption_data_dict(kek, cek, iv, version): ''' Generates and returns the encryption metadata as a dict. :param object kek: The key encryption key. See calling functions for more information. :param bytes cek: The content encryption key. - :param bytes iv: The initialization vector. + :param Optional[bytes] iv: The initialization vector. Only required for AES-CBC. + :param str version: The client encryption version used. :return: A dict containing all the encryption metadata. :rtype: dict ''' @@ -146,13 +195,26 @@ def _generate_encryption_data_dict(kek, cek, iv): wrapped_content_key['Algorithm'] = kek.get_key_wrap_algorithm() encryption_agent = OrderedDict() - encryption_agent['Protocol'] = _ENCRYPTION_PROTOCOL_V1 - encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + encryption_agent['Protocol'] = version + + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_CBC_256 + + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 + + encrypted_region_info = OrderedDict() + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH + encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key encryption_data_dict['EncryptionAgent'] = encryption_agent - encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + if version == _ENCRYPTION_PROTOCOL_V1: + encryption_data_dict['ContentEncryptionIV'] = encode_base64(iv) + elif version == _ENCRYPTION_PROTOCOL_V2: + encryption_data_dict['EncryptedRegionInfo'] = encrypted_region_info encryption_data_dict['KeyWrappingMetadata'] = {'EncryptionLibrary': 'Python ' + VERSION} return encryption_data_dict @@ -169,7 +231,8 @@ def _dict_to_encryption_data(encryption_data_dict): :rtype: _EncryptionData ''' try: - if encryption_data_dict['EncryptionAgent']['Protocol'] != _ENCRYPTION_PROTOCOL_V1: + protocol = encryption_data_dict['EncryptionAgent']['Protocol'] + if protocol not in [_ENCRYPTION_PROTOCOL_V1, _ENCRYPTION_PROTOCOL_V2]: raise ValueError("Unsupported encryption version.") except KeyError: raise ValueError("Unsupported encryption version.") @@ -187,7 +250,21 @@ def _dict_to_encryption_data(encryption_data_dict): else: key_wrapping_metadata = None - encryption_data = _EncryptionData(decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']), + # AES-CBC only + encryption_iv = None + if 'ContentEncryptionIV' in encryption_data_dict: + encryption_iv = decode_base64_to_bytes(encryption_data_dict['ContentEncryptionIV']) + + # AES-GCM only + region_info = None + if 'EncryptedRegionInfo' in encryption_data_dict: + encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] + region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['NonceLength'], + encrypted_region_info['TagLength']) + + encryption_data = _EncryptionData(encryption_iv, + region_info, encryption_agent, wrapped_content_key, key_wrapping_metadata) @@ -227,11 +304,15 @@ def _validate_and_unwrap_cek(encryption_data, key_encryption_key=None, key_resol :rtype: bytes[] ''' - _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) _validate_not_none('encrypted_key', encryption_data.wrapped_content_key.encrypted_key) - if _ENCRYPTION_PROTOCOL_V1 != encryption_data.encryption_agent.protocol: - raise ValueError('Encryption version is not supported.') + # Validate we have the right info for the specified version + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: + _validate_not_none('content_encryption_IV', encryption_data.content_encryption_IV) + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: + _validate_not_none('encrypted_region_info', encryption_data.encrypted_region_info) + else: + raise ValueError('Specified encryption version is not supported.') content_encryption_key = None @@ -279,19 +360,37 @@ def _decrypt_message(message, encryption_data, key_encryption_key=None, resolver _validate_not_none('message', message) content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, resolver) - if _EncryptionAlgorithm.AES_CBC_256 != encryption_data.encryption_agent.encryption_algorithm: - raise ValueError('Specified encryption algorithm is not supported.') + if encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1: + if not encryption_data.content_encryption_IV: + raise ValueError("Missing required metadata for decryption.") - cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) + cipher = _generate_AES_CBC_cipher(content_encryption_key, encryption_data.content_encryption_IV) - # decrypt data - decrypted_data = message - decryptor = cipher.decryptor() - decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + # decrypt data + decrypted_data = message + decryptor = cipher.decryptor() + decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + + # unpad data + unpadder = PKCS7(128).unpadder() + decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + + elif encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V2: + block_info = encryption_data.encrypted_region_info + if not block_info or not block_info.nonce_length: + raise ValueError("Missing required metadata for decryption.") - # unpad data - unpadder = PKCS7(128).unpadder() - decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + nonce_length = encryption_data.encrypted_region_info.nonce_length + + # First bytes are the nonce + nonce = message[:nonce_length] + ciphertext_with_tag = message[nonce_length:] + + aesgcm = AESGCM(content_encryption_key) + decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None) + + else: + raise ValueError('Specified encryption version is not supported.') return decrypted_data @@ -333,7 +432,7 @@ def encrypt_blob(blob, key_encryption_key): encryptor = cipher.encryptor() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' return dumps(encryption_data), encrypted_data @@ -358,7 +457,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector) + initialization_vector, + _EncryptionAlgorithm.AES_CBC_256) encryption_data['EncryptionMode'] = 'FullBlob' encryption_data = dumps(encryption_data) @@ -452,9 +552,9 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): return encryptor, padder -def encrypt_queue_message(message, key_encryption_key): +def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using AES256 in CBC mode with 128 bit padding. + Encrypts the given plain text message using the given algorithm. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. @@ -465,6 +565,7 @@ def encrypt_queue_message(message, key_encryption_key): wrap_key(key)--wraps the specified key using an algorithm of the user's choice. get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key. get_kid()--returns a string key id for this key-encryption-key. + :param str version: The client encryption version to use. :return: A json-formatted string containing the encrypted message and the encryption metadata. :rtype: str ''' @@ -473,29 +574,47 @@ def encrypt_queue_message(message, key_encryption_key): _validate_not_none('key_encryption_key', key_encryption_key) _validate_key_encryption_key_wrap(key_encryption_key) - # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = os.urandom(32) - initialization_vector = os.urandom(16) - # Queue encoding functions all return unicode strings, and encryption should # operate on binary strings. message = message.encode('utf-8') - cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) + if version == _ENCRYPTION_PROTOCOL_V1: + # AES256 CBC uses 256 bit (32 byte) keys and always with 16 byte blocks + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) - # PKCS7 with 16 byte blocks ensures compatibility with AES. - padder = PKCS7(128).padder() - padded_data = padder.update(message) + padder.finalize() + cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) - # Encrypt the data. - encryptor = cipher.encryptor() - encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + # PKCS7 with 16 byte blocks ensures compatibility with AES. + padder = PKCS7(128).padder() + padded_data = padder.update(message) + padder.finalize() + + # Encrypt the data. + encryptor = cipher.encryptor() + encrypted_data = encryptor.update(padded_data) + encryptor.finalize() + + elif version == _ENCRYPTION_PROTOCOL_V2: + # AES256 GCM uses 256 bit (32 byte) keys and a 12 byte nonce. + content_encryption_key = AESGCM.generate_key(bit_length=256) + initialization_vector = None + + # The nonce MUST be different for each key + nonce = os.urandom(12) + aesgcm = AESGCM(content_encryption_key) + + # Returns ciphertext + tag + cipertext_with_tag = aesgcm.encrypt(nonce, message, None) + encrypted_data = nonce + cipertext_with_tag + + else: + raise ValueError("Invalid encryption version specified.") # Build the dictionary structure. queue_message = {'EncryptedMessageContents': encode_base64(encrypted_data), 'EncryptionData': _generate_encryption_data_dict(key_encryption_key, content_encryption_key, - initialization_vector)} + initialization_vector, + version)} return dumps(queue_message) @@ -520,6 +639,7 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ :return: The plain text message from the queue message. :rtype: str ''' + response = response.http_response try: message = loads(message) @@ -528,9 +648,12 @@ def decrypt_queue_message(message, response, require_encryption, key_encryption_ decoded_data = decode_base64_to_bytes(message['EncryptedMessageContents']) except (KeyError, ValueError): # Message was not json formatted and so was not encrypted - # or the user provided a json formatted message. + # or the user provided a json formatted message + # or the metadata was malformed. if require_encryption: - raise ValueError('Message was not encrypted.') + raise ValueError( + 'Encryption required, but received message does not contain appropriate metatadata. ' + \ + 'Message was either not encrypted or metadata was incorrect.') return message try: diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index d09e99ed32f5..d71a6fd384c4 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -446,7 +446,7 @@ def test_get_with_strict_mode(self, storage_account_name, storage_account_key): with self.assertRaises(ValueError) as e: next(queue.receive_messages()) - self.assertEqual(str(e.exception), 'Message was not encrypted.') + self.assertTrue('Message was either not encrypted or metadata was incorrect.' in str(e.exception)) @QueuePreparer() def test_encryption_add_encrypted_64k_message(self, storage_account_name, storage_account_key): diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py index 269fbd45dcbb..30254a21b226 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py @@ -91,443 +91,443 @@ async def _create_queue(self, qsc, prefix=TEST_QUEUE_PREFIX, **kwargs): pass return queue # -------------------------------------------------------------------------- - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_get_messages_encrypted_kek(self, storage_account_name, storage_account_key): - # # Arrange - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # qsc.key_encryption_key = KeyWrapper('key1') - # queue = await self._create_queue(qsc) - # await queue.send_message(u'encrypted_message_2') - - # # Act - # li = None - # async for m in queue.receive_messages(): - # li = m - - # # Assert - # self.assertEqual(li.content, u'encrypted_message_2') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_get_messages_encrypted_resolver(self, storage_account_name, storage_account_key): - # # Arrange - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # qsc.key_encryption_key = KeyWrapper('key1') - # queue = await self._create_queue(qsc) - # await queue.send_message(u'encrypted_message_2') - # key_resolver = KeyResolver() - # key_resolver.put_key(qsc.key_encryption_key) - # queue.key_resolver_function = key_resolver.resolve_key - # queue.key_encryption_key = None # Ensure that the resolver is used - - # # Act - # li = None - # async for m in queue.receive_messages(): - # li = m - - # # Assert - # self.assertEqual(li.content, u'encrypted_message_2') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_peek_messages_encrypted_kek(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # qsc.key_encryption_key = KeyWrapper('key1') - # queue = await self._create_queue(qsc) - # await queue.send_message(u'encrypted_message_3') - - # # Act - # li = await queue.peek_messages() - - # # Assert - # self.assertEqual(li[0].content, u'encrypted_message_3') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_peek_messages_encrypted_resolver(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # qsc.key_encryption_key = KeyWrapper('key1') - # queue = await self._create_queue(qsc) - # await queue.send_message(u'encrypted_message_4') - # key_resolver = KeyResolver() - # key_resolver.put_key(qsc.key_encryption_key) - # queue.key_resolver_function = key_resolver.resolve_key - # queue.key_encryption_key = None # Ensure that the resolver is used - - # # Act - # li = await queue.peek_messages() - - # # Assert - # self.assertEqual(li[0].content, u'encrypted_message_4') - - # @pytest.mark.live_test_only - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_peek_messages_encrypted_kek_RSA(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # We can only generate random RSA keys, so this must be run live or - # # the playback test will fail due to a change in kek values. - - # # Arrange - # qsc.key_encryption_key = RSAKeyWrapper('key2') - # queue = await self._create_queue(qsc) - # await queue.send_message(u'encrypted_message_3') - - # # Act - # li = await queue.peek_messages() - - # # Assert - # self.assertEqual(li[0].content, u'encrypted_message_3') - - # @pytest.mark.live_test_only - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_update_encrypted_message(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # TODO: Recording doesn't work - # # Arrange - # queue = await self._create_queue(qsc) - # queue.key_encryption_key = KeyWrapper('key1') - # await queue.send_message(u'Update Me') - - # messages = [] - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result1 = messages[0] - # list_result1.content = u'Updated' - - # # Act - # message = await queue.update_message(list_result1) - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result2 = messages[0] - - # # Assert - # self.assertEqual(u'Updated', list_result2.content) - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_update_encrypted_binary_message(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc, message_encode_policy=BinaryBase64EncodePolicy(), message_decode_policy=BinaryBase64DecodePolicy()) - # queue.key_encryption_key = KeyWrapper('key1') - - # binary_message = self.get_random_bytes(100) - # await queue.send_message(binary_message) - # messages = [] - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result1 = messages[0] - - # # Act - # binary_message = self.get_random_bytes(100) - # list_result1.content = binary_message - # await queue.update_message(list_result1) - - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result2 = messages[0] - - # # Assert - # self.assertEqual(binary_message, list_result2.content) - - # @pytest.mark.live_test_only - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_update_encrypted_raw_text_message(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # TODO: Recording doesn't work - # # Arrange - # queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) - # queue.key_encryption_key = KeyWrapper('key1') - - # raw_text = u'Update Me' - # await queue.send_message(raw_text) - # messages = [] - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result1 = messages[0] - - # # Act - # raw_text = u'Updated' - # list_result1.content = raw_text - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result2 = messages[0] - - # # Assert - # self.assertEqual(raw_text, list_result2.content) - - # @pytest.mark.live_test_only - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_update_encrypted_json_message(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # TODO: Recording doesn't work - # # Arrange - # queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) - # queue.key_encryption_key = KeyWrapper('key1') - - # message_dict = {'val1': 1, 'val2': '2'} - # json_text = dumps(message_dict) - # await queue.send_message(json_text) - # messages = [] - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result1 = messages[0] - - # # Act - # message_dict['val1'] = 0 - # message_dict['val2'] = 'updated' - # json_text = dumps(message_dict) - # list_result1.content = json_text - # await queue.update_message(list_result1) - - # async for m in queue.receive_messages(): - # messages.append(m) - # list_result2 = messages[0] - - # # Assert - # self.assertEqual(message_dict, loads(list_result2.content)) - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_invalid_value_kek_wrap(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # queue.key_encryption_key = KeyWrapper('key1') - # queue.key_encryption_key.get_kid = None - - # with self.assertRaises(AttributeError) as e: - # await queue.send_message(u'message') - - # self.assertEqual(str(e.exception), _ERROR_OBJECT_INVALID.format('key encryption key', 'get_kid')) - - # queue.key_encryption_key = KeyWrapper('key1') - # queue.key_encryption_key.get_kid = None - # with self.assertRaises(AttributeError): - # await queue.send_message(u'message') - - # queue.key_encryption_key = KeyWrapper('key1') - # queue.key_encryption_key.wrap_key = None - # with self.assertRaises(AttributeError): - # await queue.send_message(u'message') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_missing_attribute_kek_wrap(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - - # valid_key = KeyWrapper('key1') - - # # Act - # invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object - # invalid_key_1.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm - # invalid_key_1.get_kid = valid_key.get_kid - # # No attribute wrap_key - # queue.key_encryption_key = invalid_key_1 - # with self.assertRaises(AttributeError): - # await queue.send_message(u'message') - - # invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object - # invalid_key_2.wrap_key = valid_key.wrap_key - # invalid_key_2.get_kid = valid_key.get_kid - # # No attribute get_key_wrap_algorithm - # queue.key_encryption_key = invalid_key_2 - # with self.assertRaises(AttributeError): - # await queue.send_message(u'message') - - # invalid_key_3 = lambda: None # functions are objects, so this effectively creates an empty object - # invalid_key_3.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm - # invalid_key_3.wrap_key = valid_key.wrap_key - # # No attribute get_kid - # queue.key_encryption_key = invalid_key_3 - # with self.assertRaises(AttributeError): - # await queue.send_message(u'message') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_invalid_value_kek_unwrap(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # queue.key_encryption_key = KeyWrapper('key1') - # await queue.send_message(u'message') - - # # Act - # queue.key_encryption_key.unwrap_key = None - # with self.assertRaises(HttpResponseError): - # await queue.peek_messages() - - # queue.key_encryption_key.get_kid = None - # with self.assertRaises(HttpResponseError): - # await queue.peek_messages() - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_missing_attribute_kek_unrwap(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # queue.key_encryption_key = KeyWrapper('key1') - # await queue.send_message(u'message') - - # # Act - # valid_key = KeyWrapper('key1') - # invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object - # invalid_key_1.unwrap_key = valid_key.unwrap_key - # # No attribute get_kid - # queue.key_encryption_key = invalid_key_1 - # with self.assertRaises(HttpResponseError) as e: - # await queue.peek_messages() - - # assert "Decryption failed." in str(e.exception) - - # invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object - # invalid_key_2.get_kid = valid_key.get_kid - # # No attribute unwrap_key - # queue.key_encryption_key = invalid_key_2 - # with self.assertRaises(HttpResponseError): - # await queue.peek_messages() - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_validate_encryption(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # kek = KeyWrapper('key1') - # queue.key_encryption_key = kek - # await queue.send_message(u'message') - - # # Act - # queue.key_encryption_key = None # Message will not be decrypted - # li = await queue.peek_messages() - # message = li[0].content - # message = loads(message) - - # encryption_data = message['EncryptionData'] - - # wrapped_content_key = encryption_data['WrappedContentKey'] - # wrapped_content_key = _WrappedContentKey( - # wrapped_content_key['Algorithm'], - # b64decode(wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), - # wrapped_content_key['KeyId']) - - # encryption_agent = encryption_data['EncryptionAgent'] - # encryption_agent = _EncryptionAgent( - # encryption_agent['EncryptionAlgorithm'], - # encryption_agent['Protocol']) - - # encryption_data = _EncryptionData( - # b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), - # encryption_agent, - # wrapped_content_key, - # {'EncryptionLibrary': VERSION}) - - # message = message['EncryptedMessageContents'] - # content_encryption_key = kek.unwrap_key( - # encryption_data.wrapped_content_key.encrypted_key, - # encryption_data.wrapped_content_key.algorithm) - - # # Create decryption cipher - # backend = backends.default_backend() - # algorithm = AES(content_encryption_key) - # mode = CBC(encryption_data.content_encryption_IV) - # cipher = Cipher(algorithm, mode, backend) - - # # decode and decrypt data - # decrypted_data = _decode_base64_to_bytes(message) - # decryptor = cipher.decryptor() - # decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) - - # # unpad data - # unpadder = PKCS7(128).unpadder() - # decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) - - # decrypted_data = decrypted_data.decode(encoding='utf-8') - - # # Assert - # self.assertEqual(decrypted_data, u'message') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_put_with_strict_mode(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # kek = KeyWrapper('key1') - # queue.key_encryption_key = kek - # queue.require_encryption = True - - # await queue.send_message(u'message') - # queue.key_encryption_key = None - - # # Assert - # with self.assertRaises(ValueError) as e: - # await queue.send_message(u'message') - - # self.assertEqual(str(e.exception), "Encryption required but no key was provided.") - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_get_with_strict_mode(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # await queue.send_message(u'message') - - # queue.require_encryption = True - # queue.key_encryption_key = KeyWrapper('key1') - # with self.assertRaises(ValueError) as e: - # messages = [] - # async for m in queue.receive_messages(): - # messages.append(m) - # _ = messages[0] - # self.assertEqual(str(e.exception), 'Message was not encrypted.') - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_encryption_add_encrypted_64k_message(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # message = u'a' * 1024 * 64 - - # # Act - # await queue.send_message(message) - - # # Assert - # queue.key_encryption_key = KeyWrapper('key1') - # with self.assertRaises(HttpResponseError): - # await queue.send_message(message) - - # @QueuePreparer() - # @AsyncStorageTestCase.await_prepared_test - # async def test_encryption_nonmatching_kid(self, storage_account_name, storage_account_key): - # qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) - # # Arrange - # queue = await self._create_queue(qsc) - # queue.key_encryption_key = KeyWrapper('key1') - # await queue.send_message(u'message') - - # # Act - # queue.key_encryption_key.kid = 'Invalid' - - # # Assert - # with self.assertRaises(HttpResponseError) as e: - # messages = [] - # async for m in queue.receive_messages(): - # messages.append(m) - - # assert "Decryption failed." in str(e.exception) + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_get_messages_encrypted_kek(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + qsc.key_encryption_key = KeyWrapper('key1') + queue = await self._create_queue(qsc) + await queue.send_message(u'encrypted_message_2') + + # Act + li = None + async for m in queue.receive_messages(): + li = m + + # Assert + self.assertEqual(li.content, u'encrypted_message_2') + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_get_messages_encrypted_resolver(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + qsc.key_encryption_key = KeyWrapper('key1') + queue = await self._create_queue(qsc) + await queue.send_message(u'encrypted_message_2') + key_resolver = KeyResolver() + key_resolver.put_key(qsc.key_encryption_key) + queue.key_resolver_function = key_resolver.resolve_key + queue.key_encryption_key = None # Ensure that the resolver is used + + # Act + li = None + async for m in queue.receive_messages(): + li = m + + # Assert + self.assertEqual(li.content, u'encrypted_message_2') + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_peek_messages_encrypted_kek(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + qsc.key_encryption_key = KeyWrapper('key1') + queue = await self._create_queue(qsc) + await queue.send_message(u'encrypted_message_3') + + # Act + li = await queue.peek_messages() + + # Assert + self.assertEqual(li[0].content, u'encrypted_message_3') + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_peek_messages_encrypted_resolver(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + qsc.key_encryption_key = KeyWrapper('key1') + queue = await self._create_queue(qsc) + await queue.send_message(u'encrypted_message_4') + key_resolver = KeyResolver() + key_resolver.put_key(qsc.key_encryption_key) + queue.key_resolver_function = key_resolver.resolve_key + queue.key_encryption_key = None # Ensure that the resolver is used + + # Act + li = await queue.peek_messages() + + # Assert + self.assertEqual(li[0].content, u'encrypted_message_4') + + @pytest.mark.live_test_only + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_peek_messages_encrypted_kek_RSA(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # We can only generate random RSA keys, so this must be run live or + # the playback test will fail due to a change in kek values. + + # Arrange + qsc.key_encryption_key = RSAKeyWrapper('key2') + queue = await self._create_queue(qsc) + await queue.send_message(u'encrypted_message_3') + + # Act + li = await queue.peek_messages() + + # Assert + self.assertEqual(li[0].content, u'encrypted_message_3') + + @pytest.mark.live_test_only + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_update_encrypted_message(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # TODO: Recording doesn't work + # Arrange + queue = await self._create_queue(qsc) + queue.key_encryption_key = KeyWrapper('key1') + await queue.send_message(u'Update Me') + + messages = [] + async for m in queue.receive_messages(): + messages.append(m) + list_result1 = messages[0] + list_result1.content = u'Updated' + + # Act + message = await queue.update_message(list_result1) + async for m in queue.receive_messages(): + messages.append(m) + list_result2 = messages[0] + + # Assert + self.assertEqual(u'Updated', list_result2.content) + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_update_encrypted_binary_message(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc, message_encode_policy=BinaryBase64EncodePolicy(), message_decode_policy=BinaryBase64DecodePolicy()) + queue.key_encryption_key = KeyWrapper('key1') + + binary_message = self.get_random_bytes(100) + await queue.send_message(binary_message) + messages = [] + async for m in queue.receive_messages(): + messages.append(m) + list_result1 = messages[0] + + # Act + binary_message = self.get_random_bytes(100) + list_result1.content = binary_message + await queue.update_message(list_result1) + + async for m in queue.receive_messages(): + messages.append(m) + list_result2 = messages[0] + + # Assert + self.assertEqual(binary_message, list_result2.content) + + @pytest.mark.live_test_only + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_update_encrypted_raw_text_message(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # TODO: Recording doesn't work + # Arrange + queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) + queue.key_encryption_key = KeyWrapper('key1') + + raw_text = u'Update Me' + await queue.send_message(raw_text) + messages = [] + async for m in queue.receive_messages(): + messages.append(m) + list_result1 = messages[0] + + # Act + raw_text = u'Updated' + list_result1.content = raw_text + async for m in queue.receive_messages(): + messages.append(m) + list_result2 = messages[0] + + # Assert + self.assertEqual(raw_text, list_result2.content) + + @pytest.mark.live_test_only + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_update_encrypted_json_message(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # TODO: Recording doesn't work + # Arrange + queue = await self._create_queue(qsc, message_encode_policy=None, message_decode_policy=None) + queue.key_encryption_key = KeyWrapper('key1') + + message_dict = {'val1': 1, 'val2': '2'} + json_text = dumps(message_dict) + await queue.send_message(json_text) + messages = [] + async for m in queue.receive_messages(): + messages.append(m) + list_result1 = messages[0] + + # Act + message_dict['val1'] = 0 + message_dict['val2'] = 'updated' + json_text = dumps(message_dict) + list_result1.content = json_text + await queue.update_message(list_result1) + + async for m in queue.receive_messages(): + messages.append(m) + list_result2 = messages[0] + + # Assert + self.assertEqual(message_dict, loads(list_result2.content)) + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_invalid_value_kek_wrap(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + queue.key_encryption_key = KeyWrapper('key1') + queue.key_encryption_key.get_kid = None + + with self.assertRaises(AttributeError) as e: + await queue.send_message(u'message') + + self.assertEqual(str(e.exception), _ERROR_OBJECT_INVALID.format('key encryption key', 'get_kid')) + + queue.key_encryption_key = KeyWrapper('key1') + queue.key_encryption_key.get_kid = None + with self.assertRaises(AttributeError): + await queue.send_message(u'message') + + queue.key_encryption_key = KeyWrapper('key1') + queue.key_encryption_key.wrap_key = None + with self.assertRaises(AttributeError): + await queue.send_message(u'message') + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_missing_attribute_kek_wrap(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + + valid_key = KeyWrapper('key1') + + # Act + invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object + invalid_key_1.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm + invalid_key_1.get_kid = valid_key.get_kid + # No attribute wrap_key + queue.key_encryption_key = invalid_key_1 + with self.assertRaises(AttributeError): + await queue.send_message(u'message') + + invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object + invalid_key_2.wrap_key = valid_key.wrap_key + invalid_key_2.get_kid = valid_key.get_kid + # No attribute get_key_wrap_algorithm + queue.key_encryption_key = invalid_key_2 + with self.assertRaises(AttributeError): + await queue.send_message(u'message') + + invalid_key_3 = lambda: None # functions are objects, so this effectively creates an empty object + invalid_key_3.get_key_wrap_algorithm = valid_key.get_key_wrap_algorithm + invalid_key_3.wrap_key = valid_key.wrap_key + # No attribute get_kid + queue.key_encryption_key = invalid_key_3 + with self.assertRaises(AttributeError): + await queue.send_message(u'message') + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_invalid_value_kek_unwrap(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + queue.key_encryption_key = KeyWrapper('key1') + await queue.send_message(u'message') + + # Act + queue.key_encryption_key.unwrap_key = None + with self.assertRaises(HttpResponseError): + await queue.peek_messages() + + queue.key_encryption_key.get_kid = None + with self.assertRaises(HttpResponseError): + await queue.peek_messages() + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_missing_attribute_kek_unrwap(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + queue.key_encryption_key = KeyWrapper('key1') + await queue.send_message(u'message') + + # Act + valid_key = KeyWrapper('key1') + invalid_key_1 = lambda: None # functions are objects, so this effectively creates an empty object + invalid_key_1.unwrap_key = valid_key.unwrap_key + # No attribute get_kid + queue.key_encryption_key = invalid_key_1 + with self.assertRaises(HttpResponseError) as e: + await queue.peek_messages() + + assert "Decryption failed." in str(e.exception) + + invalid_key_2 = lambda: None # functions are objects, so this effectively creates an empty object + invalid_key_2.get_kid = valid_key.get_kid + # No attribute unwrap_key + queue.key_encryption_key = invalid_key_2 + with self.assertRaises(HttpResponseError): + await queue.peek_messages() + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_validate_encryption(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + kek = KeyWrapper('key1') + queue.key_encryption_key = kek + await queue.send_message(u'message') + + # Act + queue.key_encryption_key = None # Message will not be decrypted + li = await queue.peek_messages() + message = li[0].content + message = loads(message) + + encryption_data = message['EncryptionData'] + + wrapped_content_key = encryption_data['WrappedContentKey'] + wrapped_content_key = _WrappedContentKey( + wrapped_content_key['Algorithm'], + b64decode(wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), + wrapped_content_key['KeyId']) + + encryption_agent = encryption_data['EncryptionAgent'] + encryption_agent = _EncryptionAgent( + encryption_agent['EncryptionAlgorithm'], + encryption_agent['Protocol']) + + encryption_data = _EncryptionData( + b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), + encryption_agent, + wrapped_content_key, + {'EncryptionLibrary': VERSION}) + + message = message['EncryptedMessageContents'] + content_encryption_key = kek.unwrap_key( + encryption_data.wrapped_content_key.encrypted_key, + encryption_data.wrapped_content_key.algorithm) + + # Create decryption cipher + backend = backends.default_backend() + algorithm = AES(content_encryption_key) + mode = CBC(encryption_data.content_encryption_IV) + cipher = Cipher(algorithm, mode, backend) + + # decode and decrypt data + decrypted_data = _decode_base64_to_bytes(message) + decryptor = cipher.decryptor() + decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) + + # unpad data + unpadder = PKCS7(128).unpadder() + decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) + + decrypted_data = decrypted_data.decode(encoding='utf-8') + + # Assert + self.assertEqual(decrypted_data, u'message') + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_put_with_strict_mode(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + kek = KeyWrapper('key1') + queue.key_encryption_key = kek + queue.require_encryption = True + + await queue.send_message(u'message') + queue.key_encryption_key = None + + # Assert + with self.assertRaises(ValueError) as e: + await queue.send_message(u'message') + + self.assertEqual(str(e.exception), "Encryption required but no key was provided.") + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_get_with_strict_mode(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + await queue.send_message(u'message') + + queue.require_encryption = True + queue.key_encryption_key = KeyWrapper('key1') + with self.assertRaises(ValueError) as e: + messages = [] + async for m in queue.receive_messages(): + messages.append(m) + _ = messages[0] + self.assertTrue('Message was either not encrypted or metadata was incorrect.' in str(e.exception)) + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_encryption_add_encrypted_64k_message(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + message = u'a' * 1024 * 64 + + # Act + await queue.send_message(message) + + # Assert + queue.key_encryption_key = KeyWrapper('key1') + with self.assertRaises(HttpResponseError): + await queue.send_message(message) + + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_encryption_nonmatching_kid(self, storage_account_name, storage_account_key): + qsc = QueueServiceClient(self.account_url(storage_account_name, "queue"), storage_account_key, transport=AiohttpTestTransport()) + # Arrange + queue = await self._create_queue(qsc) + queue.key_encryption_key = KeyWrapper('key1') + await queue.send_message(u'message') + + # Act + queue.key_encryption_key.kid = 'Invalid' + + # Assert + with self.assertRaises(HttpResponseError) as e: + messages = [] + async for m in queue.receive_messages(): + messages.append(m) + + assert "Decryption failed." in str(e.exception) @QueuePreparer() @AsyncStorageTestCase.await_prepared_test From 0efc43819fb02027c8faf0e5d43c1e83dd9f73ac Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Mon, 23 May 2022 11:53:25 -0700 Subject: [PATCH 07/13] Fix test, minor tweaks --- .../azure/storage/blob/_shared/encryption.py | 11 +++++------ .../azure/storage/filedatalake/_shared/encryption.py | 11 +++++------ .../azure/storage/fileshare/_shared/encryption.py | 11 +++++------ .../azure/storage/queue/_shared/encryption.py | 11 +++++------ .../tests/test_queue_encryption_async.py | 1 + 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py index 9158d1bf556d..5dcbd8442c15 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py @@ -5,7 +5,6 @@ # -------------------------------------------------------------------------- import os -from os import urandom from json import ( dumps, loads, @@ -419,8 +418,8 @@ def encrypt_blob(blob, key_encryption_key): _validate_key_encryption_key_wrap(key_encryption_key) # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) @@ -453,8 +452,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = None if key_encryption_key: _validate_key_encryption_key_wrap(key_encryption_key) - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, initialization_vector, @@ -554,7 +553,7 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using the given algorithm. + Encrypts the given plain text message using the given protocol version. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py index 9158d1bf556d..5dcbd8442c15 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py @@ -5,7 +5,6 @@ # -------------------------------------------------------------------------- import os -from os import urandom from json import ( dumps, loads, @@ -419,8 +418,8 @@ def encrypt_blob(blob, key_encryption_key): _validate_key_encryption_key_wrap(key_encryption_key) # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) @@ -453,8 +452,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = None if key_encryption_key: _validate_key_encryption_key_wrap(key_encryption_key) - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, initialization_vector, @@ -554,7 +553,7 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using the given algorithm. + Encrypts the given plain text message using the given protocol version. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py index 9158d1bf556d..5dcbd8442c15 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py @@ -5,7 +5,6 @@ # -------------------------------------------------------------------------- import os -from os import urandom from json import ( dumps, loads, @@ -419,8 +418,8 @@ def encrypt_blob(blob, key_encryption_key): _validate_key_encryption_key_wrap(key_encryption_key) # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) @@ -453,8 +452,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = None if key_encryption_key: _validate_key_encryption_key_wrap(key_encryption_key) - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, initialization_vector, @@ -554,7 +553,7 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using the given algorithm. + Encrypts the given plain text message using the given protocol version. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index 9158d1bf556d..5dcbd8442c15 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -5,7 +5,6 @@ # -------------------------------------------------------------------------- import os -from os import urandom from json import ( dumps, loads, @@ -419,8 +418,8 @@ def encrypt_blob(blob, key_encryption_key): _validate_key_encryption_key_wrap(key_encryption_key) # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector) @@ -453,8 +452,8 @@ def generate_blob_encryption_data(key_encryption_key): initialization_vector = None if key_encryption_key: _validate_key_encryption_key_wrap(key_encryption_key) - content_encryption_key = urandom(32) - initialization_vector = urandom(16) + content_encryption_key = os.urandom(32) + initialization_vector = os.urandom(16) encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key, initialization_vector, @@ -554,7 +553,7 @@ def get_blob_encryptor_and_padder(cek, iv, should_pad): def encrypt_queue_message(message, key_encryption_key, version): ''' - Encrypts the given plain text message using the given algorithm. + Encrypts the given plain text message using the given protocol version. Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek). Returns a json-formatted string containing the encrypted message and the encryption metadata. diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py index 30254a21b226..7470b7f6faa5 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py @@ -428,6 +428,7 @@ async def test_validate_encryption(self, storage_account_name, storage_account_k encryption_data = _EncryptionData( b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), + None, encryption_agent, wrapped_content_key, {'EncryptionLibrary': VERSION}) From 18af88a7c5c3f79af6ba84e7d44e7503739fe8dd Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Tue, 31 May 2022 16:50:34 -0700 Subject: [PATCH 08/13] Minor changes --- .../azure/storage/blob/_shared/encryption.py | 4 +- .../filedatalake/_shared/encryption.py | 4 +- .../storage/fileshare/_shared/encryption.py | 4 +- .../azure/storage/queue/_message_encoding.py | 4 +- .../azure/storage/queue/_queue_client.py | 45 ++-- .../azure/storage/queue/_shared/encryption.py | 4 +- .../storage/queue/aio/_queue_client_async.py | 54 +++-- ...st_update_encrypted_binary_message_v2.yaml | 221 ++++++++++++++++++ ...st_update_encrypted_binary_message_v2.yaml | 177 ++++++++++++++ .../tests/test_queue_encryption.py | 31 ++- .../tests/test_queue_encryption_async.py | 31 ++- 11 files changed, 531 insertions(+), 48 deletions(-) create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml create mode 100644 sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py index 5dcbd8442c15..e41fab90daed 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py @@ -26,7 +26,7 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' _ENCRYPTION_PROTOCOL_V2 = '2.0' -_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_REGION_DATA_LENGTH = 4 * 1024 * 1024 _GCM_NONCE_LENGTH = 12 _GCM_TAG_LENGTH = 16 @@ -203,7 +203,7 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py index 5dcbd8442c15..e41fab90daed 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py @@ -26,7 +26,7 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' _ENCRYPTION_PROTOCOL_V2 = '2.0' -_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_REGION_DATA_LENGTH = 4 * 1024 * 1024 _GCM_NONCE_LENGTH = 12 _GCM_TAG_LENGTH = 16 @@ -203,7 +203,7 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py index 5dcbd8442c15..e41fab90daed 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py @@ -26,7 +26,7 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' _ENCRYPTION_PROTOCOL_V2 = '2.0' -_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_REGION_DATA_LENGTH = 4 * 1024 * 1024 _GCM_NONCE_LENGTH = 12 _GCM_TAG_LENGTH = 16 @@ -203,7 +203,7 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py index 30fb79e14055..d429f7a86c6d 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_message_encoding.py @@ -11,7 +11,7 @@ import six from azure.core.exceptions import DecodeError -from ._shared.encryption import decrypt_queue_message, encrypt_queue_message +from ._shared.encryption import decrypt_queue_message, encrypt_queue_message, _ENCRYPTION_PROTOCOL_V1 class MessageEncodePolicy(object): @@ -29,7 +29,7 @@ def __call__(self, content): content = encrypt_queue_message(content, self.key_encryption_key, self.encryption_version) return content - def configure(self, require_encryption, encryption_version, key_encryption_key, resolver): + def configure(self, require_encryption, key_encryption_key, resolver, encryption_version=_ENCRYPTION_PROTOCOL_V1): self.require_encryption = require_encryption self.encryption_version = encryption_version self.key_encryption_key = key_encryption_key diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py index 71968d035b89..65bfddaadcec 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py @@ -5,8 +5,9 @@ # -------------------------------------------------------------------------- import functools +import warnings from typing import ( # pylint: disable=unused-import - Union, Optional, Any, IO, Iterable, AnyStr, Dict, List, Tuple, + Optional, Any, Dict, List, TYPE_CHECKING) try: from urllib.parse import urlparse, quote, unquote @@ -34,8 +35,6 @@ from ._models import QueueMessage, AccessPolicy, MessagesPaged if TYPE_CHECKING: - from datetime import datetime - from azure.core.pipeline.policies import HTTPPolicy from ._models import QueueProperties @@ -477,11 +476,21 @@ def send_message( visibility_timeout = kwargs.pop('visibility_timeout', None) time_to_live = kwargs.pop('time_to_live', None) timeout = kwargs.pop('timeout', None) - self._config.message_encode_policy.configure( - require_encryption=self.require_encryption, - encryption_version=self.encryption_version, - key_encryption_key=self.key_encryption_key, - resolver=self.key_resolver_function) + try: + self._config.message_encode_policy.configure( + require_encryption=self.require_encryption, + key_encryption_key=self.key_encryption_key, + resolver=self.key_resolver_function, + encryption_version=self.encryption_version) + except TypeError: + warnings.warn( + "message_encode_policy.configure does not accept encryption_version parameter.", + DeprecationWarning + ) + self._config.message_encode_policy.configure( + require_encryption=self.require_encryption, + key_encryption_key=self.key_encryption_key, + resolver=self.key_resolver_function) encoded_content = self._config.message_encode_policy(content) new_message = GenQueueMessage(message_text=encoded_content) @@ -712,11 +721,21 @@ def update_message(self, if receipt is None: raise ValueError("pop_receipt must be present") if message_text is not None: - self._config.message_encode_policy.configure( - self.require_encryption, - self.encryption_version, - self.key_encryption_key, - self.key_resolver_function) + try: + self._config.message_encode_policy.configure( + self.require_encryption, + self.key_encryption_key, + self.key_resolver_function, + encryption_version=self.encryption_version) + except TypeError: + warnings.warn( + "message_encode_policy.configure does not accept encryption_version parameter.", + DeprecationWarning + ) + self._config.message_encode_policy.configure( + self.require_encryption, + self.key_encryption_key, + self.key_resolver_function) encoded_message_text = self._config.message_encode_policy(message_text) updated = GenQueueMessage(message_text=encoded_message_text) else: diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index 5dcbd8442c15..e41fab90daed 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -26,7 +26,7 @@ _ENCRYPTION_PROTOCOL_V1 = '1.0' _ENCRYPTION_PROTOCOL_V2 = '2.0' -_GCM_REGION_LENGTH = 4 * 1024 * 1024 +_GCM_REGION_DATA_LENGTH = 4 * 1024 * 1024 _GCM_NONCE_LENGTH = 12 _GCM_TAG_LENGTH = 16 @@ -203,7 +203,7 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_LENGTH + encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py index d48274f86e1a..1b265346a0e1 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py @@ -6,16 +6,12 @@ # pylint: disable=invalid-overridden-method import functools +import warnings from typing import ( # pylint: disable=unused-import - Union, Optional, Any, - IO, - Iterable, - AnyStr, Dict, List, - Tuple, TYPE_CHECKING, ) @@ -45,9 +41,7 @@ if TYPE_CHECKING: - from datetime import datetime - from azure.core.pipeline.policies import HTTPPolicy - from .._models import QueueSasPermissions, QueueProperties + from .._models import QueueProperties class QueueClient(AsyncStorageAccountHostsMixin, QueueClientBase): @@ -371,12 +365,21 @@ async def send_message( # type: ignore visibility_timeout = kwargs.pop('visibility_timeout', None) time_to_live = kwargs.pop('time_to_live', None) timeout = kwargs.pop('timeout', None) - self._config.message_encode_policy.configure( - require_encryption=self.require_encryption, - encryption_version=self.encryption_version, - key_encryption_key=self.key_encryption_key, - resolver=self.key_resolver_function - ) + try: + self._config.message_encode_policy.configure( + require_encryption=self.require_encryption, + key_encryption_key=self.key_encryption_key, + resolver=self.key_resolver_function, + encryption_version=self.encryption_version) + except TypeError: + warnings.warn( + "message_encode_policy.configure does not accept encryption_version parameter.", + DeprecationWarning + ) + self._config.message_encode_policy.configure( + require_encryption=self.require_encryption, + key_encryption_key=self.key_encryption_key, + resolver=self.key_resolver_function) encoded_content = self._config.message_encode_policy(content) new_message = GenQueueMessage(message_text=encoded_content) @@ -601,12 +604,23 @@ async def update_message( if receipt is None: raise ValueError("pop_receipt must be present") if message_text is not None: - self._config.message_encode_policy.configure( - self.require_encryption, - self.encryption_version, - self.key_encryption_key, - self.key_resolver_function - ) + try: + self._config.message_encode_policy.configure( + self.require_encryption, + self.key_encryption_key, + self.key_resolver_function, + encryption_version=self.encryption_version + ) + except TypeError: + warnings.warn( + "message_encode_policy.configure does not accept encryption_version parameter.", + DeprecationWarning + ) + self._config.message_encode_policy.configure( + self.require_encryption, + self.key_encryption_key, + self.key_resolver_function + ) encoded_message_text = self._config.message_encode_policy(message_text) updated = GenQueueMessage(message_text=encoded_message_text) else: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml new file mode 100644 index 000000000000..b05c395b81e1 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml @@ -0,0 +1,221 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:25:30 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Tue, 31 May 2022 23:25:29 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: ' + + {"EncryptedMessageContents": "SgO6wmEicLT7tGGBcZ8p3STA/gc2X9DqPQnjp0p8yH3fJbQHSLmQUw==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "Y8CU6GOnhJfRrFhVyU7lhsmHN9YsPDPv8cF4lWVLPfKINQ6l9XdSJQ==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '582' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:25:30 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages + response: + body: + string: "\uFEFF72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8Tue, + 31 May 2022 23:25:30 GMTTue, 07 Jun 2022 23:25:30 + GMTAgAAAAMAAAAAAAAAWgrpt0V12AE=Tue, + 31 May 2022 23:25:30 GMT" + headers: + content-type: + - application/xml + date: + - Tue, 31 May 2022 23:25:29 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:25:30 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages?numofmessages=1 + response: + body: + string: "\uFEFF72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8Tue, + 31 May 2022 23:25:30 GMTTue, 07 Jun 2022 23:25:30 + GMTAgAAAAMAAAAAAAAAEQzVyUV12AE=Tue, + 31 May 2022 23:26:00 GMT1{\"EncryptedMessageContents\": + \"SgO6wmEicLT7tGGBcZ8p3STA/gc2X9DqPQnjp0p8yH3fJbQHSLmQUw==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"Y8CU6GOnhJfRrFhVyU7lhsmHN9YsPDPv8cF4lWVLPfKINQ6l9XdSJQ==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Tue, 31 May 2022 23:25:29 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +- request: + body: ' + + {"EncryptedMessageContents": "RPW2ZZn1bIROwajIJVy059ywW4wofeXdwqgyuj1BAIWBwvH5O0d/Kg==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "MOMFJ8MGblfg098nWLKPYN7USNDgtRzOCFDLaceHVde+h769J8eaiQ==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '582' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:25:30 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages/72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8?popreceipt=AgAAAAMAAAAAAAAAEQzVyUV12AE%3D&visibilitytimeout=0 + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Tue, 31 May 2022 23:25:29 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-popreceipt: + - AwAAAAMAAAAAAAAAVcP/t0V12AEBAAAA + x-ms-time-next-visible: + - Tue, 31 May 2022 23:25:30 GMT + x-ms-version: + - '2021-02-12' + status: + code: 204 + message: No Content +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:25:30 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages?numofmessages=1 + response: + body: + string: "\uFEFF72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8Tue, + 31 May 2022 23:25:30 GMTTue, 07 Jun 2022 23:25:30 + GMTAgAAAAMAAAAAAAAAJBPsyUV12AE=Tue, + 31 May 2022 23:26:00 GMT2{\"EncryptedMessageContents\": + \"RPW2ZZn1bIROwajIJVy059ywW4wofeXdwqgyuj1BAIWBwvH5O0d/Kg==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"MOMFJ8MGblfg098nWLKPYN7USNDgtRzOCFDLaceHVde+h769J8eaiQ==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: + - no-cache + content-type: + - application/xml + date: + - Tue, 31 May 2022 23:25:30 GMT + server: + - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2021-02-12' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml new file mode 100644 index 000000000000..e5e1d421e203 --- /dev/null +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml @@ -0,0 +1,177 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:46:27 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98 + response: + body: + string: '' + headers: + content-length: '0' + date: Tue, 31 May 2022 23:46:27 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98 +- request: + body: ' + + {"EncryptedMessageContents": "AaCNHJJV1gEDzpCLL6VC37/NbG8UA3dpiEBVL7n1vH5OCBb/6i9s1A==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "2d2mrpU3bjAwpCMm7jYlHTwmty+7QOSus0d2yb5hAdHR9bBCyd0Q9g==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '582' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:46:28 GMT + x-ms-version: + - '2021-02-12' + method: POST + uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages + response: + body: + string: "\uFEFFf4b39a5f-ecae-4aa8-8ab5-46e4f372ce10Tue, + 31 May 2022 23:46:28 GMTTue, 07 Jun 2022 23:46:28 + GMTAgAAAAMAAAAAAAAAfkuLpUh12AE=Tue, + 31 May 2022 23:46:28 GMT" + headers: + content-type: application/xml + date: Tue, 31 May 2022 23:46:27 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 201 + message: Created + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98/messages +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:46:28 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages?numofmessages=1 + response: + body: + string: "\uFEFFf4b39a5f-ecae-4aa8-8ab5-46e4f372ce10Tue, + 31 May 2022 23:46:28 GMTTue, 07 Jun 2022 23:46:28 + GMTAgAAAAMAAAAAAAAAfDd4t0h12AE=Tue, + 31 May 2022 23:46:58 GMT1{\"EncryptedMessageContents\": + \"AaCNHJJV1gEDzpCLL6VC37/NbG8UA3dpiEBVL7n1vH5OCBb/6i9s1A==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"2d2mrpU3bjAwpCMm7jYlHTwmty+7QOSus0d2yb5hAdHR9bBCyd0Q9g==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Tue, 31 May 2022 23:46:27 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98/messages?numofmessages=1 +- request: + body: ' + + {"EncryptedMessageContents": "zlOxd9T7vJ9fG4OrPcuM8Fd0ebwEtNFMyqgteD5OziTz0pQD9tNj0A==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "e+7lnlMRfi4GMV9T+WCBYVC7KX9dDuyEE0Fo/08pbjyj2krZLGVGXw==", + "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": + "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, + "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": + "Python 12.3.1"}}}' + headers: + Accept: + - application/xml + Content-Length: + - '582' + Content-Type: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:46:28 GMT + x-ms-version: + - '2021-02-12' + method: PUT + uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages/f4b39a5f-ecae-4aa8-8ab5-46e4f372ce10?popreceipt=AgAAAAMAAAAAAAAAfDd4t0h12AE%3D&visibilitytimeout=0 + response: + body: + string: '' + headers: + content-length: '0' + date: Tue, 31 May 2022 23:46:27 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + x-ms-popreceipt: AwAAAAMAAAAAAAAAuO6ipUh12AEBAAAA + x-ms-time-next-visible: Tue, 31 May 2022 23:46:28 GMT + x-ms-version: '2021-02-12' + status: + code: 204 + message: No Content + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98/messages/f4b39a5f-ecae-4aa8-8ab5-46e4f372ce10?popreceipt=AgAAAAMAAAAAAAAAfDd4t0h12AE%3D&visibilitytimeout=0 +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + x-ms-date: + - Tue, 31 May 2022 23:46:28 GMT + x-ms-version: + - '2021-02-12' + method: GET + uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages?numofmessages=1 + response: + body: + string: "\uFEFFf4b39a5f-ecae-4aa8-8ab5-46e4f372ce10Tue, + 31 May 2022 23:46:28 GMTTue, 07 Jun 2022 23:46:28 + GMTAgAAAAMAAAAAAAAAMX+Vt0h12AE=Tue, + 31 May 2022 23:46:58 GMT2{\"EncryptedMessageContents\": + \"zlOxd9T7vJ9fG4OrPcuM8Fd0ebwEtNFMyqgteD5OziTz0pQD9tNj0A==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"e+7lnlMRfi4GMV9T+WCBYVC7KX9dDuyEE0Fo/08pbjyj2krZLGVGXw==\", + \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": + 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": + {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + headers: + cache-control: no-cache + content-type: application/xml + date: Tue, 31 May 2022 23:46:27 GMT + server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2021-02-12' + status: + code: 200 + message: OK + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98/messages?numofmessages=1 +version: 1 diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index d71a6fd384c4..46cf7249a4f0 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -24,7 +24,7 @@ from azure.storage.queue._shared import decode_base64_to_bytes from azure.storage.queue._shared.encryption import ( _ERROR_OBJECT_INVALID, - _GCM_REGION_LENGTH, + _GCM_REGION_DATA_LENGTH, _GCM_NONCE_LENGTH, _GCM_TAG_LENGTH, _EncryptedRegionInfo, @@ -37,7 +37,6 @@ from azure.storage.queue import ( VERSION, QueueServiceClient, - QueueClient, BinaryBase64EncodePolicy, BinaryBase64DecodePolicy, ) @@ -569,6 +568,32 @@ def test_update_encrypted_message_v2(self, storage_account_name, storage_account # Assert self.assertEqual('Updated', message.content) + @QueuePreparer() + def test_update_encrypted_binary_message_v2(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) + queue = self._create_queue( + qsc, + message_encode_policy=BinaryBase64EncodePolicy(), + message_decode_policy=BinaryBase64DecodePolicy()) + queue.key_encryption_key = KeyWrapper('key1') + + queue.send_message(b'Update Me') + message = queue.receive_message() + message.content = b'Updated' + + # Act + queue.update_message(message) + message = queue.receive_message() + + # Assert + self.assertEqual(b'Updated', message.content) + @QueuePreparer() def test_validate_encryption_v2(self, storage_account_name, storage_account_key): # Arrange @@ -612,7 +637,7 @@ def test_validate_encryption_v2(self, storage_account_name, storage_account_key) encrypted_region_info['EncryptedRegionDataLength'], encrypted_region_info['NonceLength'], encrypted_region_info['TagLength']) - self.assertEqual(_GCM_REGION_LENGTH, encrypted_region_info.encrypted_region_data_length) + self.assertEqual(_GCM_REGION_DATA_LENGTH, encrypted_region_info.encrypted_region_data_length) self.assertEqual(_GCM_NONCE_LENGTH, encrypted_region_info.nonce_length) self.assertEqual(_GCM_TAG_LENGTH, encrypted_region_info.tag_length) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py index 7470b7f6faa5..9c63d452d412 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py @@ -27,7 +27,7 @@ from multidict import CIMultiDict, CIMultiDictProxy from azure.storage.queue._shared.encryption import ( _ERROR_OBJECT_INVALID, - _GCM_REGION_LENGTH, + _GCM_REGION_DATA_LENGTH, _GCM_NONCE_LENGTH, _GCM_TAG_LENGTH, _EncryptedRegionInfo, @@ -623,6 +623,33 @@ async def test_update_encrypted_message_v2(self, storage_account_name, storage_a # Assert self.assertEqual('Updated', message.content) + @QueuePreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_update_encrypted_binary_message_v2(self, storage_account_name, storage_account_key): + # Arrange + qsc = QueueServiceClient( + self.account_url(storage_account_name, "queue"), + storage_account_key, + requires_encryption=True, + encryption_version='2.0', + key_encryption_key=KeyWrapper('key1')) + queue = await self._create_queue( + qsc, + message_encode_policy=BinaryBase64EncodePolicy(), + message_decode_policy=BinaryBase64DecodePolicy()) + queue.key_encryption_key = KeyWrapper('key1') + + await queue.send_message(b'Update Me') + message = await queue.receive_message() + message.content = b'Updated' + + # Act + await queue.update_message(message) + message = await queue.receive_message() + + # Assert + self.assertEqual(b'Updated', message.content) + @QueuePreparer() @AsyncStorageTestCase.await_prepared_test async def test_validate_encryption_v2(self, storage_account_name, storage_account_key): @@ -667,7 +694,7 @@ async def test_validate_encryption_v2(self, storage_account_name, storage_accoun encrypted_region_info['EncryptedRegionDataLength'], encrypted_region_info['NonceLength'], encrypted_region_info['TagLength']) - self.assertEqual(_GCM_REGION_LENGTH, encrypted_region_info.encrypted_region_data_length) + self.assertEqual(_GCM_REGION_DATA_LENGTH, encrypted_region_info.encrypted_region_data_length) self.assertEqual(_GCM_NONCE_LENGTH, encrypted_region_info.nonce_length) self.assertEqual(_GCM_TAG_LENGTH, encrypted_region_info.tag_length) From 9e4afe8a6d26ba5f9e700cd32b5c275e437aa990 Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Thu, 2 Jun 2022 16:47:08 -0700 Subject: [PATCH 09/13] Fix warnings --- .../azure-storage-queue/azure/storage/queue/_queue_client.py | 3 +-- .../azure/storage/queue/aio/_queue_client_async.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py index 65bfddaadcec..af12f9b6a1c8 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py @@ -484,8 +484,7 @@ def send_message( encryption_version=self.encryption_version) except TypeError: warnings.warn( - "message_encode_policy.configure does not accept encryption_version parameter.", - DeprecationWarning + "message_encode_policy.configure is likely missing the encryption_version parameter." ) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py index 1b265346a0e1..53fcac0d4a22 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py @@ -373,8 +373,7 @@ async def send_message( # type: ignore encryption_version=self.encryption_version) except TypeError: warnings.warn( - "message_encode_policy.configure does not accept encryption_version parameter.", - DeprecationWarning + "message_encode_policy.configure is likely missing the encryption_version parameter." ) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, From b9ed10f69b1d3d2cece7ad1823f93a49b3af582f Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Fri, 3 Jun 2022 11:54:02 -0700 Subject: [PATCH 10/13] PR Feedback --- .../azure/storage/blob/_shared/encryption.py | 6 +++--- .../azure/storage/filedatalake/_shared/encryption.py | 6 +++--- .../azure/storage/fileshare/_shared/encryption.py | 6 +++--- .../azure/storage/queue/_queue_client.py | 4 +++- .../azure/storage/queue/_shared/encryption.py | 6 +++--- .../azure/storage/queue/aio/_queue_client_async.py | 4 +++- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py index e41fab90daed..85d2a58bf44f 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py @@ -141,10 +141,10 @@ def __init__( ''' :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. - Required for AES-CBC. + Required for AES-CBC (V1). :param Optional[_EncryptedRegionInfo] encrypted_region_info: The info about the autenticated block sizes. - Required for AES-GCM. + Required for AES-GCM (V2). :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -157,7 +157,7 @@ def __init__( _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) - # Validate we have the right info for the specified algorithm + # Validate we have the right matching optional parameter for the specified algorithm if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: _validate_not_none('content_encryption_IV', content_encryption_IV) elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py index e41fab90daed..85d2a58bf44f 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py @@ -141,10 +141,10 @@ def __init__( ''' :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. - Required for AES-CBC. + Required for AES-CBC (V1). :param Optional[_EncryptedRegionInfo] encrypted_region_info: The info about the autenticated block sizes. - Required for AES-GCM. + Required for AES-GCM (V2). :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -157,7 +157,7 @@ def __init__( _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) - # Validate we have the right info for the specified algorithm + # Validate we have the right matching optional parameter for the specified algorithm if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: _validate_not_none('content_encryption_IV', content_encryption_IV) elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py index e41fab90daed..85d2a58bf44f 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py @@ -141,10 +141,10 @@ def __init__( ''' :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. - Required for AES-CBC. + Required for AES-CBC (V1). :param Optional[_EncryptedRegionInfo] encrypted_region_info: The info about the autenticated block sizes. - Required for AES-GCM. + Required for AES-GCM (V2). :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -157,7 +157,7 @@ def __init__( _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) - # Validate we have the right info for the specified algorithm + # Validate we have the right matching optional parameter for the specified algorithm if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: _validate_not_none('content_encryption_IV', content_encryption_IV) elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py index af12f9b6a1c8..8f0e4593bb43 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py @@ -484,7 +484,9 @@ def send_message( encryption_version=self.encryption_version) except TypeError: warnings.warn( - "message_encode_policy.configure is likely missing the encryption_version parameter." + "TypeError when calling message_encode_policy.configure. \ + It is likely missing the encryption_version parameter. \ + Retrying without encryption_version." ) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index e41fab90daed..85d2a58bf44f 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -141,10 +141,10 @@ def __init__( ''' :param Optional[bytes] content_encryption_IV: The content encryption initialization vector. - Required for AES-CBC. + Required for AES-CBC (V1). :param Optional[_EncryptedRegionInfo] encrypted_region_info: The info about the autenticated block sizes. - Required for AES-GCM. + Required for AES-GCM (V2). :param _EncryptionAgent encryption_agent: The encryption agent. :param _WrappedContentKey wrapped_content_key: @@ -157,7 +157,7 @@ def __init__( _validate_not_none('encryption_agent', encryption_agent) _validate_not_none('wrapped_content_key', wrapped_content_key) - # Validate we have the right info for the specified algorithm + # Validate we have the right matching optional parameter for the specified algorithm if encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256: _validate_not_none('content_encryption_IV', content_encryption_IV) elif encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_GCM_256: diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py index 53fcac0d4a22..47125b2d6f1a 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py @@ -373,7 +373,9 @@ async def send_message( # type: ignore encryption_version=self.encryption_version) except TypeError: warnings.warn( - "message_encode_policy.configure is likely missing the encryption_version parameter." + "TypeError when calling message_encode_policy.configure. \ + It is likely missing the encryption_version parameter. \ + Retrying without encryption_version." ) self._config.message_encode_policy.configure( require_encryption=self.require_encryption, From 4372a3b3b0e31e4e2a7eb569e6f057d3d6004bc7 Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Tue, 7 Jun 2022 15:13:32 -0700 Subject: [PATCH 11/13] Update CHANGELOG and version --- sdk/storage/azure-storage-queue/CHANGELOG.md | 13 +++++-------- .../azure/storage/queue/_version.py | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sdk/storage/azure-storage-queue/CHANGELOG.md b/sdk/storage/azure-storage-queue/CHANGELOG.md index 0011d90e24ea..26a67e328662 100644 --- a/sdk/storage/azure-storage-queue/CHANGELOG.md +++ b/sdk/storage/azure-storage-queue/CHANGELOG.md @@ -1,14 +1,11 @@ -# Release History + # Release History -## 12.3.1 (Unreleased) +## 12.4.0b1 (Unreleased) ### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added a new version of client-side encryption for Queue messages (version 2.0) which utilizes AES-GCM-256 encryption. +If you are currently using client-side encryption, it is **highly recommended** to switch to version 2.0. The encryption +version can be specified on any client constructor via the `encryption_version` keyword (`encryption_version='2.0'`). ## 12.3.0 (2022-05-09) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_version.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_version.py index 70efc5305910..949c0f220054 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_version.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_version.py @@ -9,4 +9,4 @@ # regenerated. # -------------------------------------------------------------------------- -VERSION = "12.3.1" +VERSION = "12.4.0b1" From 3adbffbc3954a35ad11733a4ffb23e09940a75cd Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Tue, 7 Jun 2022 15:15:00 -0700 Subject: [PATCH 12/13] Remove space --- sdk/storage/azure-storage-queue/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-queue/CHANGELOG.md b/sdk/storage/azure-storage-queue/CHANGELOG.md index 26a67e328662..7b525b6bfb6c 100644 --- a/sdk/storage/azure-storage-queue/CHANGELOG.md +++ b/sdk/storage/azure-storage-queue/CHANGELOG.md @@ -1,4 +1,4 @@ - # Release History +# Release History ## 12.4.0b1 (Unreleased) From a9c88449abbc418b8f3d3da2ca108174ad75df0f Mon Sep 17 00:00:00 2001 From: Jacob Lauzon Date: Wed, 8 Jun 2022 14:54:38 -0700 Subject: [PATCH 13/13] PR feedback, updates to metadata --- .../azure/storage/blob/_shared/encryption.py | 17 ++- .../filedatalake/_shared/encryption.py | 17 ++- .../storage/fileshare/_shared/encryption.py | 17 ++- sdk/storage/azure-storage-queue/CHANGELOG.md | 8 +- .../azure/storage/queue/_queue_client.py | 7 +- .../storage/queue/_shared/base_client.py | 7 ++ .../azure/storage/queue/_shared/encryption.py | 17 ++- .../storage/queue/aio/_queue_client_async.py | 7 +- ...ion.test_get_message_encrypted_kek_v2.yaml | 59 +++++----- ...est_get_message_encrypted_resolver_v2.yaml | 54 +++++----- ...st_update_encrypted_binary_message_v2.yaml | 100 +++++++++-------- ...tion.test_update_encrypted_message_v2.yaml | 100 +++++++++-------- ...ncryption.test_validate_encryption_v2.yaml | 54 +++++----- ...ync.test_get_message_encrypted_kek_v2.yaml | 54 +++++----- ...est_get_message_encrypted_resolver_v2.yaml | 54 +++++----- ...st_update_encrypted_binary_message_v2.yaml | 102 +++++++++--------- ...sync.test_update_encrypted_message_v2.yaml | 102 +++++++++--------- ...ion_async.test_validate_encryption_v2.yaml | 54 +++++----- .../tests/test_queue_encryption.py | 6 +- .../tests/test_queue_encryption_async.py | 7 +- 20 files changed, 414 insertions(+), 429 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py index 85d2a58bf44f..d9cc47165fa8 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/encryption.py @@ -87,20 +87,20 @@ class _EncryptedRegionInfo: This is only used for Encryption V2. ''' - def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + def __init__(self, data_length, nonce_length, tag_length): ''' - :param int encrypted_region_data_length: + :param int data_length: The length of the encryption region data (not including nonce + tag). :param str nonce_length: The length of nonce used when encrypting. :param int tag_length: The length of the encryption tag. ''' - _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('data_length', data_length) _validate_not_none('nonce_length', nonce_length) _validate_not_none('tag_length', tag_length) - self.encrypted_region_data_length = encrypted_region_data_length + self.data_length = data_length self.nonce_length = nonce_length self.tag_length = tag_length @@ -203,9 +203,8 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH + encrypted_region_info['DataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH - encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key @@ -258,9 +257,9 @@ def _dict_to_encryption_data(encryption_data_dict): region_info = None if 'EncryptedRegionInfo' in encryption_data_dict: encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] - region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], - encrypted_region_info['NonceLength'], - encrypted_region_info['TagLength']) + region_info = _EncryptedRegionInfo(encrypted_region_info['DataLength'], + encrypted_region_info['NonceLength'], + _GCM_TAG_LENGTH) encryption_data = _EncryptionData(encryption_iv, region_info, diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py index 85d2a58bf44f..d9cc47165fa8 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/encryption.py @@ -87,20 +87,20 @@ class _EncryptedRegionInfo: This is only used for Encryption V2. ''' - def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + def __init__(self, data_length, nonce_length, tag_length): ''' - :param int encrypted_region_data_length: + :param int data_length: The length of the encryption region data (not including nonce + tag). :param str nonce_length: The length of nonce used when encrypting. :param int tag_length: The length of the encryption tag. ''' - _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('data_length', data_length) _validate_not_none('nonce_length', nonce_length) _validate_not_none('tag_length', tag_length) - self.encrypted_region_data_length = encrypted_region_data_length + self.data_length = data_length self.nonce_length = nonce_length self.tag_length = tag_length @@ -203,9 +203,8 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH + encrypted_region_info['DataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH - encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key @@ -258,9 +257,9 @@ def _dict_to_encryption_data(encryption_data_dict): region_info = None if 'EncryptedRegionInfo' in encryption_data_dict: encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] - region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], - encrypted_region_info['NonceLength'], - encrypted_region_info['TagLength']) + region_info = _EncryptedRegionInfo(encrypted_region_info['DataLength'], + encrypted_region_info['NonceLength'], + _GCM_TAG_LENGTH) encryption_data = _EncryptionData(encryption_iv, region_info, diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py index 85d2a58bf44f..d9cc47165fa8 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/encryption.py @@ -87,20 +87,20 @@ class _EncryptedRegionInfo: This is only used for Encryption V2. ''' - def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + def __init__(self, data_length, nonce_length, tag_length): ''' - :param int encrypted_region_data_length: + :param int data_length: The length of the encryption region data (not including nonce + tag). :param str nonce_length: The length of nonce used when encrypting. :param int tag_length: The length of the encryption tag. ''' - _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('data_length', data_length) _validate_not_none('nonce_length', nonce_length) _validate_not_none('tag_length', tag_length) - self.encrypted_region_data_length = encrypted_region_data_length + self.data_length = data_length self.nonce_length = nonce_length self.tag_length = tag_length @@ -203,9 +203,8 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH + encrypted_region_info['DataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH - encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key @@ -258,9 +257,9 @@ def _dict_to_encryption_data(encryption_data_dict): region_info = None if 'EncryptedRegionInfo' in encryption_data_dict: encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] - region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], - encrypted_region_info['NonceLength'], - encrypted_region_info['TagLength']) + region_info = _EncryptedRegionInfo(encrypted_region_info['DataLength'], + encrypted_region_info['NonceLength'], + _GCM_TAG_LENGTH) encryption_data = _EncryptionData(encryption_iv, region_info, diff --git a/sdk/storage/azure-storage-queue/CHANGELOG.md b/sdk/storage/azure-storage-queue/CHANGELOG.md index 7b525b6bfb6c..ae539a039954 100644 --- a/sdk/storage/azure-storage-queue/CHANGELOG.md +++ b/sdk/storage/azure-storage-queue/CHANGELOG.md @@ -3,9 +3,11 @@ ## 12.4.0b1 (Unreleased) ### Features Added -- Added a new version of client-side encryption for Queue messages (version 2.0) which utilizes AES-GCM-256 encryption. -If you are currently using client-side encryption, it is **highly recommended** to switch to version 2.0. The encryption -version can be specified on any client constructor via the `encryption_version` keyword (`encryption_version='2.0'`). +- Introduced version 2.0 of client-side encryption for Queue messages which utilizes AES-GCM-256 encryption. +Version 1.0 is now deprecated and no longer considered secure. If you are using client-side encryption, it is +**highly recommended** that you update to version 2.0. +The encryption version can be specified on any client constructor via the `encryption_version` +keyword (i.e. `encryption_version='2.0'`). ## 12.3.0 (2022-05-09) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py index 8f0e4593bb43..3d40078a432d 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_queue_client.py @@ -486,6 +486,7 @@ def send_message( warnings.warn( "TypeError when calling message_encode_policy.configure. \ It is likely missing the encryption_version parameter. \ + Consider updating your encryption information/implementation. \ Retrying without encryption_version." ) self._config.message_encode_policy.configure( @@ -730,8 +731,10 @@ def update_message(self, encryption_version=self.encryption_version) except TypeError: warnings.warn( - "message_encode_policy.configure does not accept encryption_version parameter.", - DeprecationWarning + "TypeError when calling message_encode_policy.configure. \ + It is likely missing the encryption_version parameter. \ + Consider updating your encryption information/implementation. \ + Retrying without encryption_version." ) self._config.message_encode_policy.configure( self.require_encryption, diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py index fa50b1a0780e..e6981534837a 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py @@ -5,6 +5,7 @@ # -------------------------------------------------------------------------- import logging import uuid +import warnings from typing import ( # pylint: disable=unused-import Optional, Any, @@ -107,6 +108,12 @@ def __init__( self.encryption_version = kwargs.get("encryption_version", "1.0") self.key_encryption_key = kwargs.get("key_encryption_key") self.key_resolver_function = kwargs.get("key_resolver_function") + if self.key_encryption_key and self.encryption_version == '1.0': + warnings.warn("This client has been configured to use encryption with version 1.0. \ + Version 1.0 is deprecated and no longer considered secure. It is highly \ + recommended that you switch to using version 2.0. The version can be \ + specified using the 'encryption_version' keyword.") + self._config, self._pipeline = self._create_pipeline(self.credential, storage_sdk=service, **kwargs) def __enter__(self): diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py index 85d2a58bf44f..d9cc47165fa8 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/encryption.py @@ -87,20 +87,20 @@ class _EncryptedRegionInfo: This is only used for Encryption V2. ''' - def __init__(self, encrypted_region_data_length, nonce_length, tag_length): + def __init__(self, data_length, nonce_length, tag_length): ''' - :param int encrypted_region_data_length: + :param int data_length: The length of the encryption region data (not including nonce + tag). :param str nonce_length: The length of nonce used when encrypting. :param int tag_length: The length of the encryption tag. ''' - _validate_not_none('encrypted_region_data_length', encrypted_region_data_length) + _validate_not_none('data_length', data_length) _validate_not_none('nonce_length', nonce_length) _validate_not_none('tag_length', tag_length) - self.encrypted_region_data_length = encrypted_region_data_length + self.data_length = data_length self.nonce_length = nonce_length self.tag_length = tag_length @@ -203,9 +203,8 @@ def _generate_encryption_data_dict(kek, cek, iv, version): encryption_agent['EncryptionAlgorithm'] = _EncryptionAlgorithm.AES_GCM_256 encrypted_region_info = OrderedDict() - encrypted_region_info['EncryptedRegionDataLength'] = _GCM_REGION_DATA_LENGTH + encrypted_region_info['DataLength'] = _GCM_REGION_DATA_LENGTH encrypted_region_info['NonceLength'] = _GCM_NONCE_LENGTH - encrypted_region_info['TagLength'] = _GCM_TAG_LENGTH encryption_data_dict = OrderedDict() encryption_data_dict['WrappedContentKey'] = wrapped_content_key @@ -258,9 +257,9 @@ def _dict_to_encryption_data(encryption_data_dict): region_info = None if 'EncryptedRegionInfo' in encryption_data_dict: encrypted_region_info = encryption_data_dict['EncryptedRegionInfo'] - region_info = _EncryptedRegionInfo(encrypted_region_info['EncryptedRegionDataLength'], - encrypted_region_info['NonceLength'], - encrypted_region_info['TagLength']) + region_info = _EncryptedRegionInfo(encrypted_region_info['DataLength'], + encrypted_region_info['NonceLength'], + _GCM_TAG_LENGTH) encryption_data = _EncryptionData(encryption_iv, region_info, diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py index 47125b2d6f1a..747b3ffd935a 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/aio/_queue_client_async.py @@ -375,6 +375,7 @@ async def send_message( # type: ignore warnings.warn( "TypeError when calling message_encode_policy.configure. \ It is likely missing the encryption_version parameter. \ + Consider updating your encryption information/implementation. \ Retrying without encryption_version." ) self._config.message_encode_policy.configure( @@ -614,8 +615,10 @@ async def update_message( ) except TypeError: warnings.warn( - "message_encode_policy.configure does not accept encryption_version parameter.", - DeprecationWarning + "TypeError when calling message_encode_policy.configure. \ + It is likely missing the encryption_version parameter. \ + Consider updating your encryption information/implementation. \ + Retrying without encryption_version." ) self._config.message_encode_policy.configure( self.require_encryption, diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml index e80f5c210635..8016537b836c 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_kek_v2.yaml @@ -11,9 +11,9 @@ interactions: Content-Length: - '0' User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:06 GMT + - Wed, 08 Jun 2022 20:47:12 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,23 +25,22 @@ interactions: content-length: - '0' date: - - Thu, 19 May 2022 18:51:06 GMT + - Wed, 08 Jun 2022 20:47:12 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: - '2021-02-12' status: - code: 201 - message: Created + code: 204 + message: No Content - request: body: ' - {"EncryptedMessageContents": "E3T4ukeab6hVsYz9c0VKbKDD02Ogw9OvVvERUltFuGHC/89t8JKKYDxKp6Wt34/wCY4=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "XIRlkoc9x6tIaC3HoL4ekUOrf5OT/MDR4BzwUgksctPcUMxAf0/MIQ==", + {"EncryptedMessageContents": "sCK6rsOwH7jOo3V6d3i7E+0C+XLzF+oELrU9lgRzflWQ5LZqVIGXxjzk5QwO+D7QEP8=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "w7flxc3aQCZqCf9kLRe5Syqyrho473dFbnpQkBy3oereJdGgVXpLAg==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -50,28 +49,28 @@ interactions: Connection: - keep-alive Content-Length: - - '594' + - '564' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:06 GMT + - Wed, 08 Jun 2022 20:47:12 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e/messages response: body: - string: "\uFEFFaf147b8c-241e-46cc-bfee-388ae280f233Thu, - 19 May 2022 18:51:06 GMTThu, 26 May 2022 18:51:06 - GMTAgAAAAMAAAAAAAAAT7LSZbFr2AE=Thu, - 19 May 2022 18:51:06 GMT" + string: "\uFEFF0a6f6277-5158-44e8-8cfb-d9111a5ecff9Wed, + 08 Jun 2022 20:47:12 GMTWed, 15 Jun 2022 20:47:12 + GMTAgAAAAMAAAAAAAAA50st7nh72AE=Wed, + 08 Jun 2022 20:47:12 GMT" headers: content-type: - application/xml date: - - Thu, 19 May 2022 18:51:06 GMT + - Wed, 08 Jun 2022 20:47:12 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -91,33 +90,33 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:06 GMT + - Wed, 08 Jun 2022 20:47:12 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue80c1168e/messages?numofmessages=1 response: body: - string: "\uFEFFaf147b8c-241e-46cc-bfee-388ae280f233Thu, - 19 May 2022 18:51:06 GMTThu, 26 May 2022 18:51:06 - GMTAgAAAAMAAAAAAAAAW+y/d7Fr2AE=Thu, - 19 May 2022 18:51:36 GMT1{\"EncryptedMessageContents\": - \"E3T4ukeab6hVsYz9c0VKbKDD02Ogw9OvVvERUltFuGHC/89t8JKKYDxKp6Wt34/wCY4=\", + string: "\uFEFF566fc358-b37a-4246-8919-850cae52af5cWed, + 08 Jun 2022 20:31:19 GMTWed, 15 Jun 2022 20:31:19 + GMTAgAAAAMAAAAAAAAAZmMYAHl72AE=Wed, + 08 Jun 2022 20:47:43 GMT2{\"EncryptedMessageContents\": + \"VxbJPBjyiXmXg+Qsj4dlCvygzQNfL90i/BGE4I5g0l0UjMVGwtonQjH+Yq18EN7utVE=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"XIRlkoc9x6tIaC3HoL4ekUOrf5OT/MDR4BzwUgksctPcUMxAf0/MIQ==\", \"Algorithm\": + \"eFXceOxSdz3CX+btFX0CSXTkKBI9nUbxdZUt0xZh9z8qPQKGMwTfnw==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python + 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Thu, 19 May 2022 18:51:06 GMT + - Wed, 08 Jun 2022 20:47:12 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml index 1f6960ebb731..24dd1c691eb6 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_get_message_encrypted_resolver_v2.yaml @@ -11,9 +11,9 @@ interactions: Content-Length: - '0' User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:13 GMT + - Wed, 08 Jun 2022 20:48:47 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Thu, 19 May 2022 18:51:13 GMT + - Wed, 08 Jun 2022 20:48:47 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,12 +36,11 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "O22FsY56u5vWzpOeudz7R5bQjt/ENv78cTs67AsS33025V1P5zN2/ixal62c3iEoUZc=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "5d1yKp0goG7ktjqO5srexNKBkaZ8QnYSv7zL+gmaRz5MoyGdsustlg==", + {"EncryptedMessageContents": "5MI9+PixaIvSy3XyJfo5E2c50RwDx3BSg3YKkOsFo/N+1emGWWG9Z6g+BUOwlthA/yA=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "/HsNvDGQ8N4+SCic1tHdMvfXft962/onBHZkYhWAp6JUkyxhdlWTFQ==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -50,28 +49,28 @@ interactions: Connection: - keep-alive Content-Length: - - '594' + - '564' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:13 GMT + - Wed, 08 Jun 2022 20:48:47 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5/messages response: body: - string: "\uFEFF1df01551-628e-4f5e-b4d0-90a67833d682Thu, - 19 May 2022 18:51:13 GMTThu, 26 May 2022 18:51:13 - GMTAgAAAAMAAAAAAAAAse7eabFr2AE=Thu, - 19 May 2022 18:51:13 GMT" + string: "\uFEFF9b44db8f-f308-46e8-99e6-280f3079326bWed, + 08 Jun 2022 20:48:47 GMTWed, 15 Jun 2022 20:48:47 + GMTAgAAAAMAAAAAAAAAj9G7Jnl72AE=Wed, + 08 Jun 2022 20:48:47 GMT" headers: content-type: - application/xml date: - - Thu, 19 May 2022 18:51:13 GMT + - Wed, 08 Jun 2022 20:48:47 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -91,33 +90,32 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:13 GMT + - Wed, 08 Jun 2022 20:48:47 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueuef9ea18c5/messages?numofmessages=1 response: body: - string: "\uFEFF1df01551-628e-4f5e-b4d0-90a67833d682Thu, - 19 May 2022 18:51:13 GMTThu, 26 May 2022 18:51:13 - GMTAgAAAAMAAAAAAAAAchfLe7Fr2AE=Thu, - 19 May 2022 18:51:43 GMT1{\"EncryptedMessageContents\": - \"O22FsY56u5vWzpOeudz7R5bQjt/ENv78cTs67AsS33025V1P5zN2/ixal62c3iEoUZc=\", + string: "\uFEFF9b44db8f-f308-46e8-99e6-280f3079326bWed, + 08 Jun 2022 20:48:47 GMTWed, 15 Jun 2022 20:48:47 + GMTAgAAAAMAAAAAAAAAe72oOHl72AE=Wed, + 08 Jun 2022 20:49:17 GMT1{\"EncryptedMessageContents\": + \"5MI9+PixaIvSy3XyJfo5E2c50RwDx3BSg3YKkOsFo/N+1emGWWG9Z6g+BUOwlthA/yA=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"5d1yKp0goG7ktjqO5srexNKBkaZ8QnYSv7zL+gmaRz5MoyGdsustlg==\", \"Algorithm\": + \"/HsNvDGQ8N4+SCic1tHdMvfXft962/onBHZkYhWAp6JUkyxhdlWTFQ==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Thu, 19 May 2022 18:51:13 GMT + - Wed, 08 Jun 2022 20:48:47 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml index b05c395b81e1..f09b0e672f9a 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_binary_message_v2.yaml @@ -11,9 +11,9 @@ interactions: Content-Length: - '0' User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Tue, 31 May 2022 23:25:29 GMT + - Wed, 08 Jun 2022 20:49:20 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,12 +36,11 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "SgO6wmEicLT7tGGBcZ8p3STA/gc2X9DqPQnjp0p8yH3fJbQHSLmQUw==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "Y8CU6GOnhJfRrFhVyU7lhsmHN9YsPDPv8cF4lWVLPfKINQ6l9XdSJQ==", + {"EncryptedMessageContents": "GlHp7dFsQUdqyCMGVAI7DKG62KNutq2dl8+GnJ56a/Kaq+LiHqz1OQ==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "FVdcp57JQ1Yx5MYx4YN5rnGYf5wVHeyngjdtT1s2JDvy1xPHIDqGhQ==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -50,28 +49,28 @@ interactions: Connection: - keep-alive Content-Length: - - '582' + - '552' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages response: body: - string: "\uFEFF72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8Tue, - 31 May 2022 23:25:30 GMTTue, 07 Jun 2022 23:25:30 - GMTAgAAAAMAAAAAAAAAWgrpt0V12AE=Tue, - 31 May 2022 23:25:30 GMT" + string: "\uFEFF6fe22d93-2c72-4bd6-9651-d7df2854deffWed, + 08 Jun 2022 20:49:20 GMTWed, 15 Jun 2022 20:49:20 + GMTAgAAAAMAAAAAAAAAmuk7Onl72AE=Wed, + 08 Jun 2022 20:49:20 GMT" headers: content-type: - application/xml date: - - Tue, 31 May 2022 23:25:29 GMT + - Wed, 08 Jun 2022 20:49:20 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -91,32 +90,31 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages?numofmessages=1 response: body: - string: "\uFEFF72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8Tue, - 31 May 2022 23:25:30 GMTTue, 07 Jun 2022 23:25:30 - GMTAgAAAAMAAAAAAAAAEQzVyUV12AE=Tue, - 31 May 2022 23:26:00 GMT1{\"EncryptedMessageContents\": - \"SgO6wmEicLT7tGGBcZ8p3STA/gc2X9DqPQnjp0p8yH3fJbQHSLmQUw==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"Y8CU6GOnhJfRrFhVyU7lhsmHN9YsPDPv8cF4lWVLPfKINQ6l9XdSJQ==\", + string: "\uFEFF6fe22d93-2c72-4bd6-9651-d7df2854deffWed, + 08 Jun 2022 20:49:20 GMTWed, 15 Jun 2022 20:49:20 + GMTAgAAAAMAAAAAAAAAh64oTHl72AE=Wed, + 08 Jun 2022 20:49:50 GMT1{\"EncryptedMessageContents\": + \"GlHp7dFsQUdqyCMGVAI7DKG62KNutq2dl8+GnJ56a/Kaq+LiHqz1OQ==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"FVdcp57JQ1Yx5MYx4YN5rnGYf5wVHeyngjdtT1s2JDvy1xPHIDqGhQ==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Tue, 31 May 2022 23:25:29 GMT + - Wed, 08 Jun 2022 20:49:20 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -129,12 +127,11 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "RPW2ZZn1bIROwajIJVy059ywW4wofeXdwqgyuj1BAIWBwvH5O0d/Kg==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "MOMFJ8MGblfg098nWLKPYN7USNDgtRzOCFDLaceHVde+h769J8eaiQ==", + {"EncryptedMessageContents": "bBaq3mN8zmmBafnKAcGoLmeWLYuIhmsIW7dRFJn3adUPGT2ulACQqQ==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "EJY3GXw1ZWeUppUKwZ10hd1YEYZ2gUXFXLZYxpZMMWxLFGpaxSYMDg==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -143,17 +140,17 @@ interactions: Connection: - keep-alive Content-Length: - - '582' + - '552' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT x-ms-version: - '2021-02-12' method: PUT - uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages/72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8?popreceipt=AgAAAAMAAAAAAAAAEQzVyUV12AE%3D&visibilitytimeout=0 + uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages/6fe22d93-2c72-4bd6-9651-d7df2854deff?popreceipt=AgAAAAMAAAAAAAAAh64oTHl72AE%3D&visibilitytimeout=0 response: body: string: '' @@ -161,13 +158,13 @@ interactions: content-length: - '0' date: - - Tue, 31 May 2022 23:25:29 GMT + - Wed, 08 Jun 2022 20:49:20 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-popreceipt: - - AwAAAAMAAAAAAAAAVcP/t0V12AEBAAAA + - AwAAAAMAAAAAAAAAR2pROnl72AEBAAAA x-ms-time-next-visible: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT x-ms-version: - '2021-02-12' status: @@ -183,32 +180,31 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue1434191b/messages?numofmessages=1 response: body: - string: "\uFEFF72dc4cc0-bec4-42d8-8eb6-86bbacf1a6d8Tue, - 31 May 2022 23:25:30 GMTTue, 07 Jun 2022 23:25:30 - GMTAgAAAAMAAAAAAAAAJBPsyUV12AE=Tue, - 31 May 2022 23:26:00 GMT2{\"EncryptedMessageContents\": - \"RPW2ZZn1bIROwajIJVy059ywW4wofeXdwqgyuj1BAIWBwvH5O0d/Kg==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"MOMFJ8MGblfg098nWLKPYN7USNDgtRzOCFDLaceHVde+h769J8eaiQ==\", + string: "\uFEFF6fe22d93-2c72-4bd6-9651-d7df2854deffWed, + 08 Jun 2022 20:49:20 GMTWed, 15 Jun 2022 20:49:20 + GMTAgAAAAMAAAAAAAAA9hRBTHl72AE=Wed, + 08 Jun 2022 20:49:50 GMT2{\"EncryptedMessageContents\": + \"bBaq3mN8zmmBafnKAcGoLmeWLYuIhmsIW7dRFJn3adUPGT2ulACQqQ==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"EJY3GXw1ZWeUppUKwZ10hd1YEYZ2gUXFXLZYxpZMMWxLFGpaxSYMDg==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Tue, 31 May 2022 23:25:30 GMT + - Wed, 08 Jun 2022 20:49:20 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml index 142e09f79065..1df63bd973b4 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_update_encrypted_message_v2.yaml @@ -11,9 +11,9 @@ interactions: Content-Length: - '0' User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,12 +36,11 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "QhN6VveqAIg4qjG1Vofe4RaFqfCLvGC9yBbIYBUUrBlkawIS2Q==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "h34o7hhucQOC/Ne3HiPrHOaxh0pvkyiZyUyzgzJPyQSVykLenUSB4Q==", + {"EncryptedMessageContents": "9ygAp6H+6EIUYasZPZdZcCmSPuhDanvsJFnGL9Qt/pjhWnIJvw==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "1aaapOXSk0yVCQV5+0ewAClb8KjfvErH6STQd47MLwGIYnskscnFzw==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -50,28 +49,28 @@ interactions: Connection: - keep-alive Content-Length: - - '578' + - '548' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages response: body: - string: "\uFEFF6eed6f93-76f4-4293-b0bb-250b6d4e314aThu, - 19 May 2022 18:51:21 GMTThu, 26 May 2022 18:51:21 - GMTAgAAAAMAAAAAAAAAHZDMbrFr2AE=Thu, - 19 May 2022 18:51:21 GMT" + string: "\uFEFF2f6c8bef-7184-4889-92e7-7efbd6b805c7Wed, + 08 Jun 2022 20:49:13 GMTWed, 15 Jun 2022 20:49:13 + GMTAgAAAAMAAAAAAAAAudYCNnl72AE=Wed, + 08 Jun 2022 20:49:13 GMT" headers: content-type: - application/xml date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -91,32 +90,31 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages?numofmessages=1 response: body: - string: "\uFEFF6eed6f93-76f4-4293-b0bb-250b6d4e314aThu, - 19 May 2022 18:51:21 GMTThu, 26 May 2022 18:51:21 - GMTAgAAAAMAAAAAAAAARBi6gLFr2AE=Thu, - 19 May 2022 18:51:52 GMT1{\"EncryptedMessageContents\": - \"QhN6VveqAIg4qjG1Vofe4RaFqfCLvGC9yBbIYBUUrBlkawIS2Q==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"h34o7hhucQOC/Ne3HiPrHOaxh0pvkyiZyUyzgzJPyQSVykLenUSB4Q==\", + string: "\uFEFF2f6c8bef-7184-4889-92e7-7efbd6b805c7Wed, + 08 Jun 2022 20:49:13 GMTWed, 15 Jun 2022 20:49:13 + GMTAgAAAAMAAAAAAAAAZtjuR3l72AE=Wed, + 08 Jun 2022 20:49:43 GMT1{\"EncryptedMessageContents\": + \"9ygAp6H+6EIUYasZPZdZcCmSPuhDanvsJFnGL9Qt/pjhWnIJvw==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"1aaapOXSk0yVCQV5+0ewAClb8KjfvErH6STQd47MLwGIYnskscnFzw==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -129,12 +127,11 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "vahQtIo3YQpazOCCOhzHaJZ3Ly/Ralhj6lCQhYN0ixNS/HM=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "EB4xgA5rns3W8gqRpnonBwko3D3J3WykqgCNoeg3zGhYTCzL1TK5zg==", + {"EncryptedMessageContents": "EAsjZ+nZRmcXtzQ+rvQljYSGzosSDjYyUfGwDGMAsQ3CQy4=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "pEyzHAK3yJVRjMiMMHDaBS4zciJMGg3XjqOKoH2xu2zbkA5NYTlPpw==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -143,17 +140,17 @@ interactions: Connection: - keep-alive Content-Length: - - '574' + - '544' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:22 GMT + - Wed, 08 Jun 2022 20:49:13 GMT x-ms-version: - '2021-02-12' method: PUT - uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages/6eed6f93-76f4-4293-b0bb-250b6d4e314a?popreceipt=AgAAAAMAAAAAAAAARBi6gLFr2AE%3D&visibilitytimeout=0 + uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages/2f6c8bef-7184-4889-92e7-7efbd6b805c7?popreceipt=AgAAAAMAAAAAAAAAZtjuR3l72AE%3D&visibilitytimeout=0 response: body: string: '' @@ -161,13 +158,13 @@ interactions: content-length: - '0' date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-popreceipt: - - AwAAAAMAAAAAAAAAWTPkbrFr2AEBAAAA + - AwAAAAMAAAAAAAAAeswYNnl72AEBAAAA x-ms-time-next-visible: - - Thu, 19 May 2022 18:51:22 GMT + - Wed, 08 Jun 2022 20:49:13 GMT x-ms-version: - '2021-02-12' status: @@ -183,32 +180,31 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:22 GMT + - Wed, 08 Jun 2022 20:49:13 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue6bbb1637/messages?numofmessages=1 response: body: - string: "\uFEFF6eed6f93-76f4-4293-b0bb-250b6d4e314aThu, - 19 May 2022 18:51:21 GMTThu, 26 May 2022 18:51:21 - GMTAgAAAAMAAAAAAAAAAg7QgLFr2AE=Thu, - 19 May 2022 18:51:52 GMT2{\"EncryptedMessageContents\": - \"vahQtIo3YQpazOCCOhzHaJZ3Ly/Ralhj6lCQhYN0ixNS/HM=\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"EB4xgA5rns3W8gqRpnonBwko3D3J3WykqgCNoeg3zGhYTCzL1TK5zg==\", + string: "\uFEFF2f6c8bef-7184-4889-92e7-7efbd6b805c7Wed, + 08 Jun 2022 20:49:13 GMTWed, 15 Jun 2022 20:49:13 + GMTAgAAAAMAAAAAAAAA7LwDSHl72AE=Wed, + 08 Jun 2022 20:49:43 GMT2{\"EncryptedMessageContents\": + \"EAsjZ+nZRmcXtzQ+rvQljYSGzosSDjYyUfGwDGMAsQ3CQy4=\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"pEyzHAK3yJVRjMiMMHDaBS4zciJMGg3XjqOKoH2xu2zbkA5NYTlPpw==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Thu, 19 May 2022 18:51:21 GMT + - Wed, 08 Jun 2022 20:49:13 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml index 4af9a11584a4..636ee2223e97 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption.test_validate_encryption_v2.yaml @@ -11,9 +11,9 @@ interactions: Content-Length: - '0' User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:28 GMT + - Wed, 08 Jun 2022 20:59:40 GMT x-ms-version: - '2021-02-12' method: PUT @@ -25,7 +25,7 @@ interactions: content-length: - '0' date: - - Thu, 19 May 2022 18:51:28 GMT + - Wed, 08 Jun 2022 20:59:40 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -36,12 +36,11 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "TW0KXP7iPilhFkyATnyeBzPefISC6GKCTW87k2YtUDOhiKhCo3heBOkU2tYWws0aFUI=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "KfM6hR89EAb3m44zFFLSEvpB5pn1p5f0hbN+CeyarMx6ijuDgTACwg==", + {"EncryptedMessageContents": "gHowF2FSDOJtR5akkHSBEkwVFbCTF/ZNpwG/+6sl8WjcbKo8Bh0qXJO+U3lsMat9R4Y=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "fZGnKuWBECjqOwliRvJpB+5e0i/SbnN7T26q/9gFrIFg1JeYWgrCLQ==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml @@ -50,28 +49,28 @@ interactions: Connection: - keep-alive Content-Length: - - '594' + - '564' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:28 GMT + - Wed, 08 Jun 2022 20:59:41 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueueff191437/messages response: body: - string: "\uFEFF37a2248f-010b-4c9a-b701-6808057cec56Thu, - 19 May 2022 18:51:28 GMTThu, 26 May 2022 18:51:28 - GMTAgAAAAMAAAAAAAAAVCumcrFr2AE=Thu, - 19 May 2022 18:51:28 GMT" + string: "\uFEFF523d65b6-047e-4751-a662-1bcd85a8c330Wed, + 08 Jun 2022 20:59:41 GMTWed, 15 Jun 2022 20:59:41 + GMTAgAAAAMAAAAAAAAAdUFCrHp72AE=Wed, + 08 Jun 2022 20:59:41 GMT" headers: content-type: - application/xml date: - - Thu, 19 May 2022 18:51:28 GMT + - Wed, 08 Jun 2022 20:59:40 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -91,33 +90,32 @@ interactions: Connection: - keep-alive User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 18:51:28 GMT + - Wed, 08 Jun 2022 20:59:41 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueueff191437/messages?numofmessages=1 response: body: - string: "\uFEFF37a2248f-010b-4c9a-b701-6808057cec56Thu, - 19 May 2022 18:51:28 GMTThu, 26 May 2022 18:51:28 - GMTAgAAAAMAAAAAAAAADlSShLFr2AE=Thu, - 19 May 2022 18:51:58 GMT1{\"EncryptedMessageContents\": - \"TW0KXP7iPilhFkyATnyeBzPefISC6GKCTW87k2YtUDOhiKhCo3heBOkU2tYWws0aFUI=\", + string: "\uFEFF523d65b6-047e-4751-a662-1bcd85a8c330Wed, + 08 Jun 2022 20:59:41 GMTWed, 15 Jun 2022 20:59:41 + GMTAgAAAAMAAAAAAAAAPWouvnp72AE=Wed, + 08 Jun 2022 21:00:11 GMT1{\"EncryptedMessageContents\": + \"gHowF2FSDOJtR5akkHSBEkwVFbCTF/ZNpwG/+6sl8WjcbKo8Bh0qXJO+U3lsMat9R4Y=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"KfM6hR89EAb3m44zFFLSEvpB5pn1p5f0hbN+CeyarMx6ijuDgTACwg==\", \"Algorithm\": + \"fZGnKuWBECjqOwliRvJpB+5e0i/SbnN7T26q/9gFrIFg1JeYWgrCLQ==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: - no-cache content-type: - application/xml date: - - Thu, 19 May 2022 18:51:28 GMT + - Wed, 08 Jun 2022 20:59:40 GMT server: - Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml index 6364da44de25..85ca9c77c985 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_kek_v2.yaml @@ -5,9 +5,9 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:19 GMT + - Wed, 08 Jun 2022 21:45:19 GMT x-ms-version: - '2021-02-12' method: PUT @@ -17,7 +17,7 @@ interactions: string: '' headers: content-length: '0' - date: Thu, 19 May 2022 01:00:19 GMT + date: Wed, 08 Jun 2022 21:45:18 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: '2021-02-12' status: @@ -27,36 +27,35 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "uLBuNGG6qQEuOIJd3wntSh6/nzcGiwPlPhNDUu6jJagbdtiecLc0M0d5j0hq93EbPJM=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "gCtdxVuhFGW6SKuoCxR/UClrH3EHgvilAClPfhLQ/pm+eV0uvJXXCA==", + {"EncryptedMessageContents": "ZnXZjKfH33JLOL16FGhVdkBqQBfV20wLzRh0ES1ghDGq1CtFW13dd1kG7724M+G30Yg=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "TiCJNso/+7tAsfAkLhyp/6DcPKCrj3Ernz96sDYDGyIZuehLJ45uqQ==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '594' + - '564' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:19 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue1399190b/messages response: body: - string: "\uFEFF80ea2ce8-be91-4d48-981b-aa0be666c325Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAA/ePCzxtr2AE=Thu, - 19 May 2022 01:00:20 GMT" + string: "\uFEFF20f21e13-8f01-49a7-a778-a182dd654383Wed, + 08 Jun 2022 21:45:19 GMTWed, 15 Jun 2022 21:45:19 + GMTAgAAAAMAAAAAAAAAp92DDIF72AE=Wed, + 08 Jun 2022 21:45:19 GMT" headers: content-type: application/xml - date: Thu, 19 May 2022 01:00:19 GMT + date: Wed, 08 Jun 2022 21:45:18 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -70,30 +69,29 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:19 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue1399190b/messages?numofmessages=1 response: body: - string: "\uFEFF80ea2ce8-be91-4d48-981b-aa0be666c325Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAA69ir4Rtr2AE=Thu, - 19 May 2022 01:00:50 GMT1{\"EncryptedMessageContents\": - \"uLBuNGG6qQEuOIJd3wntSh6/nzcGiwPlPhNDUu6jJagbdtiecLc0M0d5j0hq93EbPJM=\", + string: "\uFEFF20f21e13-8f01-49a7-a778-a182dd654383Wed, + 08 Jun 2022 21:45:19 GMTWed, 15 Jun 2022 21:45:19 + GMTAgAAAAMAAAAAAAAAx5VtHoF72AE=Wed, + 08 Jun 2022 21:45:49 GMT1{\"EncryptedMessageContents\": + \"ZnXZjKfH33JLOL16FGhVdkBqQBfV20wLzRh0ES1ghDGq1CtFW13dd1kG7724M+G30Yg=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"gCtdxVuhFGW6SKuoCxR/UClrH3EHgvilAClPfhLQ/pm+eV0uvJXXCA==\", \"Algorithm\": + \"TiCJNso/+7tAsfAkLhyp/6DcPKCrj3Ernz96sDYDGyIZuehLJ45uqQ==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Thu, 19 May 2022 01:00:19 GMT + date: Wed, 08 Jun 2022 21:45:18 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml index 6d92afc11355..ced6792e5475 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_get_message_encrypted_resolver_v2.yaml @@ -5,9 +5,9 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:19 GMT x-ms-version: - '2021-02-12' method: PUT @@ -17,7 +17,7 @@ interactions: string: '' headers: content-length: '0' - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:19 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: '2021-02-12' status: @@ -27,36 +27,35 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "V4LMKSSg3MaHErdJ7D5C6FrO+cMJRpD4B3cN98AHvcx1e8IPgDXbvAyM7lfsy1tYDeI=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "nGBJ1BtjaTN+gfv0FZR4jjiC4BhWb6+L+QJqsExaczQqUZPP/sqPzg==", + {"EncryptedMessageContents": "hKYLs8Xeur7VwEXDpwyXPMk7hl0DGEbh6dmpT8QJnKybGptljHxRj31TuoeT8E5PTCY=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "bolP5f9LyxA0ISg+uzt6fmuPyWyykbRJs41OXgNf9fy1bYLo/nzb0g==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '594' + - '564' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue99331b42/messages response: body: - string: "\uFEFF3541ef37-698b-4c51-8fc1-d35df0d0dca4Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAAhyH2zxtr2AE=Thu, - 19 May 2022 01:00:20 GMT" + string: "\uFEFF91500197-480e-4cf8-b017-ac64ca059a94Wed, + 08 Jun 2022 21:45:20 GMTWed, 15 Jun 2022 21:45:20 + GMTAgAAAAMAAAAAAAAAwou5DIF72AE=Wed, + 08 Jun 2022 21:45:20 GMT" headers: content-type: application/xml - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:19 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -70,30 +69,29 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue99331b42/messages?numofmessages=1 response: body: - string: "\uFEFF3541ef37-698b-4c51-8fc1-d35df0d0dca4Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAAhT3f4Rtr2AE=Thu, - 19 May 2022 01:00:50 GMT1{\"EncryptedMessageContents\": - \"V4LMKSSg3MaHErdJ7D5C6FrO+cMJRpD4B3cN98AHvcx1e8IPgDXbvAyM7lfsy1tYDeI=\", + string: "\uFEFF91500197-480e-4cf8-b017-ac64ca059a94Wed, + 08 Jun 2022 21:45:20 GMTWed, 15 Jun 2022 21:45:20 + GMTAgAAAAMAAAAAAAAA+JGjHoF72AE=Wed, + 08 Jun 2022 21:45:50 GMT1{\"EncryptedMessageContents\": + \"hKYLs8Xeur7VwEXDpwyXPMk7hl0DGEbh6dmpT8QJnKybGptljHxRj31TuoeT8E5PTCY=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"nGBJ1BtjaTN+gfv0FZR4jjiC4BhWb6+L+QJqsExaczQqUZPP/sqPzg==\", \"Algorithm\": + \"bolP5f9LyxA0ISg+uzt6fmuPyWyykbRJs41OXgNf9fy1bYLo/nzb0g==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:19 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml index e5e1d421e203..9c07eee48c70 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_binary_message_v2.yaml @@ -5,9 +5,9 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:46:27 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: PUT @@ -17,7 +17,7 @@ interactions: string: '' headers: content-length: '0' - date: Tue, 31 May 2022 23:46:27 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: '2021-02-12' status: @@ -27,36 +27,35 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "AaCNHJJV1gEDzpCLL6VC37/NbG8UA3dpiEBVL7n1vH5OCBb/6i9s1A==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "2d2mrpU3bjAwpCMm7jYlHTwmty+7QOSus0d2yb5hAdHR9bBCyd0Q9g==", + {"EncryptedMessageContents": "3qvP8kUyyDHOdxIztlirqT2dll3dqtpNRXSE8DqxOfb2owUbchgyig==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "jjZ4j+JiQiV0X7Q3na29Bo7pIJmRCbe3VBfwdgCG9GwSX/+wG5Xtrw==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '582' + - '552' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:46:28 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages response: body: - string: "\uFEFFf4b39a5f-ecae-4aa8-8ab5-46e4f372ce10Tue, - 31 May 2022 23:46:28 GMTTue, 07 Jun 2022 23:46:28 - GMTAgAAAAMAAAAAAAAAfkuLpUh12AE=Tue, - 31 May 2022 23:46:28 GMT" + string: "\uFEFFe4a389d3-824d-4c1a-b60a-7b43f5042f36Wed, + 08 Jun 2022 21:45:20 GMTWed, 15 Jun 2022 21:45:20 + GMTAgAAAAMAAAAAAAAAP5nwDIF72AE=Wed, + 08 Jun 2022 21:45:20 GMT" headers: content-type: application/xml - date: Tue, 31 May 2022 23:46:27 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -70,29 +69,28 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:46:28 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages?numofmessages=1 response: body: - string: "\uFEFFf4b39a5f-ecae-4aa8-8ab5-46e4f372ce10Tue, - 31 May 2022 23:46:28 GMTTue, 07 Jun 2022 23:46:28 - GMTAgAAAAMAAAAAAAAAfDd4t0h12AE=Tue, - 31 May 2022 23:46:58 GMT1{\"EncryptedMessageContents\": - \"AaCNHJJV1gEDzpCLL6VC37/NbG8UA3dpiEBVL7n1vH5OCBb/6i9s1A==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"2d2mrpU3bjAwpCMm7jYlHTwmty+7QOSus0d2yb5hAdHR9bBCyd0Q9g==\", + string: "\uFEFFe4a389d3-824d-4c1a-b60a-7b43f5042f36Wed, + 08 Jun 2022 21:45:20 GMTWed, 15 Jun 2022 21:45:20 + GMTAgAAAAMAAAAAAAAAXVHaHoF72AE=Wed, + 08 Jun 2022 21:45:50 GMT1{\"EncryptedMessageContents\": + \"3qvP8kUyyDHOdxIztlirqT2dll3dqtpNRXSE8DqxOfb2owUbchgyig==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"jjZ4j+JiQiV0X7Q3na29Bo7pIJmRCbe3VBfwdgCG9GwSX/+wG5Xtrw==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Tue, 31 May 2022 23:46:27 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -103,70 +101,68 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "zlOxd9T7vJ9fG4OrPcuM8Fd0ebwEtNFMyqgteD5OziTz0pQD9tNj0A==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "e+7lnlMRfi4GMV9T+WCBYVC7KX9dDuyEE0Fo/08pbjyj2krZLGVGXw==", + {"EncryptedMessageContents": "0CL4mt9PVIkIL4gyu5NNRhNc17pFI93g3orZ+9gskGNQXGp2LOstRg==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "82uC2JYD0f65MNQ1yzi7T7fMLy/J3bEMj1ZXyvyhGbOUTTH0yDl0aA==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '582' + - '552' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:46:28 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: PUT - uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages/f4b39a5f-ecae-4aa8-8ab5-46e4f372ce10?popreceipt=AgAAAAMAAAAAAAAAfDd4t0h12AE%3D&visibilitytimeout=0 + uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages/e4a389d3-824d-4c1a-b60a-7b43f5042f36?popreceipt=AgAAAAMAAAAAAAAAXVHaHoF72AE%3D&visibilitytimeout=0 response: body: string: '' headers: content-length: '0' - date: Tue, 31 May 2022 23:46:27 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 - x-ms-popreceipt: AwAAAAMAAAAAAAAAuO6ipUh12AEBAAAA - x-ms-time-next-visible: Tue, 31 May 2022 23:46:28 GMT + x-ms-popreceipt: AwAAAAMAAAAAAAAAroYBDYF72AEBAAAA + x-ms-time-next-visible: Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: '2021-02-12' status: code: 204 message: No Content - url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98/messages/f4b39a5f-ecae-4aa8-8ab5-46e4f372ce10?popreceipt=AgAAAAMAAAAAAAAAfDd4t0h12AE%3D&visibilitytimeout=0 + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueueb5eb1b98/messages/e4a389d3-824d-4c1a-b60a-7b43f5042f36?popreceipt=AgAAAAMAAAAAAAAAXVHaHoF72AE%3D&visibilitytimeout=0 - request: body: null headers: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Tue, 31 May 2022 23:46:28 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueueb5eb1b98/messages?numofmessages=1 response: body: - string: "\uFEFFf4b39a5f-ecae-4aa8-8ab5-46e4f372ce10Tue, - 31 May 2022 23:46:28 GMTTue, 07 Jun 2022 23:46:28 - GMTAgAAAAMAAAAAAAAAMX+Vt0h12AE=Tue, - 31 May 2022 23:46:58 GMT2{\"EncryptedMessageContents\": - \"zlOxd9T7vJ9fG4OrPcuM8Fd0ebwEtNFMyqgteD5OziTz0pQD9tNj0A==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"e+7lnlMRfi4GMV9T+WCBYVC7KX9dDuyEE0Fo/08pbjyj2krZLGVGXw==\", + string: "\uFEFFe4a389d3-824d-4c1a-b60a-7b43f5042f36Wed, + 08 Jun 2022 21:45:20 GMTWed, 15 Jun 2022 21:45:20 + GMTAgAAAAMAAAAAAAAAxhfrHoF72AE=Wed, + 08 Jun 2022 21:45:50 GMT2{\"EncryptedMessageContents\": + \"0CL4mt9PVIkIL4gyu5NNRhNc17pFI93g3orZ+9gskGNQXGp2LOstRg==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"82uC2JYD0f65MNQ1yzi7T7fMLy/J3bEMj1ZXyvyhGbOUTTH0yDl0aA==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Tue, 31 May 2022 23:46:27 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml index 362ce8b103cd..6ec587595551 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_update_encrypted_message_v2.yaml @@ -5,9 +5,9 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: PUT @@ -17,7 +17,7 @@ interactions: string: '' headers: content-length: '0' - date: Thu, 19 May 2022 01:00:19 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: '2021-02-12' status: @@ -27,36 +27,35 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "PFeC6fjF8gaPXMUB70Z3HslvgPB7q+3L1qjOd4Va4HrqgODwAw==", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "cNmXaFo4CCk5AjXzm4evZke/4eSiAwl0Hbit9CCz4ghuFP0HeYLmFg==", + {"EncryptedMessageContents": "LQujhYs/Sq2RXwc29wxSngGuODSyHbiFCZ5bTAsrQs7wqc3byw==", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "GpRyVvWBjWmO1HgYGuh712m8fBTVejvGTM/Wsi7vR0ujtzpr0nXspw==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '578' + - '548' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:20 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages response: body: - string: "\uFEFF76b3b8c2-7ad2-46e6-ac93-48f1c1446e69Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAAwCYo0Btr2AE=Thu, - 19 May 2022 01:00:20 GMT" + string: "\uFEFFe1a9a4cb-1eb9-4e5d-b245-28aa6923a55bWed, + 08 Jun 2022 21:45:21 GMTWed, 15 Jun 2022 21:45:21 + GMTAgAAAAMAAAAAAAAAZa41DYF72AE=Wed, + 08 Jun 2022 21:45:21 GMT" headers: content-type: application/xml - date: Thu, 19 May 2022 01:00:19 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -70,29 +69,28 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages?numofmessages=1 response: body: - string: "\uFEFF76b3b8c2-7ad2-46e6-ac93-48f1c1446e69Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAA7H4Z4htr2AE=Thu, - 19 May 2022 01:00:50 GMT1{\"EncryptedMessageContents\": - \"PFeC6fjF8gaPXMUB70Z3HslvgPB7q+3L1qjOd4Va4HrqgODwAw==\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"cNmXaFo4CCk5AjXzm4evZke/4eSiAwl0Hbit9CCz4ghuFP0HeYLmFg==\", + string: "\uFEFFe1a9a4cb-1eb9-4e5d-b245-28aa6923a55bWed, + 08 Jun 2022 21:45:21 GMTWed, 15 Jun 2022 21:45:21 + GMTAgAAAAMAAAAAAAAAVfEeH4F72AE=Wed, + 08 Jun 2022 21:45:51 GMT1{\"EncryptedMessageContents\": + \"LQujhYs/Sq2RXwc29wxSngGuODSyHbiFCZ5bTAsrQs7wqc3byw==\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"GpRyVvWBjWmO1HgYGuh712m8fBTVejvGTM/Wsi7vR0ujtzpr0nXspw==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -103,70 +101,68 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "eVsLrQTkmmx3/KVv0KIqEXSaX6vbQTcN+YNWgeTWIJpS81A=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "2BO5GkR7F3fG80brOOeOwxh/lo02EnwfISlAMmeLNkkZ2at2twvzaQ==", + {"EncryptedMessageContents": "pqbonwgtnBXsW1XD01XVDoWVAodNx2v4vWqSDgGUz7b2Bjg=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "/ISWkIbCvQHpNgdai4KctrCMcrKcgAMu1BvUcpDLE/8mnMSQO40CpA==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '574' + - '544' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: - '2021-02-12' method: PUT - uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages/76b3b8c2-7ad2-46e6-ac93-48f1c1446e69?popreceipt=AgAAAAMAAAAAAAAA7H4Z4htr2AE%3D&visibilitytimeout=0 + uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages/e1a9a4cb-1eb9-4e5d-b245-28aa6923a55b?popreceipt=AgAAAAMAAAAAAAAAVfEeH4F72AE%3D&visibilitytimeout=0 response: body: string: '' headers: content-length: '0' - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 - x-ms-popreceipt: AwAAAAMAAAAAAAAAS9tA0Btr2AEBAAAA - x-ms-time-next-visible: Thu, 19 May 2022 01:00:20 GMT + x-ms-popreceipt: AwAAAAMAAAAAAAAAkLFFDYF72AEBAAAA + x-ms-time-next-visible: Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: '2021-02-12' status: code: 204 message: No Content - url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4/messages/76b3b8c2-7ad2-46e6-ac93-48f1c1446e69?popreceipt=AgAAAAMAAAAAAAAA7H4Z4htr2AE%3D&visibilitytimeout=0 + url: https://jalauzoncanary.queue.core.windows.net/encryptionqueuefc0718b4/messages/e1a9a4cb-1eb9-4e5d-b245-28aa6923a55b?popreceipt=AgAAAAMAAAAAAAAAVfEeH4F72AE%3D&visibilitytimeout=0 - request: body: null headers: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:20 GMT + - Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueuefc0718b4/messages?numofmessages=1 response: body: - string: "\uFEFF76b3b8c2-7ad2-46e6-ac93-48f1c1446e69Thu, - 19 May 2022 01:00:20 GMTThu, 26 May 2022 01:00:20 - GMTAgAAAAMAAAAAAAAAcJMq4htr2AE=Thu, - 19 May 2022 01:00:51 GMT2{\"EncryptedMessageContents\": - \"eVsLrQTkmmx3/KVv0KIqEXSaX6vbQTcN+YNWgeTWIJpS81A=\", \"EncryptionData\": - {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"2BO5GkR7F3fG80brOOeOwxh/lo02EnwfISlAMmeLNkkZ2at2twvzaQ==\", + string: "\uFEFFe1a9a4cb-1eb9-4e5d-b245-28aa6923a55bWed, + 08 Jun 2022 21:45:21 GMTWed, 15 Jun 2022 21:45:21 + GMTAgAAAAMAAAAAAAAAm/QuH4F72AE=Wed, + 08 Jun 2022 21:45:51 GMT2{\"EncryptedMessageContents\": + \"pqbonwgtnBXsW1XD01XVDoWVAodNx2v4vWqSDgGUz7b2Bjg=\", \"EncryptionData\": + {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": \"/ISWkIbCvQHpNgdai4KctrCMcrKcgAMu1BvUcpDLE/8mnMSQO40CpA==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:20 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' diff --git a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml index dbd7b4993f47..c3eb19314282 100644 --- a/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml +++ b/sdk/storage/azure-storage-queue/tests/recordings/test_queue_encryption_async.test_validate_encryption_v2.yaml @@ -5,9 +5,9 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:21 GMT + - Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: - '2021-02-12' method: PUT @@ -17,7 +17,7 @@ interactions: string: '' headers: content-length: '0' - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:21 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: '2021-02-12' status: @@ -27,36 +27,35 @@ interactions: - request: body: ' - {"EncryptedMessageContents": "T/cvNkyRHKCiO8pH54fAQefSktJFh8vM9w5ji5D5GG3KMOZkLHDB7rp7rCe3AmkFg94=", - "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "inxs+p2MHYWDKKw+3BmYh1DMSGvI4+lB81rxomHLPvJysqmpiu1g8w==", + {"EncryptedMessageContents": "XxPeA9/f7kcSY4v/jpSl/Y0VrqzLpRC3H91U6yy8klcPa+EHxGW1tcbr+oyWW2uy9Lw=", + "EncryptionData": {"WrappedContentKey": {"KeyId": "key1", "EncryptedKey": "fy3tHqM7SNZhYV02jYLMAgV/D8Ys6Vsw5/sIySKQegaaUSX6AXZrWw==", "Algorithm": "A256KW"}, "EncryptionAgent": {"Protocol": "2.0", "EncryptionAlgorithm": - "AES_GCM_256"}, "EncryptedRegionInfo": {"EncryptedRegionDataLength": 4194304, - "NonceLength": 12, "TagLength": 16}, "KeyWrappingMetadata": {"EncryptionLibrary": - "Python 12.3.1"}}}' + "AES_GCM_256"}, "EncryptedRegionInfo": {"DataLength": 4194304, "NonceLength": + 12}, "KeyWrappingMetadata": {"EncryptionLibrary": "Python 12.4.0b1"}}}' headers: Accept: - application/xml Content-Length: - - '594' + - '564' Content-Type: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:21 GMT + - Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: - '2021-02-12' method: POST uri: https://storagename.queue.core.windows.net/encryptionqueue830316b4/messages response: body: - string: "\uFEFF302a481a-775b-48df-819c-8841d1ca1f3dThu, - 19 May 2022 01:00:21 GMTThu, 26 May 2022 01:00:21 - GMTAgAAAAMAAAAAAAAAplVz0Btr2AE=Thu, - 19 May 2022 01:00:21 GMT" + string: "\uFEFF467f6a9d-6ea0-4f72-84ef-33cc1d6d42e5Wed, + 08 Jun 2022 21:45:21 GMTWed, 15 Jun 2022 21:45:21 + GMTAgAAAAMAAAAAAAAAk+p6DYF72AE=Wed, + 08 Jun 2022 21:45:21 GMT" headers: content-type: application/xml - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:21 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' @@ -70,30 +69,29 @@ interactions: Accept: - application/xml User-Agent: - - azsdk-python-storage-queue/12.3.1 Python/3.10.4 (Windows-10-10.0.17763-SP0) + - azsdk-python-storage-queue/12.4.0b1 Python/3.10.4 (Windows-10-10.0.17763-SP0) x-ms-date: - - Thu, 19 May 2022 01:00:21 GMT + - Wed, 08 Jun 2022 21:45:21 GMT x-ms-version: - '2021-02-12' method: GET uri: https://storagename.queue.core.windows.net/encryptionqueue830316b4/messages?numofmessages=1 response: body: - string: "\uFEFF302a481a-775b-48df-819c-8841d1ca1f3dThu, - 19 May 2022 01:00:21 GMTThu, 26 May 2022 01:00:21 - GMTAgAAAAMAAAAAAAAAtL9c4htr2AE=Thu, - 19 May 2022 01:00:51 GMT1{\"EncryptedMessageContents\": - \"T/cvNkyRHKCiO8pH54fAQefSktJFh8vM9w5ji5D5GG3KMOZkLHDB7rp7rCe3AmkFg94=\", + string: "\uFEFF467f6a9d-6ea0-4f72-84ef-33cc1d6d42e5Wed, + 08 Jun 2022 21:45:21 GMTWed, 15 Jun 2022 21:45:21 + GMTAgAAAAMAAAAAAAAAii1kH4F72AE=Wed, + 08 Jun 2022 21:45:51 GMT1{\"EncryptedMessageContents\": + \"XxPeA9/f7kcSY4v/jpSl/Y0VrqzLpRC3H91U6yy8klcPa+EHxGW1tcbr+oyWW2uy9Lw=\", \"EncryptionData\": {\"WrappedContentKey\": {\"KeyId\": \"key1\", \"EncryptedKey\": - \"inxs+p2MHYWDKKw+3BmYh1DMSGvI4+lB81rxomHLPvJysqmpiu1g8w==\", \"Algorithm\": + \"fy3tHqM7SNZhYV02jYLMAgV/D8Ys6Vsw5/sIySKQegaaUSX6AXZrWw==\", \"Algorithm\": \"A256KW\"}, \"EncryptionAgent\": {\"Protocol\": \"2.0\", \"EncryptionAlgorithm\": - \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"EncryptedRegionDataLength\": - 4194304, \"NonceLength\": 12, \"TagLength\": 16}, \"KeyWrappingMetadata\": - {\"EncryptionLibrary\": \"Python 12.3.1\"}}}" + \"AES_GCM_256\"}, \"EncryptedRegionInfo\": {\"DataLength\": 4194304, \"NonceLength\": + 12}, \"KeyWrappingMetadata\": {\"EncryptionLibrary\": \"Python 12.4.0b1\"}}}" headers: cache-control: no-cache content-type: application/xml - date: Thu, 19 May 2022 01:00:20 GMT + date: Wed, 08 Jun 2022 21:45:21 GMT server: Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: chunked x-ms-version: '2021-02-12' diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py index 46cf7249a4f0..f7535b5e4081 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption.py @@ -634,10 +634,10 @@ def test_validate_encryption_v2(self, storage_account_name, storage_account_key) encrypted_region_info = encryption_data['EncryptedRegionInfo'] encrypted_region_info = _EncryptedRegionInfo( - encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['DataLength'], encrypted_region_info['NonceLength'], - encrypted_region_info['TagLength']) - self.assertEqual(_GCM_REGION_DATA_LENGTH, encrypted_region_info.encrypted_region_data_length) + _GCM_TAG_LENGTH) + self.assertEqual(_GCM_REGION_DATA_LENGTH, encrypted_region_info.data_length) self.assertEqual(_GCM_NONCE_LENGTH, encrypted_region_info.nonce_length) self.assertEqual(_GCM_TAG_LENGTH, encrypted_region_info.tag_length) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py index 9c63d452d412..8779e3365ad9 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_encryption_async.py @@ -91,6 +91,7 @@ async def _create_queue(self, qsc, prefix=TEST_QUEUE_PREFIX, **kwargs): pass return queue # -------------------------------------------------------------------------- + @QueuePreparer() @AsyncStorageTestCase.await_prepared_test async def test_get_messages_encrypted_kek(self, storage_account_name, storage_account_key): @@ -691,10 +692,10 @@ async def test_validate_encryption_v2(self, storage_account_name, storage_accoun encrypted_region_info = encryption_data['EncryptedRegionInfo'] encrypted_region_info = _EncryptedRegionInfo( - encrypted_region_info['EncryptedRegionDataLength'], + encrypted_region_info['DataLength'], encrypted_region_info['NonceLength'], - encrypted_region_info['TagLength']) - self.assertEqual(_GCM_REGION_DATA_LENGTH, encrypted_region_info.encrypted_region_data_length) + _GCM_TAG_LENGTH) + self.assertEqual(_GCM_REGION_DATA_LENGTH, encrypted_region_info.data_length) self.assertEqual(_GCM_NONCE_LENGTH, encrypted_region_info.nonce_length) self.assertEqual(_GCM_TAG_LENGTH, encrypted_region_info.tag_length)