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 )