github.com/aldelo/common@v1.5.1/wrapper/kms/kms.go (about)

     1  package kms
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  // =================================================================================================================
    20  // AWS CREDENTIAL:
    21  //		use $> aws configure (to set aws access key and secret to target machine)
    22  //		Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli
    23  //
    24  // To Install & Setup AWS CLI on Host:
    25  //		1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html
    26  //				On Ubuntu, if host does not have zip and unzip:
    27  //					$> sudo apt install zip
    28  //					$> sudo apt install unzip
    29  //				On Ubuntu, to install AWS CLI v2:
    30  //					$> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    31  //					$> unzip awscliv2.zip
    32  //					$> sudo ./aws/install
    33  //		2) $> aws configure set region awsRegionName --profile default
    34  // 		3) $> aws configure
    35  //				follow prompts to enter Access ID and Secret Key
    36  //
    37  // AWS Region Name Reference:
    38  //		us-west-2, us-east-1, ap-northeast-1, etc
    39  //		See: https://docs.aws.amazon.com/general/latest/gr/rande.html
    40  // =================================================================================================================
    41  
    42  import (
    43  	"context"
    44  	"errors"
    45  	util "github.com/aldelo/common"
    46  	"github.com/aldelo/common/crypto"
    47  	awshttp2 "github.com/aldelo/common/wrapper/aws"
    48  	"github.com/aldelo/common/wrapper/aws/awsregion"
    49  	"github.com/aldelo/common/wrapper/xray"
    50  	"github.com/aws/aws-sdk-go/aws"
    51  	"github.com/aws/aws-sdk-go/aws/session"
    52  	"github.com/aws/aws-sdk-go/service/kms"
    53  	awsxray "github.com/aws/aws-xray-sdk-go/xray"
    54  	"net/http"
    55  )
    56  
    57  // ================================================================================================================
    58  // STRUCTS
    59  // ================================================================================================================
    60  
    61  // KMS struct encapsulates the AWS KMS access functionality
    62  type KMS struct {
    63  	// define the AWS region that KMS is located at
    64  	AwsRegion awsregion.AWSRegion
    65  
    66  	// custom http2 client options
    67  	HttpOptions *awshttp2.HttpClientSettings
    68  
    69  	// define kms key name
    70  	AesKmsKeyName       string
    71  	RsaKmsKeyName       string
    72  	SignatureKmsKeyName string
    73  
    74  	// store aws session object
    75  	sess *session.Session
    76  
    77  	// store kms client object
    78  	kmsClient *kms.KMS
    79  
    80  	_parentSegment *xray.XRayParentSegment
    81  }
    82  
    83  // ================================================================================================================
    84  // STRUCTS FUNCTIONS
    85  // ================================================================================================================
    86  
    87  // ----------------------------------------------------------------------------------------------------------------
    88  // utility functions
    89  // ----------------------------------------------------------------------------------------------------------------
    90  
    91  // Connect will establish a connection to the KMS service
    92  func (k *KMS) Connect(parentSegment ...*xray.XRayParentSegment) (err error) {
    93  	if xray.XRayServiceOn() {
    94  		if len(parentSegment) > 0 {
    95  			k._parentSegment = parentSegment[0]
    96  		}
    97  
    98  		seg := xray.NewSegment("KMS-Connect", k._parentSegment)
    99  		defer seg.Close()
   100  		defer func() {
   101  			_ = seg.Seg.AddMetadata("KDS-AWS-Region", k.AwsRegion)
   102  
   103  			if err != nil {
   104  				_ = seg.Seg.AddError(err)
   105  			}
   106  		}()
   107  
   108  		err = k.connectInternal()
   109  
   110  		if err == nil {
   111  			awsxray.AWS(k.kmsClient.Client)
   112  		}
   113  
   114  		return err
   115  	} else {
   116  		return k.connectInternal()
   117  	}
   118  }
   119  
   120  // Connect will establish a connection to the KMS service
   121  func (k *KMS) connectInternal() error {
   122  	// clean up prior session reference
   123  	k.sess = nil
   124  
   125  	if !k.AwsRegion.Valid() || k.AwsRegion == awsregion.UNKNOWN {
   126  		return errors.New("Connect To KMS Failed: (AWS Session Error) " + "Region is Required")
   127  	}
   128  
   129  	// create custom http2 client if needed
   130  	var httpCli *http.Client
   131  	var httpErr error
   132  
   133  	if k.HttpOptions == nil {
   134  		k.HttpOptions = new(awshttp2.HttpClientSettings)
   135  	}
   136  
   137  	// use custom http2 client
   138  	h2 := &awshttp2.AwsHttp2Client{
   139  		Options: k.HttpOptions,
   140  	}
   141  
   142  	if httpCli, httpErr = h2.NewHttp2Client(); httpErr != nil {
   143  		return errors.New("Connect to KMS Failed: (AWS Session Error) " + "Create Custom Http2 Client Errored = " + httpErr.Error())
   144  	}
   145  
   146  	// establish aws session connection and keep session object in struct
   147  	if sess, err := session.NewSession(
   148  		&aws.Config{
   149  			Region:     aws.String(k.AwsRegion.Key()),
   150  			HTTPClient: httpCli,
   151  		}); err != nil {
   152  		// aws session error
   153  		return errors.New("Connect To KMS Failed: (AWS Session Error) " + err.Error())
   154  	} else {
   155  		// aws session obtained
   156  		k.sess = sess
   157  
   158  		// create cached objects for shared use
   159  		k.kmsClient = kms.New(k.sess)
   160  
   161  		if k.kmsClient == nil {
   162  			return errors.New("Connect To KMS Client Failed: (New KMS Client Connection) " + "Connection Object Nil")
   163  		}
   164  
   165  		// session stored to struct
   166  		return nil
   167  	}
   168  }
   169  
   170  // Disconnect will disjoin from aws session by clearing it
   171  func (k *KMS) Disconnect() {
   172  	k.kmsClient = nil
   173  	k.sess = nil
   174  }
   175  
   176  // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil
   177  func (k *KMS) UpdateParentSegment(parentSegment *xray.XRayParentSegment) {
   178  	k._parentSegment = parentSegment
   179  }
   180  
   181  // ----------------------------------------------------------------------------------------------------------------
   182  // kms-cmk encrypt/decrypt via aes 256 functions
   183  // ----------------------------------------------------------------------------------------------------------------
   184  
   185  // EncryptViaCmkAes256 will use kms cmk to encrypt plainText using aes 256 symmetric kms cmk key, and return cipherText string,
   186  // the cipherText can only be decrypted with aes 256 symmetric kms cmk key
   187  func (k *KMS) EncryptViaCmkAes256(plainText string) (cipherText string, err error) {
   188  	var segCtx context.Context
   189  	segCtx = nil
   190  
   191  	seg := xray.NewSegmentNullable("KMS-EncryptViaCmkAes256", k._parentSegment)
   192  
   193  	if seg != nil {
   194  		segCtx = seg.Ctx
   195  
   196  		defer seg.Close()
   197  		defer func() {
   198  			_ = seg.Seg.AddMetadata("KMS-EncryptViaCmkAes256-AES-KMS-KeyName", k.AesKmsKeyName)
   199  			_ = seg.Seg.AddMetadata("KMS-EncryptViaCmkAes256-PlainText-Length", len(plainText))
   200  			_ = seg.Seg.AddMetadata("KMS-EncryptViaCmkAes256-Result-CipherText-Length", len(cipherText))
   201  
   202  			if err != nil {
   203  				_ = seg.Seg.AddError(err)
   204  			}
   205  		}()
   206  	}
   207  
   208  	// validate
   209  	if k.kmsClient == nil {
   210  		err = errors.New("EncryptViaCmkAes256 with KMS CMK Failed: " + "KMS Client is Required")
   211  		return "", err
   212  	}
   213  
   214  	if len(k.AesKmsKeyName) <= 0 {
   215  		err = errors.New("EncryptViaCmkAes256 with KMS CMK Failed: " + "AES KMS Key Name is Required")
   216  		return "", err
   217  	}
   218  
   219  	if len(plainText) <= 0 {
   220  		err = errors.New("EncryptViaCmkAes256 with KMS CMK Failed: " + "PlainText is Required")
   221  		return "", err
   222  	}
   223  
   224  	// prepare key info
   225  	keyId := "alias/" + k.AesKmsKeyName
   226  
   227  	// encrypt symmetric using kms cmk
   228  	var encryptedOutput *kms.EncryptOutput
   229  	var e error
   230  
   231  	if segCtx == nil {
   232  		encryptedOutput, e = k.kmsClient.Encrypt(&kms.EncryptInput{
   233  			EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   234  			KeyId:               aws.String(keyId),
   235  			Plaintext:           []byte(plainText),
   236  		})
   237  	} else {
   238  		encryptedOutput, e = k.kmsClient.EncryptWithContext(segCtx,
   239  			&kms.EncryptInput{
   240  				EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   241  				KeyId:               aws.String(keyId),
   242  				Plaintext:           []byte(plainText),
   243  			})
   244  	}
   245  
   246  	if e != nil {
   247  		err = errors.New("EncryptViaCmkAes256 with KMS CMK Failed: (Symmetric Encrypt) " + e.Error())
   248  		return "", err
   249  	}
   250  
   251  	// return encrypted cipher text blob
   252  	cipherText = util.ByteToHex(encryptedOutput.CiphertextBlob)
   253  	return cipherText, nil
   254  }
   255  
   256  // ReEncryptViaCmkAes256 will re-encrypt sourceCipherText using the new targetKmsKeyName via kms, (must be targeting aes 256 key)
   257  // the re-encrypted cipherText is then returned
   258  func (k *KMS) ReEncryptViaCmkAes256(sourceCipherText string, targetKmsKeyName string) (targetCipherText string, err error) {
   259  	var segCtx context.Context
   260  	segCtx = nil
   261  
   262  	seg := xray.NewSegmentNullable("KMS-ReEncryptViaCmkAes256", k._parentSegment)
   263  
   264  	if seg != nil {
   265  		segCtx = seg.Ctx
   266  
   267  		defer seg.Close()
   268  		defer func() {
   269  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkAes256-Source-AES-KMS-KeyName", k.AesKmsKeyName)
   270  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkAes256-Target-AES-KMS-KeyName", targetKmsKeyName)
   271  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkAes256-SourceCipherText-Length", len(sourceCipherText))
   272  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkAes256-Result-Target-CipherText-Length", len(targetCipherText))
   273  
   274  			if err != nil {
   275  				_ = seg.Seg.AddError(err)
   276  			}
   277  		}()
   278  	}
   279  
   280  	// validate
   281  	if k.kmsClient == nil {
   282  		err = errors.New("ReEncryptViaCmkAes256 with KMS CMK Failed: " + "KMS Client is Required")
   283  		return "", err
   284  	}
   285  
   286  	if len(k.AesKmsKeyName) <= 0 {
   287  		err = errors.New("ReEncryptViaCmkAes256 with KMS CMK Failed: " + "AES KMS Key Name is Required")
   288  		return "", err
   289  	}
   290  
   291  	if len(sourceCipherText) <= 0 {
   292  		err = errors.New("ReEncryptViaCmkAes256 with KMS CMK Failed: " + "Source CipherText is Required")
   293  		return "", err
   294  	}
   295  
   296  	if len(targetKmsKeyName) <= 0 {
   297  		err = errors.New("ReEncryptViaCmkAes256 with KMS CMK Failed: " + "Target KMS Key Name is Required")
   298  		return "", err
   299  	}
   300  
   301  	// prepare key info
   302  	keyId := "alias/" + k.AesKmsKeyName
   303  
   304  	// convert hex to bytes
   305  	cipherBytes, ce := util.HexToByte(sourceCipherText)
   306  
   307  	if ce != nil {
   308  		err = errors.New("ReEncryptViaCmkAes256 with KMS CMK Failed: (Unmarshal Source CipherText Hex To Byte) " + ce.Error())
   309  		return "", err
   310  	}
   311  
   312  	// re-encrypt symmetric kms cmk
   313  	var reEncryptOutput *kms.ReEncryptOutput
   314  	var e error
   315  
   316  	if segCtx == nil {
   317  		reEncryptOutput, e = k.kmsClient.ReEncrypt(&kms.ReEncryptInput{
   318  			SourceEncryptionAlgorithm:      aws.String("SYMMETRIC_DEFAULT"),
   319  			SourceKeyId:                    aws.String(keyId),
   320  			DestinationEncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   321  			DestinationKeyId:               aws.String("alias/" + targetKmsKeyName),
   322  			CiphertextBlob:                 cipherBytes,
   323  		})
   324  	} else {
   325  		reEncryptOutput, e = k.kmsClient.ReEncryptWithContext(segCtx,
   326  			&kms.ReEncryptInput{
   327  				SourceEncryptionAlgorithm:      aws.String("SYMMETRIC_DEFAULT"),
   328  				SourceKeyId:                    aws.String(keyId),
   329  				DestinationEncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   330  				DestinationKeyId:               aws.String("alias/" + targetKmsKeyName),
   331  				CiphertextBlob:                 cipherBytes,
   332  			})
   333  	}
   334  
   335  	if e != nil {
   336  		err = errors.New("ReEncryptViaCmkAes256 with KMS CMK Failed: (Symmetric ReEncrypt) " + e.Error())
   337  		return "", err
   338  	}
   339  
   340  	// return encrypted cipher text blob
   341  	targetCipherText = util.ByteToHex(reEncryptOutput.CiphertextBlob)
   342  	return targetCipherText, nil
   343  }
   344  
   345  // DecryptViaCmkAes256 will use kms cmk to decrypt cipherText using symmetric aes 256 kms cmk key, and return plainText string,
   346  // the cipherText can only be decrypted with the symmetric aes 256 kms cmk key
   347  func (k *KMS) DecryptViaCmkAes256(cipherText string) (plainText string, err error) {
   348  	var segCtx context.Context
   349  	segCtx = nil
   350  
   351  	seg := xray.NewSegmentNullable("KMS-DecryptViaCmkAes256", k._parentSegment)
   352  
   353  	if seg != nil {
   354  		segCtx = seg.Ctx
   355  
   356  		defer seg.Close()
   357  		defer func() {
   358  			_ = seg.Seg.AddMetadata("KMS-DecryptViaCmkAes256-AES-KMS-KeyName", k.AesKmsKeyName)
   359  			_ = seg.Seg.AddMetadata("KMS-DecryptViaCmkAes256-CipherText-Length", len(cipherText))
   360  			_ = seg.Seg.AddMetadata("KMS-DecryptViaCmkAes256-Result-PlainText-Length", len(plainText))
   361  
   362  			if err != nil {
   363  				_ = seg.Seg.AddError(err)
   364  			}
   365  		}()
   366  	}
   367  
   368  	// validate
   369  	if k.kmsClient == nil {
   370  		err = errors.New("DecryptViaCmkAes256 with KMS CMK Failed: " + "KMS Client is Required")
   371  		return "", err
   372  	}
   373  
   374  	if len(k.AesKmsKeyName) <= 0 {
   375  		err = errors.New("DecryptViaCmkAes256 with KMS CMK Failed: " + "AES KMS Key Name is Required")
   376  		return "", err
   377  	}
   378  
   379  	if len(cipherText) <= 0 {
   380  		err = errors.New("DecryptViaCmkAes256 with KMS CMK Failed: " + "Cipher Text is Required")
   381  		return "", err
   382  	}
   383  
   384  	// prepare key info
   385  	keyId := "alias/" + k.AesKmsKeyName
   386  	cipherBytes, ce := util.HexToByte(cipherText)
   387  
   388  	if ce != nil {
   389  		err = errors.New("DecryptViaCmkAes256 with KMS CMK Failed: (Unmarshal CipherText Hex To Byte) " + ce.Error())
   390  		return "", err
   391  	}
   392  
   393  	// decrypt symmetric using kms cmk
   394  	var decryptedOutput *kms.DecryptOutput
   395  	var e error
   396  
   397  	if segCtx == nil {
   398  		decryptedOutput, e = k.kmsClient.Decrypt(&kms.DecryptInput{
   399  			EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   400  			KeyId:               aws.String(keyId),
   401  			CiphertextBlob:      cipherBytes,
   402  		})
   403  	} else {
   404  		decryptedOutput, e = k.kmsClient.DecryptWithContext(segCtx,
   405  			&kms.DecryptInput{
   406  				EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   407  				KeyId:               aws.String(keyId),
   408  				CiphertextBlob:      cipherBytes,
   409  			})
   410  	}
   411  
   412  	if e != nil {
   413  		err = errors.New("DecryptViaCmkAes256 with KMS CMK Failed: (Symmetric Decrypt) " + e.Error())
   414  		return "", err
   415  	}
   416  
   417  	// return decrypted cipher text blob
   418  	plainText = string(decryptedOutput.Plaintext)
   419  	return plainText, nil
   420  }
   421  
   422  // ----------------------------------------------------------------------------------------------------------------
   423  // kms-cmk encrypt/decrypt via rsa 2048 public/private key functions
   424  // ----------------------------------------------------------------------------------------------------------------
   425  
   426  // EncryptViaCmkRsa2048 will use kms cmk to encrypt plainText with asymmetric rsa 2048 kms cmk public key, and return cipherText string,
   427  // the cipherText can only be decrypted with the paired asymmetric rsa 2048 kms cmk private key
   428  //
   429  // *** To Encrypt using Public Key Outside of KMS ***
   430  //  1. Copy Public Key from AWS KMS for the given RSA CMK
   431  //  2. Using External RSA Public Key Crypto Encrypt Function with the given Public Key to Encrypt
   432  func (k *KMS) EncryptViaCmkRsa2048(plainText string) (cipherText string, err error) {
   433  	var segCtx context.Context
   434  	segCtx = nil
   435  
   436  	seg := xray.NewSegmentNullable("KMS-EncryptViaCmkRsa2048", k._parentSegment)
   437  
   438  	if seg != nil {
   439  		segCtx = seg.Ctx
   440  
   441  		defer seg.Close()
   442  		defer func() {
   443  			_ = seg.Seg.AddMetadata("KMS-EncryptViaCmkRsa2048-RSA-KMS-KeyName", k.RsaKmsKeyName)
   444  			_ = seg.Seg.AddMetadata("KMS-EncryptViaCmkRsa2048-PlainText-Length", len(plainText))
   445  			_ = seg.Seg.AddMetadata("KMS-EncryptViaCmkRsa2048-Result-CipherText-Length", len(cipherText))
   446  
   447  			if err != nil {
   448  				_ = seg.Seg.AddError(err)
   449  			}
   450  		}()
   451  	}
   452  
   453  	// validate
   454  	if k.kmsClient == nil {
   455  		err = errors.New("EncryptViaCmkRsa2048 with KMS CMK Failed: " + "KMS Client is Required")
   456  		return "", err
   457  	}
   458  
   459  	if len(k.RsaKmsKeyName) <= 0 {
   460  		err = errors.New("EncryptViaCmkRsa2048 with KMS CMK Failed: " + "RSA KMS Key Name is Required")
   461  		return "", err
   462  	}
   463  
   464  	if len(plainText) <= 0 {
   465  		err = errors.New("EncryptViaCmkRsa2048 with KMS CMK Failed: " + "PlainText is Required")
   466  		return "", err
   467  	}
   468  
   469  	if len(plainText) > 214 {
   470  		err = errors.New("EncryptViaCmkRsa2048 with KMS CMK Failed: " + "PlainText Cannot Exceed 214 Bytes")
   471  		return "", err
   472  	}
   473  
   474  	// prepare key info
   475  	keyId := "alias/" + k.RsaKmsKeyName
   476  
   477  	// encrypt asymmetric using kms cmk
   478  	var encryptedOutput *kms.EncryptOutput
   479  	var e error
   480  
   481  	if segCtx == nil {
   482  		encryptedOutput, e = k.kmsClient.Encrypt(&kms.EncryptInput{
   483  			EncryptionAlgorithm: aws.String("RSAES_OAEP_SHA_256"),
   484  			KeyId:               aws.String(keyId),
   485  			Plaintext:           []byte(plainText),
   486  		})
   487  	} else {
   488  		encryptedOutput, e = k.kmsClient.EncryptWithContext(segCtx,
   489  			&kms.EncryptInput{
   490  				EncryptionAlgorithm: aws.String("RSAES_OAEP_SHA_256"),
   491  				KeyId:               aws.String(keyId),
   492  				Plaintext:           []byte(plainText),
   493  			})
   494  	}
   495  
   496  	if e != nil {
   497  		err = errors.New("EncryptViaCmkRsa2048 with KMS CMK Failed: (Asymmetric Encrypt) " + e.Error())
   498  		return "", err
   499  	}
   500  
   501  	// return encrypted cipher text blob
   502  	cipherText = util.ByteToHex(encryptedOutput.CiphertextBlob)
   503  	return cipherText, nil
   504  }
   505  
   506  // ReEncryptViaCmkRsa2048 will re-encrypt sourceCipherText using the new targetKmsKeyName via kms, (must be targeting rsa 2048 key)
   507  // the re-encrypted cipherText is then returned
   508  func (k *KMS) ReEncryptViaCmkRsa2048(sourceCipherText string, targetKmsKeyName string) (targetCipherText string, err error) {
   509  	var segCtx context.Context
   510  	segCtx = nil
   511  
   512  	seg := xray.NewSegmentNullable("KMS-ReEncryptViaCmkRsa2048", k._parentSegment)
   513  
   514  	if seg != nil {
   515  		segCtx = seg.Ctx
   516  
   517  		defer seg.Close()
   518  		defer func() {
   519  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkRsa2048-Source-RSA-KMS-KeyName", k.AesKmsKeyName)
   520  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkRsa2048-Target-RSA-KMS-KeyName", targetKmsKeyName)
   521  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkRsa2048-Source-CipherText-Length", len(sourceCipherText))
   522  			_ = seg.Seg.AddMetadata("KMS-ReEncryptViaCmkRsa2048-Result-Target-CipherText-Length", len(targetCipherText))
   523  
   524  			if err != nil {
   525  				_ = seg.Seg.AddError(err)
   526  			}
   527  		}()
   528  	}
   529  
   530  	// validate
   531  	if k.kmsClient == nil {
   532  		err = errors.New("ReEncryptViaCmkRsa2048 with KMS CMK Failed: " + "KMS Client is Required")
   533  		return "", err
   534  	}
   535  
   536  	if len(k.RsaKmsKeyName) <= 0 {
   537  		err = errors.New("ReEncryptViaCmkRsa2048 with KMS CMK Failed: " + "RSA KMS Key Name is Required")
   538  		return "", err
   539  	}
   540  
   541  	if len(sourceCipherText) <= 0 {
   542  		err = errors.New("ReEncryptViaCmkRsa2048 with KMS CMK Failed: " + "Source CipherText is Required")
   543  		return "", err
   544  	}
   545  
   546  	if len(targetKmsKeyName) <= 0 {
   547  		err = errors.New("ReEncryptViaCmkRsa2048 with KMS CMK Failed: " + "Target KMS Key Name is Required")
   548  		return "", err
   549  	}
   550  
   551  	// prepare key info
   552  	keyId := "alias/" + k.RsaKmsKeyName
   553  
   554  	// convert hex to bytes
   555  	cipherBytes, ce := util.HexToByte(sourceCipherText)
   556  
   557  	if ce != nil {
   558  		err = errors.New("ReEncryptViaCmkRsa2048 with KMS CMK Failed: (Unmarshal Source CipherText Hex To Byte) " + ce.Error())
   559  		return "", err
   560  	}
   561  
   562  	// re-encrypt asymmetric kms cmk
   563  	var reEncryptOutput *kms.ReEncryptOutput
   564  	var e error
   565  
   566  	if segCtx == nil {
   567  		reEncryptOutput, e = k.kmsClient.ReEncrypt(&kms.ReEncryptInput{
   568  			SourceEncryptionAlgorithm:      aws.String("RSAES_OAEP_SHA_256"),
   569  			SourceKeyId:                    aws.String(keyId),
   570  			DestinationEncryptionAlgorithm: aws.String("RSAES_OAEP_SHA_256"),
   571  			DestinationKeyId:               aws.String("alias/" + targetKmsKeyName),
   572  			CiphertextBlob:                 cipherBytes,
   573  		})
   574  	} else {
   575  		reEncryptOutput, e = k.kmsClient.ReEncryptWithContext(segCtx,
   576  			&kms.ReEncryptInput{
   577  				SourceEncryptionAlgorithm:      aws.String("RSAES_OAEP_SHA_256"),
   578  				SourceKeyId:                    aws.String(keyId),
   579  				DestinationEncryptionAlgorithm: aws.String("RSAES_OAEP_SHA_256"),
   580  				DestinationKeyId:               aws.String("alias/" + targetKmsKeyName),
   581  				CiphertextBlob:                 cipherBytes,
   582  			})
   583  	}
   584  
   585  	if e != nil {
   586  		err = errors.New("ReEncryptViaCmkRsa2048 with KMS CMK Failed: (Asymmetric ReEncrypt) " + e.Error())
   587  		return "", err
   588  	}
   589  
   590  	// return encrypted cipher text blob
   591  	targetCipherText = util.ByteToHex(reEncryptOutput.CiphertextBlob)
   592  	return targetCipherText, nil
   593  }
   594  
   595  // DecryptViaCmkRsa2048 will use kms cmk to decrypt cipherText using asymmetric rsa 2048 kms cmk private key, and return plainText string,
   596  // the cipherText can only be decrypted with the asymmetric rsa 2048 kms cmk private key
   597  func (k *KMS) DecryptViaCmkRsa2048(cipherText string) (plainText string, err error) {
   598  	var segCtx context.Context
   599  	segCtx = nil
   600  
   601  	seg := xray.NewSegmentNullable("KMS-DecryptViaCmkRsa2048", k._parentSegment)
   602  
   603  	if seg != nil {
   604  		segCtx = seg.Ctx
   605  
   606  		defer seg.Close()
   607  		defer func() {
   608  			_ = seg.Seg.AddMetadata("KMS-DecryptViaCmkRsa2048-RSA-KMS-KeyName", k.RsaKmsKeyName)
   609  			_ = seg.Seg.AddMetadata("KMS-DecryptViaCmkRsa2048-CipherText-Length", len(cipherText))
   610  			_ = seg.Seg.AddMetadata("KMS-DecryptViaCmkRsa2048-Result-PlainText-Length", len(plainText))
   611  
   612  			if err != nil {
   613  				_ = seg.Seg.AddError(err)
   614  			}
   615  		}()
   616  	}
   617  
   618  	// validate
   619  	if k.kmsClient == nil {
   620  		err = errors.New("DecryptViaCmkRsa2048 with KMS CMK Failed: " + "KMS Client is Required")
   621  		return "", err
   622  	}
   623  
   624  	if len(k.RsaKmsKeyName) <= 0 {
   625  		err = errors.New("DecryptViaCmkRsa2048 with KMS CMK Failed: " + "RSA KMS Key Name is Required")
   626  		return "", err
   627  	}
   628  
   629  	if len(cipherText) <= 0 {
   630  		err = errors.New("DecryptViaCmkRsa2048 with KMS CMK Failed: " + "Cipher Text is Required")
   631  		return "", err
   632  	}
   633  
   634  	// prepare key info
   635  	keyId := "alias/" + k.RsaKmsKeyName
   636  	cipherBytes, ce := util.HexToByte(cipherText)
   637  
   638  	if ce != nil {
   639  		err = errors.New("DecryptViaCmkRsa2048 with KMS CMK Failed: (Unmarshal CipherText Hex To Byte) " + ce.Error())
   640  		return "", err
   641  	}
   642  
   643  	// decrypt symmetric using kms cmk
   644  	var decryptedOutput *kms.DecryptOutput
   645  	var e error
   646  
   647  	if segCtx == nil {
   648  		decryptedOutput, e = k.kmsClient.Decrypt(&kms.DecryptInput{
   649  			EncryptionAlgorithm: aws.String("RSAES_OAEP_SHA_256"),
   650  			KeyId:               aws.String(keyId),
   651  			CiphertextBlob:      cipherBytes,
   652  		})
   653  	} else {
   654  		decryptedOutput, e = k.kmsClient.DecryptWithContext(segCtx,
   655  			&kms.DecryptInput{
   656  				EncryptionAlgorithm: aws.String("RSAES_OAEP_SHA_256"),
   657  				KeyId:               aws.String(keyId),
   658  				CiphertextBlob:      cipherBytes,
   659  			})
   660  	}
   661  
   662  	if e != nil {
   663  		err = errors.New("DecryptViaCmkRsa2048 with KMS CMK Failed: (Asymmetric Decrypt) " + e.Error())
   664  		return "", err
   665  	}
   666  
   667  	// return decrypted cipher text blob
   668  	plainText = string(decryptedOutput.Plaintext)
   669  	return plainText, nil
   670  }
   671  
   672  // ----------------------------------------------------------------------------------------------------------------
   673  // kms-cmk sign/verify via rsa 2048 private/public key functions
   674  // ----------------------------------------------------------------------------------------------------------------
   675  
   676  // SignViaCmkRsa2048 will sign dataToSign using KMS CMK RSA Sign/Verify Key (Private Key on KMS will be used to securely sign)
   677  func (k *KMS) SignViaCmkRsa2048(dataToSign string) (signature string, err error) {
   678  	var segCtx context.Context
   679  	segCtx = nil
   680  
   681  	seg := xray.NewSegmentNullable("KMS-SignViaCmkRsa2048", k._parentSegment)
   682  
   683  	if seg != nil {
   684  		segCtx = seg.Ctx
   685  
   686  		defer seg.Close()
   687  		defer func() {
   688  			_ = seg.Seg.AddMetadata("KMS-SignViaCmkRsa2048-Signature-KMS-KeyName", k.SignatureKmsKeyName)
   689  			_ = seg.Seg.AddMetadata("KMS-SignViaCmkRsa2048-DataToSign-Length", len(dataToSign))
   690  			_ = seg.Seg.AddMetadata("KMS-SignViaCmkRsa2048-Result-Signature", signature)
   691  
   692  			if err != nil {
   693  				_ = seg.Seg.AddError(err)
   694  			}
   695  		}()
   696  	}
   697  
   698  	// validate
   699  	if k.kmsClient == nil {
   700  		err = errors.New("SignViaCmkRsa2048 with KMS Failed: " + "KMS Client is Required")
   701  		return "", err
   702  	}
   703  
   704  	if len(k.SignatureKmsKeyName) <= 0 {
   705  		err = errors.New("SignViaCmkRsa2048 with KMS Failed: " + "Signature KMS Key Name is Required")
   706  		return "", err
   707  	}
   708  
   709  	if len(dataToSign) <= 0 {
   710  		err = errors.New("SignViaCmkRsa2048 with KMS Failed: " + "Data To Sign is Required")
   711  		return "", err
   712  	}
   713  
   714  	// prepare key info
   715  	keyId := "alias/" + k.SignatureKmsKeyName
   716  
   717  	// perform sign action using kms rsa sign/verify cmk
   718  	var signOutput *kms.SignOutput
   719  	var e error
   720  
   721  	if segCtx == nil {
   722  		signOutput, e = k.kmsClient.Sign(&kms.SignInput{
   723  			KeyId:            aws.String(keyId),
   724  			SigningAlgorithm: aws.String("RSASSA_PKCS1_V1_5_SHA_256"),
   725  			MessageType:      aws.String("RAW"),
   726  			Message:          []byte(dataToSign),
   727  		})
   728  	} else {
   729  		signOutput, e = k.kmsClient.SignWithContext(segCtx,
   730  			&kms.SignInput{
   731  				KeyId:            aws.String(keyId),
   732  				SigningAlgorithm: aws.String("RSASSA_PKCS1_V1_5_SHA_256"),
   733  				MessageType:      aws.String("RAW"),
   734  				Message:          []byte(dataToSign),
   735  			})
   736  	}
   737  
   738  	if e != nil {
   739  		err = errors.New("SignViaCmkRsa2048 with KMS Failed: (Sign Action) " + e.Error())
   740  		return "", err
   741  	}
   742  
   743  	// return signature
   744  	signature = util.ByteToHex(signOutput.Signature)
   745  	return signature, nil
   746  }
   747  
   748  // VerifyViaCmkRsa2048 will verify dataToVerify with signature using KMS CMK RSA Sign/Verify Key (Public Key on KMS will be used securely to verify)
   749  //
   750  // signatureToVerify = prior signed signature in hex to verify against the dataToVerify parameter
   751  //
   752  // *** To Verify using Public Key Outside of KMS ***
   753  //  1. Copy Public Key from AWS KMS for the given RSA CMK
   754  //  2. Using External RSA Public Key Crypto Verify Function with the given Public Key to Verify
   755  func (k *KMS) VerifyViaCmkRsa2048(dataToVerify string, signatureToVerify string) (signatureValid bool, err error) {
   756  	var segCtx context.Context
   757  	segCtx = nil
   758  
   759  	seg := xray.NewSegmentNullable("KMS-VerifyViaCmkRsa2048", k._parentSegment)
   760  
   761  	if seg != nil {
   762  		segCtx = seg.Ctx
   763  
   764  		defer seg.Close()
   765  		defer func() {
   766  			_ = seg.Seg.AddMetadata("KMS-VerifyViaCmkRsa2048-Signature-KMS-KeyName", k.SignatureKmsKeyName)
   767  			_ = seg.Seg.AddMetadata("KMS-VerifyViaCmkRsa2048-DataToVerify-Length", len(dataToVerify))
   768  			_ = seg.Seg.AddMetadata("KMS-VerifyViaCmkRsa2048-Signature-To-Verify", signatureToVerify)
   769  			_ = seg.Seg.AddMetadata("KMS-VerifyViaCmkRsa2048-Result-SignatureValid", signatureValid)
   770  
   771  			if err != nil {
   772  				_ = seg.Seg.AddError(err)
   773  			}
   774  		}()
   775  	}
   776  
   777  	// validate
   778  	if k.kmsClient == nil {
   779  		err = errors.New("VerifyViaCmkRsa2048 with KMS Failed: " + "KMS Client is Required")
   780  		return false, err
   781  	}
   782  
   783  	if len(k.SignatureKmsKeyName) <= 0 {
   784  		err = errors.New("VerifyViaCmkRsa2048 with KMS Failed: " + "Signature KMS Key Name is Required")
   785  		return false, err
   786  	}
   787  
   788  	if len(dataToVerify) <= 0 {
   789  		err = errors.New("VerifyViaCmkRsa2048 with KMS Failed: " + "Data To Verify is Required")
   790  		return false, err
   791  	}
   792  
   793  	if len(signatureToVerify) <= 0 {
   794  		err = errors.New("VerifyViaCmkRsa2048 with KMS Failed: " + "Signature To Verify is Required")
   795  		return false, err
   796  	}
   797  
   798  	// prepare key info
   799  	keyId := "alias/" + k.SignatureKmsKeyName
   800  	signatureBytes, ce := util.HexToByte(signatureToVerify)
   801  
   802  	if ce != nil {
   803  		err = errors.New("VerifyViaCmkRsa2048 with KMS Failed: (Marshal SignatureToVerify Hex To Byte) " + ce.Error())
   804  		return false, err
   805  	}
   806  
   807  	// perform verify action using kms rsa sign/verify cmk
   808  	var verifyOutput *kms.VerifyOutput
   809  	var e error
   810  
   811  	if segCtx == nil {
   812  		verifyOutput, e = k.kmsClient.Verify(&kms.VerifyInput{
   813  			KeyId:            aws.String(keyId),
   814  			SigningAlgorithm: aws.String("RSASSA_PKCS1_V1_5_SHA_256"),
   815  			MessageType:      aws.String("RAW"),
   816  			Message:          []byte(dataToVerify),
   817  			Signature:        signatureBytes,
   818  		})
   819  	} else {
   820  		verifyOutput, e = k.kmsClient.VerifyWithContext(segCtx,
   821  			&kms.VerifyInput{
   822  				KeyId:            aws.String(keyId),
   823  				SigningAlgorithm: aws.String("RSASSA_PKCS1_V1_5_SHA_256"),
   824  				MessageType:      aws.String("RAW"),
   825  				Message:          []byte(dataToVerify),
   826  				Signature:        signatureBytes,
   827  			})
   828  	}
   829  
   830  	if e != nil {
   831  		err = errors.New("VerifyViaCmkRsa2048 with KMS Failed: (Verify Action) " + e.Error())
   832  		return false, err
   833  	}
   834  
   835  	// return verify result
   836  	signatureValid = *verifyOutput.SignatureValid
   837  	return signatureValid, nil
   838  }
   839  
   840  // ----------------------------------------------------------------------------------------------------------------
   841  // kms data-key encrypt/decrypt aes 256 functions
   842  // ----------------------------------------------------------------------------------------------------------------
   843  
   844  // GenerateDataKeyAes256 will return an encrypted data key generated by kms cmk,
   845  // this data key is encrypted, and able to decrypt only via kms cmk (therefore it is safe to store in memory or at rest)
   846  //
   847  // cipherKey = encrypted data key in hex (must use KMS CMK to decrypt such key)
   848  func (k *KMS) GenerateDataKeyAes256() (cipherKey string, err error) {
   849  	var segCtx context.Context
   850  	segCtx = nil
   851  
   852  	seg := xray.NewSegmentNullable("KMS-GenerateDataKeyAes256", k._parentSegment)
   853  
   854  	if seg != nil {
   855  		segCtx = seg.Ctx
   856  
   857  		defer seg.Close()
   858  		defer func() {
   859  			_ = seg.Seg.AddMetadata("KMS-GenerateDataKeyAes256-AES-KMS-KeyName", k.AesKmsKeyName)
   860  			_ = seg.Seg.AddMetadata("KMS-GenerateDataKeyAes256-Result-CipherKey-Length", len(cipherKey))
   861  
   862  			if err != nil {
   863  				_ = seg.Seg.AddError(err)
   864  			}
   865  		}()
   866  	}
   867  
   868  	// validate
   869  	if k.kmsClient == nil {
   870  		err = errors.New("GenerateDataKeyAes256 with KMS Failed: " + "KMS Client is Required")
   871  		return "", err
   872  	}
   873  
   874  	if len(k.AesKmsKeyName) <= 0 {
   875  		err = errors.New("GenerateDataKeyAes256 with KMS Failed: " + "AES KMS Key Name is Required")
   876  		return "", err
   877  	}
   878  
   879  	// prepare key info
   880  	keyId := "alias/" + k.AesKmsKeyName
   881  	keySpec := "AES_256" // always use AES 256
   882  	dataKeyInput := kms.GenerateDataKeyWithoutPlaintextInput{
   883  		KeyId:   aws.String(keyId),
   884  		KeySpec: aws.String(keySpec),
   885  	}
   886  
   887  	// generate data key
   888  	var dataKeyOutput *kms.GenerateDataKeyWithoutPlaintextOutput
   889  	var e error
   890  
   891  	if segCtx == nil {
   892  		dataKeyOutput, e = k.kmsClient.GenerateDataKeyWithoutPlaintext(&dataKeyInput)
   893  	} else {
   894  		dataKeyOutput, e = k.kmsClient.GenerateDataKeyWithoutPlaintextWithContext(segCtx, &dataKeyInput)
   895  	}
   896  
   897  	if e != nil {
   898  		err = errors.New("GenerateDataKeyAes256 with KMS Failed: (Gen Data Key) " + e.Error())
   899  		return "", err
   900  	}
   901  
   902  	// return encrypted key via cipherKey
   903  	cipherKey = util.ByteToHex(dataKeyOutput.CiphertextBlob)
   904  	return cipherKey, nil
   905  }
   906  
   907  // EncryptWithDataKeyAes256 will encrypt plainText using cipherKey that was generated via GenerateDataKeyAes256()
   908  //
   909  // cipherKey = encrypted data key in hex (must use KMS CMK to decrypt such key)
   910  func (k *KMS) EncryptWithDataKeyAes256(plainText string, cipherKey string) (cipherText string, err error) {
   911  	var segCtx context.Context
   912  	segCtx = nil
   913  
   914  	seg := xray.NewSegmentNullable("KMS-EncryptWithDataKeyAes256", k._parentSegment)
   915  
   916  	if seg != nil {
   917  		segCtx = seg.Ctx
   918  
   919  		defer seg.Close()
   920  		defer func() {
   921  			_ = seg.Seg.AddMetadata("KMS-EncryptWithDataKeyAes256-AES-KMS-KeyName", k.AesKmsKeyName)
   922  			_ = seg.Seg.AddMetadata("KMS-EncryptWithDataKeyAes256-PlainText-Length", len(plainText))
   923  			_ = seg.Seg.AddMetadata("KMS-EncryptWithDataKeyAes256-CipherKey-Length", len(cipherKey))
   924  			_ = seg.Seg.AddMetadata("KMS-EncryptWithDataKeyAes256-Result-CipherText-Length", len(cipherText))
   925  
   926  			if err != nil {
   927  				_ = seg.Seg.AddError(err)
   928  			}
   929  		}()
   930  	}
   931  
   932  	// validate
   933  	if k.kmsClient == nil {
   934  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: " + "KMS Client is Required")
   935  		return "", err
   936  	}
   937  
   938  	if len(k.AesKmsKeyName) <= 0 {
   939  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: " + "AES KMS Key Name is Required")
   940  		return "", err
   941  	}
   942  
   943  	if len(plainText) <= 0 {
   944  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: " + "PlainText is Required")
   945  		return "", err
   946  	}
   947  
   948  	if len(cipherKey) <= 0 {
   949  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: " + "CipherKey is Required")
   950  		return "", err
   951  	}
   952  
   953  	// prepare key info
   954  	keyId := "alias/" + k.AesKmsKeyName
   955  	cipherBytes, ce := util.HexToByte(cipherKey)
   956  
   957  	if ce != nil {
   958  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: (Unmarshal CipherKey Hex To Byte) " + ce.Error())
   959  		return "", err
   960  	}
   961  
   962  	// decrypt cipherKey using kms cmk
   963  	var dataKeyOutput *kms.DecryptOutput
   964  	var e error
   965  
   966  	if segCtx == nil {
   967  		dataKeyOutput, e = k.kmsClient.Decrypt(&kms.DecryptInput{
   968  			EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   969  			KeyId:               aws.String(keyId),
   970  			CiphertextBlob:      cipherBytes,
   971  		})
   972  	} else {
   973  		dataKeyOutput, e = k.kmsClient.DecryptWithContext(segCtx,
   974  			&kms.DecryptInput{
   975  				EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
   976  				KeyId:               aws.String(keyId),
   977  				CiphertextBlob:      cipherBytes,
   978  			})
   979  	}
   980  
   981  	if e != nil {
   982  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: (Decrypt Data Key) " + e.Error())
   983  		return "", err
   984  	}
   985  
   986  	// perform encryption action using decrypted plaintext data key
   987  	buf, e := crypto.AesGcmEncrypt(plainText, string(dataKeyOutput.Plaintext))
   988  
   989  	// clean up data key from memory immediately
   990  	dataKeyOutput.SetPlaintext([]byte{})
   991  	dataKeyOutput = nil
   992  
   993  	// evaluate encrypted result
   994  	if e != nil {
   995  		err = errors.New("EncryptWithDataKeyAes256 with KMS Failed: (Encrypt Data) " + e.Error())
   996  		return "", err
   997  	} else {
   998  		cipherText = buf
   999  	}
  1000  
  1001  	// return encrypted data
  1002  	return cipherText, nil
  1003  }
  1004  
  1005  // DecryptWithDataKeyAes256 will decrypt cipherText using cipherKey that was generated via GenerateDataKeyAes256()
  1006  //
  1007  // cipherKey = encrypted data key in hex (must use KMS CMK to decrypt such key)
  1008  func (k *KMS) DecryptWithDataKeyAes256(cipherText string, cipherKey string) (plainText string, err error) {
  1009  	var segCtx context.Context
  1010  	segCtx = nil
  1011  
  1012  	seg := xray.NewSegmentNullable("KMS-DecryptWithDataKeyAes256", k._parentSegment)
  1013  
  1014  	if seg != nil {
  1015  		segCtx = seg.Ctx
  1016  
  1017  		defer seg.Close()
  1018  		defer func() {
  1019  			_ = seg.Seg.AddMetadata("KMS-DecryptWithDataKeyAes256-AES-KMS-KeyName", k.AesKmsKeyName)
  1020  			_ = seg.Seg.AddMetadata("KMS-DecryptWithDataKeyAes256-CipherText-Length", len(cipherText))
  1021  			_ = seg.Seg.AddMetadata("KMS-DecryptWithDataKeyAes256-CipherKey-Length", len(cipherKey))
  1022  			_ = seg.Seg.AddMetadata("KMS-DecryptWithDataKeyAes256-Result-PlainText-Length", len(plainText))
  1023  
  1024  			if err != nil {
  1025  				_ = seg.Seg.AddError(err)
  1026  			}
  1027  		}()
  1028  	}
  1029  
  1030  	// validate
  1031  	if k.kmsClient == nil {
  1032  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: " + "KMS Client is Required")
  1033  		return "", err
  1034  	}
  1035  
  1036  	if len(k.AesKmsKeyName) <= 0 {
  1037  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: " + "AES KMS Key Name is Required")
  1038  		return "", err
  1039  	}
  1040  
  1041  	if len(cipherText) <= 0 {
  1042  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: " + "CipherText is Required")
  1043  		return "", err
  1044  	}
  1045  
  1046  	if len(cipherKey) <= 0 {
  1047  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: " + "CipherKey is Required")
  1048  		return "", err
  1049  	}
  1050  
  1051  	// prepare key info
  1052  	keyId := "alias/" + k.AesKmsKeyName
  1053  	cipherBytes, ce := util.HexToByte(cipherKey)
  1054  
  1055  	if ce != nil {
  1056  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: (Unmarshal CipherKey Hex To Byte) " + ce.Error())
  1057  		return "", err
  1058  	}
  1059  
  1060  	// decrypt cipherKey using kms cmk
  1061  	var dataKeyOutput *kms.DecryptOutput
  1062  	var e error
  1063  
  1064  	if segCtx == nil {
  1065  		dataKeyOutput, e = k.kmsClient.Decrypt(&kms.DecryptInput{
  1066  			EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
  1067  			KeyId:               aws.String(keyId),
  1068  			CiphertextBlob:      cipherBytes,
  1069  		})
  1070  	} else {
  1071  		dataKeyOutput, e = k.kmsClient.DecryptWithContext(segCtx,
  1072  			&kms.DecryptInput{
  1073  				EncryptionAlgorithm: aws.String("SYMMETRIC_DEFAULT"),
  1074  				KeyId:               aws.String(keyId),
  1075  				CiphertextBlob:      cipherBytes,
  1076  			})
  1077  	}
  1078  
  1079  	if e != nil {
  1080  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: (Decrypt Data Key) " + e.Error())
  1081  		return "", err
  1082  	}
  1083  
  1084  	// perform decryption action using decrypted plaintext data key
  1085  	buf, e := crypto.AesGcmDecrypt(cipherText, string(dataKeyOutput.Plaintext))
  1086  
  1087  	// clean up data key from memory immediately
  1088  	dataKeyOutput.SetPlaintext([]byte{})
  1089  	dataKeyOutput = nil
  1090  
  1091  	// evaluate decrypted result
  1092  	if e != nil {
  1093  		err = errors.New("DecryptWithDataKeyAes256 with KMS Failed: (Decrypt Data) " + e.Error())
  1094  		return "", err
  1095  	} else {
  1096  		plainText = buf
  1097  	}
  1098  
  1099  	// return decrypted data
  1100  	return plainText, nil
  1101  }