
                             S r SSKJr  SSKJr  SSKJr  SSKJr  SSKrSSKrSSKJ	r	  SSK
r
SSKrSSKrSSKJr  SS	KJr  S
r\" S 5      r " S S\5      r " S S\5      rS rS rS rS rS rS rS rg)zGHelper functions for dealing with encryption keys used with cloud APIs.    )absolute_import)print_function)division)unicode_literalsN)sha256)CommandException)LazyWrapperd   c                  .    [         R                  " S5      $ )Nzqprojects/([^/]+)/locations/([a-zA-Z0-9_-]{1,63})/keyRings/([a-zA-Z0-9_-]{1,63})/cryptoKeys/([a-zA-Z0-9_-]{1,63})$)recompile     0platform/gsutil/gslib/utils/encryption_helper.py<lambda>r   "   s    BJJ ; <r   c                        \ rS rSrSrSrSrSrg)CryptoKeyType(   zDEnum of valid types of encryption keys used with cloud API requests.CSEKCMEKr   N)__name__
__module____qualname____firstlineno____doc__r   r   __static_attributes__r   r   r   r   r   (   s    L	$	$r   r   c                       \ rS rSrSrS rSrg)CryptoKeyWrapper.   zClass describing a crypto key used with cloud API requests.

This class should be instantiated via the `CryptoKeyWrapperFromKey` method.
c                 \   Xl         [        U5      S:X  a.  [        R                  U l        SU l         [        U5      U l        g [        U5        [        R                  U l        SU l        SU l        g!   [        S5      e= f! [         a  n[        SUR                  -  5      eSnAff = f)a  Initialize the CryptoKeyWrapper.

Args:
  crypto_key: Base64-encoded string of a CSEK, or the name of a Cloud KMS
      CMEK.

Raises:
  CommandException: The specified crypto key was neither a CMEK key name nor
      a valid base64-encoded string of a CSEK.
,   AES256zConfigured encryption_key or decryption_key looked like a CSEK, but it was not a valid 44-character base64 string. Please double-check your configuration and ensure the key is correct.zaConfigured encryption_key or decryption_key looked like a CMEK, but the key failed validation:
%sN)
crypto_keylenr   r   crypto_type
crypto_alg#Base64Sha256FromBase64EncryptionKeycrypto_key_sha256r   ValidateCMEKreasonr   )selfr#   es      r   __init__CryptoKeyWrapper.__init__4   s     !O :"&++d doN!DZ!P=Z 
 '++ddo#dNMN 	N  =13488<= 	==s#   A4 B 4B
B+B&&B+)r&   r#   r(   r%   N)r   r   r   r   r   r-   r   r   r   r   r   r   .   s    
!$r   r   c                 *    U (       a  [        U 5      $ S$ )z>Returns a CryptoKeyWrapper for crypto_key, or None for no key.N)r   )r#   s    r   CryptoKeyWrapperFromKeyr0   X   s    )3	*	%==r   c           
      8   [         R                  (       a&  [        U [        5      (       d  U R	                  S5      n [        UR                  SSS5      5      nUb:  UR                  [        R                  :X  a  UR                  U :X  a  UR                  $ [        [        5       Hs  nUS-   n[        UR                  SS[        U5      -  S5      5      nUc    gUR                  [        R                  :X  d  MU  UR                  U :X  d  Mg  UR                  s  $    g)an  Searches boto_config for a CSEK with the given base64-encoded SHA256 hash.

Args:
  key_sha256: (str) Base64-encoded SHA256 hash of the AES256 encryption key.
  boto_config: (boto.pyami.config.Config) The boto config in which to check
      for a matching encryption key.

Returns:
  (str) Base64-encoded encryption key string if a match is found, None
  otherwise.
asciiGSUtilencryption_keyN   zdecryption_key%s)sixPY3
isinstancebytesencoder0   getr%   r   r   r(   r#   rangeMAX_DECRYPTION_KEYSstr)
key_sha256boto_config
keywrapperi
key_numbers        r   FindMatchingCSEKInBotoConfigrD   ]   s     	WWj%(($$W-j&ooh 0$79* 2 22""j0   $%aQJ("4s:"FMOJ 

 
 M$6$6
6

&
&*
4""" &r   c                 P    U R                  SSS5      nU(       a  [        U5      $ S$ )a  Returns a CryptoKeyWrapper for the configured encryption key.

Reads in the value of the "encryption_key" attribute in boto_config, and if
present, verifies it is a valid base64-encoded string and returns a
CryptoKeyWrapper for it.

Args:
  boto_config: (boto.pyami.config.Config) The boto config in which to check
      for a matching encryption key.

Returns:
  CryptoKeyWrapper for the specified encryption key, or None if no encryption
  key was specified in boto_config.
r3   r4   N)r;   r   r@   r4   s     r   GetEncryptionKeyWrapperrG      s*     ??8-=tD.-;	.	)EEr   c                 6   [         R                  (       a&  [        U [        5      (       d  U R	                  S5      n [
        R                  " U 5      n[        U5      n[        R                  " U5      n[
        R                  " U5      nUR                  SS5      $ )Nr2      
r   )r6   r7   r8   r9   r:   base64	b64decode_CalculateSha256FromStringbinascii	unhexlify	b64encodereplace)csek_encryption_keydecoded_bytesr?   sha256_bytessha256_base64s        r   r'   r'      sv    WW)511/66w?""#67-)-8*##J/,""<0-			uc	**r   c                     U (       d  [        S5      eU R                  S5      (       a  [        SU -  5      e[        5       R                  U 5      (       d  [        SU -  5      eg )NzKMS key is empty./z5KMS key should not start with leading slash (/): "%s"zInvalid KMS key name: "%s".
KMS keys should follow the format "projects/<project-id>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key-name>")r   
startswithVALID_CMEK_REmatch)keys    r   r)   r)      sk    	
.
//^^C
?#EG G 
		s	#	#
	!#&	'( ( 
$r   c                 X    [        5       nUR                  U 5        UR                  5       $ )N)r   update	hexdigest)input_stringsha256_hashs     r   rL   rL      s&    +\"				  r   c                     U R                  SSS5      nU(       a   [        R                  " U5        U$ U$ !   [        S5      e= f)a5  Reads the encryption key from boto_config and ensures it is base64-encoded.

Args:
  boto_config: (boto.pyami.config.Config) The boto config in which to check
      for a matching encryption key.

Returns:
  (str) Base64-encoded encryption key string, or None if no encryption key
  exists in configuration.

r3   r4   NzConfigured encryption_key is not a valid base64 string. Please double-check your configuration and ensure the key is valid and in base64 format.)r;   rJ   rK   r   rF   s     r    _GetAndVerifyBase64EncryptionKeyra      sS     ??8-=tD.~& 
 s	   6 A)r   
__future__r   r   r   r   rJ   rM   hashlibr   r   sysr6   gslib.exceptionr   gslib.lazy_wrapperr	   r=   rX   objectr   r   r0   rD   rG   r'   r)   rL   ra   r   r   r   <module>rh      s    N & %  '    	 
 
 , * <=F '$v '$T>
!#HF&+(!r   