# frozen_string_literal: truerequire'base64'moduleAwsmoduleS3moduleEncryptionV2# @api privateclassDefaultCipherProviderdefinitialize(options={})@key_provider=options[:key_provider]@key_wrap_schema=validate_key_wrap(options[:key_wrap_schema],@key_provider.encryption_materials.key)@content_encryption_schema=validate_cek(options[:content_encryption_schema])end# @return [Array<Hash,Cipher>] Creates an returns a new encryption# envelope and encryption cipher.defencryption_cipher(options={})validate_options(options)cipher=Utils.aes_encryption_cipher(:GCM)if@key_provider.encryption_materials.key.is_a?OpenSSL::PKey::RSAenc_key=encode64(encrypt_rsa(envelope_key(cipher),@content_encryption_schema))elseenc_key=encode64(encrypt_aes_gcm(envelope_key(cipher),@content_encryption_schema))endenvelope={'x-amz-key-v2'=>enc_key,'x-amz-cek-alg'=>@content_encryption_schema,'x-amz-tag-len'=>(AES_GCM_TAG_LEN_BYTES*8).to_s,'x-amz-wrap-alg'=>@key_wrap_schema,'x-amz-iv'=>encode64(envelope_iv(cipher)),'x-amz-matdesc'=>materials_description}cipher.auth_data=''# auth_data must be set after key and iv[envelope,cipher]end# @return [Cipher] Given an encryption envelope, returns a# decryption cipher.defdecryption_cipher(envelope,options={})validate_options(options)master_key=@key_provider.key_for(envelope['x-amz-matdesc'])ifenvelope.key?'x-amz-key'unlessoptions[:security_profile]==:v2_and_legacyraiseErrors::LegacyDecryptionErrorend# Support for decryption of legacy objectskey=Utils.decrypt(master_key,decode64(envelope['x-amz-key']))iv=decode64(envelope['x-amz-iv'])Utils.aes_decryption_cipher(:CBC,key,iv)elseifenvelope['x-amz-cek-alg']!='AES/GCM/NoPadding'raiseArgumentError,'Unsupported cek-alg: '\"#{envelope['x-amz-cek-alg']}"endkey=caseenvelope['x-amz-wrap-alg']when'AES/GCM'ifmaster_key.is_a?OpenSSL::PKey::RSAraiseArgumentError,'Key mismatch - Client is configured'\' with an RSA key and the x-amz-wrap-alg is AES/GCM.'endUtils.decrypt_aes_gcm(master_key,decode64(envelope['x-amz-key-v2']),envelope['x-amz-cek-alg'])when'RSA-OAEP-SHA1'unlessmaster_key.is_a?OpenSSL::PKey::RSAraiseArgumentError,'Key mismatch - Client is configured'\' with an AES key and the x-amz-wrap-alg is RSA-OAEP-SHA1.'endkey,cek_alg=Utils.decrypt_rsa(master_key,decode64(envelope['x-amz-key-v2']))raiseErrors::CEKAlgMismatchErrorunlesscek_alg==envelope['x-amz-cek-alg']keywhen'kms+context'raiseArgumentError,'Key mismatch - Client is configured'\' with a user provided key and the x-amz-wrap-alg is'\' kms+context. Please configure the client with the'\' required kms_key_id'elseraiseArgumentError,'Unsupported wrap-alg: '\"#{envelope['x-amz-wrap-alg']}"endiv=decode64(envelope['x-amz-iv'])Utils.aes_decryption_cipher(:GCM,key,iv)endendprivate# Validate that the key_wrap_schema# is valid, supported and matches the provided key.# Returns the string version for the x-amz-key-wrap-algdefvalidate_key_wrap(key_wrap_schema,key)ifkey.is_a?OpenSSL::PKey::RSAunlesskey_wrap_schema==:rsa_oaep_sha1raiseArgumentError,':key_wrap_schema must be set to :rsa_oaep_sha1 for RSA keys.'endelseunlesskey_wrap_schema==:aes_gcmraiseArgumentError,':key_wrap_schema must be set to :aes_gcm for AES keys.'endendcasekey_wrap_schemawhen:rsa_oaep_sha1then'RSA-OAEP-SHA1'when:aes_gcmthen'AES/GCM'when:kms_contextraiseArgumentError,'A kms_key_id is required when using :kms_context.'elseraiseArgumentError,"Unsupported key_wrap_schema: #{key_wrap_schema}"endenddefvalidate_cek(content_encryption_schema)casecontent_encryption_schemawhen:aes_gcm_no_padding"AES/GCM/NoPadding"elseraiseArgumentError,"Unsupported content_encryption_schema: #{content_encryption_schema}"endenddefenvelope_key(cipher)cipher.key=cipher.random_keyenddefenvelope_iv(cipher)cipher.iv=cipher.random_ivenddefencrypt_aes_gcm(data,auth_data)Utils.encrypt_aes_gcm(@key_provider.encryption_materials.key,data,auth_data)enddefencrypt_rsa(data,auth_data)Utils.encrypt_rsa(@key_provider.encryption_materials.key,data,auth_data)enddefmaterials_description@key_provider.encryption_materials.descriptionenddefencode64(str)Base64.encode64(str).split("\n")*''enddefdecode64(str)Base64.decode64(str)enddefvalidate_options(options)if!options[:kms_encryption_context].nil?raiseArgumentError,'Cannot provide :kms_encryption_context '\'with non KMS client.'endendendendendend