github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/s3crypto/aes_gcm_content_cipher.go (about)

     1  package s3crypto
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/aavshr/aws-sdk-go/aws"
     8  )
     9  
    10  const (
    11  	gcmKeySize   = 32
    12  	gcmNonceSize = 12
    13  )
    14  
    15  // AESGCMContentCipherBuilder returns a new encryption only AES/GCM mode structure with a specific cipher data generator
    16  // that will provide keys to be used for content encryption.
    17  //
    18  // Note: This uses the Go stdlib AEAD implementation for AES/GCM. Due to this objects to be encrypted or decrypted
    19  // will be fully loaded into memory before encryption or decryption can occur. Caution must be taken to avoid memory
    20  // allocation failures.
    21  //
    22  // deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.
    23  func AESGCMContentCipherBuilder(generator CipherDataGenerator) ContentCipherBuilder {
    24  	return gcmContentCipherBuilder{generator}
    25  }
    26  
    27  // AESGCMContentCipherBuilderV2 returns a new encryption only AES/GCM mode structure with a specific cipher data generator
    28  // that will provide keys to be used for content encryption. This type is compatible with the V2 encryption client.
    29  //
    30  // Note: This uses the Go stdlib AEAD implementation for AES/GCM. Due to this objects to be encrypted or decrypted
    31  // will be fully loaded into memory before encryption or decryption can occur. Caution must be taken to avoid memory
    32  // allocation failures.
    33  func AESGCMContentCipherBuilderV2(generator CipherDataGeneratorWithCEKAlg) ContentCipherBuilder {
    34  	return gcmContentCipherBuilderV2{generator}
    35  }
    36  
    37  // RegisterAESGCMContentCipher registers the AES/GCM content cipher algorithm with the provided CryptoRegistry.
    38  //
    39  // Example:
    40  //	cr := s3crypto.NewCryptoRegistry()
    41  //	if err := s3crypto.RegisterAESGCMContentCipher(cr); err != nil {
    42  //		panic(err) // handle error
    43  //	}
    44  //
    45  func RegisterAESGCMContentCipher(registry *CryptoRegistry) error {
    46  	if registry == nil {
    47  		return errNilCryptoRegistry
    48  	}
    49  
    50  	err := registry.AddCEK(AESGCMNoPadding, newAESGCMContentCipher)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	// NoPadder is generic but required by this algorithm, so if it is already registered and is the expected implementation
    56  	// don't error.
    57  	padderName := NoPadder.Name()
    58  	if v, ok := registry.GetPadder(padderName); !ok {
    59  		if err := registry.AddPadder(padderName, NoPadder); err != nil {
    60  			return err
    61  		}
    62  	} else if _, ok := v.(noPadder); !ok {
    63  		return fmt.Errorf("%s is already registred but does not match expected type %T", padderName, NoPadder)
    64  	}
    65  	return nil
    66  }
    67  
    68  // gcmContentCipherBuilder is a AES/GCM content cipher to be used with the V1 client CipherDataGenerator interface
    69  type gcmContentCipherBuilder struct {
    70  	generator CipherDataGenerator
    71  }
    72  
    73  func (builder gcmContentCipherBuilder) ContentCipher() (ContentCipher, error) {
    74  	return builder.ContentCipherWithContext(aws.BackgroundContext())
    75  }
    76  
    77  func (builder gcmContentCipherBuilder) ContentCipherWithContext(ctx aws.Context) (ContentCipher, error) {
    78  	var cd CipherData
    79  	var err error
    80  
    81  	switch v := builder.generator.(type) {
    82  	case CipherDataGeneratorWithContext:
    83  		cd, err = v.GenerateCipherDataWithContext(ctx, gcmKeySize, gcmNonceSize)
    84  	default:
    85  		cd, err = builder.generator.GenerateCipherData(gcmKeySize, gcmNonceSize)
    86  	}
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	return newAESGCMContentCipher(cd)
    92  }
    93  
    94  // isFixtureEncryptionCompatible will ensure that this type may only be used with the V1 client
    95  func (builder gcmContentCipherBuilder) isEncryptionVersionCompatible(version clientVersion) error {
    96  	if version != v1ClientVersion {
    97  		return errDeprecatedIncompatibleCipherBuilder
    98  	}
    99  	return nil
   100  }
   101  
   102  func (builder gcmContentCipherBuilder) isAWSFixture() bool {
   103  	return true
   104  }
   105  
   106  // gcmContentCipherBuilderV2 return a new builder for encryption content using AES/GCM/NoPadding. This type is meant
   107  // to be used with key wrapping implementations that allow the cek algorithm to be provided when calling the
   108  // cipher data generator.
   109  type gcmContentCipherBuilderV2 struct {
   110  	generator CipherDataGeneratorWithCEKAlg
   111  }
   112  
   113  func (builder gcmContentCipherBuilderV2) ContentCipher() (ContentCipher, error) {
   114  	return builder.ContentCipherWithContext(aws.BackgroundContext())
   115  }
   116  
   117  func (builder gcmContentCipherBuilderV2) ContentCipherWithContext(ctx aws.Context) (ContentCipher, error) {
   118  	cd, err := builder.generator.GenerateCipherDataWithCEKAlg(ctx, gcmKeySize, gcmNonceSize, AESGCMNoPadding)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	return newAESGCMContentCipher(cd)
   124  }
   125  
   126  // isFixtureEncryptionCompatible will ensure that this type may only be used with the V2 client
   127  func (builder gcmContentCipherBuilderV2) isEncryptionVersionCompatible(version clientVersion) error {
   128  	if version != v2ClientVersion {
   129  		return errDeprecatedIncompatibleCipherBuilder
   130  	}
   131  	return nil
   132  }
   133  
   134  // isAWSFixture will return whether this type was constructed with an AWS provided CipherDataGenerator
   135  func (builder gcmContentCipherBuilderV2) isAWSFixture() bool {
   136  	v, ok := builder.generator.(awsFixture)
   137  	return ok && v.isAWSFixture()
   138  }
   139  
   140  func newAESGCMContentCipher(cd CipherData) (ContentCipher, error) {
   141  	cd.CEKAlgorithm = AESGCMNoPadding
   142  	cd.TagLength = "128"
   143  
   144  	cipher, err := newAESGCM(cd)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	return &aesGCMContentCipher{
   150  		CipherData: cd,
   151  		Cipher:     cipher,
   152  	}, nil
   153  }
   154  
   155  // AESGCMContentCipher will use AES GCM for the main cipher.
   156  type aesGCMContentCipher struct {
   157  	CipherData CipherData
   158  	Cipher     Cipher
   159  }
   160  
   161  // EncryptContents will generate a random key and iv and encrypt the data using cbc
   162  func (cc *aesGCMContentCipher) EncryptContents(src io.Reader) (io.Reader, error) {
   163  	return cc.Cipher.Encrypt(src), nil
   164  }
   165  
   166  // DecryptContents will use the symmetric key provider to instantiate a new GCM cipher.
   167  // We grab a decrypt reader from gcm and wrap it in a CryptoReadCloser. The only error
   168  // expected here is when the key or iv is of invalid length.
   169  func (cc *aesGCMContentCipher) DecryptContents(src io.ReadCloser) (io.ReadCloser, error) {
   170  	reader := cc.Cipher.Decrypt(src)
   171  	return &CryptoReadCloser{Body: src, Decrypter: reader}, nil
   172  }
   173  
   174  // GetCipherData returns cipher data
   175  func (cc aesGCMContentCipher) GetCipherData() CipherData {
   176  	return cc.CipherData
   177  }
   178  
   179  // assert ContentCipherBuilder implementations
   180  var (
   181  	_ ContentCipherBuilder = (*gcmContentCipherBuilder)(nil)
   182  	_ ContentCipherBuilder = (*gcmContentCipherBuilderV2)(nil)
   183  )
   184  
   185  // assert ContentCipherBuilderWithContext implementations
   186  var (
   187  	_ ContentCipherBuilderWithContext = (*gcmContentCipherBuilder)(nil)
   188  	_ ContentCipherBuilderWithContext = (*gcmContentCipherBuilderV2)(nil)
   189  )
   190  
   191  // assert ContentCipher implementations
   192  var (
   193  	_ ContentCipher = (*aesGCMContentCipher)(nil)
   194  )
   195  
   196  // assert awsFixture implementations
   197  var (
   198  	_ awsFixture = (*gcmContentCipherBuilderV2)(nil)
   199  )