4040
4141_ENCRYPTION_PROTOCOL_V1 = '1.0'
4242_ENCRYPTION_PROTOCOL_V2 = '2.0'
43+ _ENCRYPTION_PROTOCOL_V2_1 = '2.1'
44+ _VALID_ENCRYPTION_PROTOCOLS = [_ENCRYPTION_PROTOCOL_V1 , _ENCRYPTION_PROTOCOL_V2 , _ENCRYPTION_PROTOCOL_V2_1 ]
45+ _ENCRYPTION_V2_PROTOCOLS = [_ENCRYPTION_PROTOCOL_V2 , _ENCRYPTION_PROTOCOL_V2_1 ]
4346_GCM_REGION_DATA_LENGTH = 4 * 1024 * 1024
4447_GCM_NONCE_LENGTH = 12
4548_GCM_TAG_LENGTH = 16
4649
4750_ERROR_OBJECT_INVALID = \
4851 '{0} does not define a complete interface. Value of {1} is either missing or invalid.'
4952
53+ _ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION = (
54+ 'The require_encryption flag is set, but encryption is not supported'
55+ ' for this method.' )
56+
5057
5158class KeyEncryptionKey (Protocol ):
5259
@@ -289,14 +296,14 @@ def encrypt_data_v2(data: bytes, nonce: int, key: bytes) -> bytes:
289296
290297def is_encryption_v2 (encryption_data : Optional [_EncryptionData ]) -> bool :
291298 """
292- Determine whether the given encryption data signifies version 2.0.
299+ Determine whether the given encryption data signifies version 2.0 or 2.1 .
293300
294301 :param Optional[_EncryptionData] encryption_data: The encryption data. Will return False if this is None.
295302 :return: True, if the encryption data indicates encryption V2, false otherwise.
296303 :rtype: bool
297304 """
298305 # If encryption_data is None, assume no encryption
299- return bool (encryption_data and (encryption_data .encryption_agent .protocol == _ENCRYPTION_PROTOCOL_V2 ))
306+ return bool (encryption_data and (encryption_data .encryption_agent .protocol in _ENCRYPTION_V2_PROTOCOLS ))
300307
301308
302309def modify_user_agent_for_encryption (
@@ -357,7 +364,7 @@ def get_adjusted_upload_size(length: int, encryption_version: str) -> int:
357364def get_adjusted_download_range_and_offset (
358365 start : int ,
359366 end : int ,
360- length : int ,
367+ length : Optional [ int ] ,
361368 encryption_data : Optional [_EncryptionData ]) -> Tuple [Tuple [int , int ], Tuple [int , int ]]:
362369 """
363370 Gets the new download range and offsets into the decrypted data for
@@ -374,7 +381,7 @@ def get_adjusted_download_range_and_offset(
374381
375382 :param int start: The user-requested start index.
376383 :param int end: The user-requested end index.
377- :param int length: The user-requested length. Only used for V1.
384+ :param Optional[ int] length: The user-requested length. Only used for V1.
378385 :param Optional[_EncryptionData] encryption_data: The encryption data to determine version and sizes.
379386 :return: (new start, new end), (start offset, end offset)
380387 :rtype: Tuple[Tuple[int, int], Tuple[int, int]]
@@ -401,7 +408,7 @@ def get_adjusted_download_range_and_offset(
401408 end_offset = 15 - (end % 16 )
402409 end += end_offset
403410
404- elif encryption_data .encryption_agent .protocol == _ENCRYPTION_PROTOCOL_V2 :
411+ elif encryption_data .encryption_agent .protocol in _ENCRYPTION_V2_PROTOCOLS :
405412 start_offset , end_offset = 0 , end
406413
407414 if encryption_data .encrypted_region_info is None :
@@ -451,17 +458,20 @@ def parse_encryption_data(metadata: Dict[str, Any]) -> Optional[_EncryptionData]
451458 return None
452459
453460
454- def adjust_blob_size_for_encryption (size : int , encryption_data : _EncryptionData ) -> int :
461+ def adjust_blob_size_for_encryption (size : int , encryption_data : Optional [ _EncryptionData ] ) -> int :
455462 """
456463 Adjusts the given blob size for encryption by subtracting the size of
457464 the encryption data (nonce + tag). This only has an affect for encryption V2.
458465
459466 :param int size: The original blob size.
460- :param _EncryptionData encryption_data: The encryption data to determine version and sizes.
467+ :param Optional[ _EncryptionData] encryption_data: The encryption data to determine version and sizes.
461468 :return: The new blob size.
462469 :rtype: int
463470 """
464- if is_encryption_v2 (encryption_data ) and encryption_data .encrypted_region_info is not None :
471+ if (encryption_data is not None and
472+ encryption_data .encrypted_region_info is not None and
473+ is_encryption_v2 (encryption_data )):
474+
465475 nonce_length = encryption_data .encrypted_region_info .nonce_length
466476 data_length = encryption_data .encrypted_region_info .data_length
467477 tag_length = encryption_data .encrypted_region_info .tag_length
@@ -543,7 +553,7 @@ def _dict_to_encryption_data(encryption_data_dict: Dict[str, Any]) -> _Encryptio
543553 """
544554 try :
545555 protocol = encryption_data_dict ['EncryptionAgent' ]['Protocol' ]
546- if protocol not in [ _ENCRYPTION_PROTOCOL_V1 , _ENCRYPTION_PROTOCOL_V2 ] :
556+ if protocol not in _VALID_ENCRYPTION_PROTOCOLS :
547557 raise ValueError ("Unsupported encryption version." )
548558 except KeyError as exc :
549559 raise ValueError ("Unsupported encryption version." ) from exc
@@ -629,7 +639,7 @@ def _validate_and_unwrap_cek(
629639 # Validate we have the right info for the specified version
630640 if encryption_data .encryption_agent .protocol == _ENCRYPTION_PROTOCOL_V1 :
631641 _validate_not_none ('content_encryption_IV' , encryption_data .content_encryption_IV )
632- elif encryption_data .encryption_agent .protocol == _ENCRYPTION_PROTOCOL_V2 :
642+ elif encryption_data .encryption_agent .protocol in _ENCRYPTION_V2_PROTOCOLS :
633643 _validate_not_none ('encrypted_region_info' , encryption_data .encrypted_region_info )
634644 else :
635645 raise ValueError ('Specified encryption version is not supported.' )
@@ -655,8 +665,8 @@ def _validate_and_unwrap_cek(
655665
656666 # For V2, the version is included with the cek. We need to validate it
657667 # and remove it from the actual cek.
658- if encryption_data .encryption_agent .protocol == _ENCRYPTION_PROTOCOL_V2 :
659- version_2_bytes = _ENCRYPTION_PROTOCOL_V2 .encode ().ljust (8 , b'\0 ' )
668+ if encryption_data .encryption_agent .protocol in _ENCRYPTION_V2_PROTOCOLS :
669+ version_2_bytes = encryption_data . encryption_agent . protocol .encode ().ljust (8 , b'\0 ' )
660670 cek_version_bytes = content_encryption_key [:len (version_2_bytes )]
661671 if cek_version_bytes != version_2_bytes :
662672 raise ValueError ('The encryption metadata is not valid and may have been modified.' )
@@ -715,7 +725,7 @@ def _decrypt_message(
715725 unpadder = PKCS7 (128 ).unpadder ()
716726 decrypted_data = (unpadder .update (decrypted_data ) + unpadder .finalize ())
717727
718- elif encryption_data .encryption_agent .protocol == _ENCRYPTION_PROTOCOL_V2 :
728+ elif encryption_data .encryption_agent .protocol in _ENCRYPTION_V2_PROTOCOLS :
719729 block_info = encryption_data .encrypted_region_info
720730 if not block_info or not block_info .nonce_length :
721731 raise ValueError ("Missing required metadata for decryption." )
@@ -887,7 +897,7 @@ def decrypt_blob( # pylint: disable=too-many-locals,too-many-statements
887897 raise ValueError ('Specified encryption algorithm is not supported.' )
888898
889899 version = encryption_data .encryption_agent .protocol
890- if version not in ( _ENCRYPTION_PROTOCOL_V1 , _ENCRYPTION_PROTOCOL_V2 ) :
900+ if version not in _VALID_ENCRYPTION_PROTOCOLS :
891901 raise ValueError ('Specified encryption version is not supported.' )
892902
893903 content_encryption_key = _validate_and_unwrap_cek (encryption_data , key_encryption_key , key_resolver )
@@ -938,7 +948,7 @@ def decrypt_blob( # pylint: disable=too-many-locals,too-many-statements
938948
939949 return content [start_offset : len (content ) - end_offset ]
940950
941- if version == _ENCRYPTION_PROTOCOL_V2 :
951+ if version in _ENCRYPTION_V2_PROTOCOLS :
942952 # We assume the content contains only full encryption regions
943953 total_size = len (content )
944954 offset = 0
0 commit comments