google.golang.org/grpc@v1.62.1/credentials/alts/internal/conn/aes128gcm.go (about) 1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package conn 20 21 import ( 22 "crypto/aes" 23 "crypto/cipher" 24 25 core "google.golang.org/grpc/credentials/alts/internal" 26 ) 27 28 const ( 29 // Overflow length n in bytes, never encrypt more than 2^(n*8) frames (in 30 // each direction). 31 overflowLenAES128GCM = 5 32 ) 33 34 // aes128gcm is the struct that holds necessary information for ALTS record. 35 // The counter value is NOT included in the payload during the encryption and 36 // decryption operations. 37 type aes128gcm struct { 38 // inCounter is used in ALTS record to check that incoming counters are 39 // as expected, since ALTS record guarantees that messages are unwrapped 40 // in the same order that the peer wrapped them. 41 inCounter Counter 42 outCounter Counter 43 aead cipher.AEAD 44 } 45 46 // NewAES128GCM creates an instance that uses aes128gcm for ALTS record. 47 func NewAES128GCM(side core.Side, key []byte) (ALTSRecordCrypto, error) { 48 c, err := aes.NewCipher(key) 49 if err != nil { 50 return nil, err 51 } 52 a, err := cipher.NewGCM(c) 53 if err != nil { 54 return nil, err 55 } 56 return &aes128gcm{ 57 inCounter: NewInCounter(side, overflowLenAES128GCM), 58 outCounter: NewOutCounter(side, overflowLenAES128GCM), 59 aead: a, 60 }, nil 61 } 62 63 // Encrypt is the encryption function. dst can contain bytes at the beginning of 64 // the ciphertext that will not be encrypted but will be authenticated. If dst 65 // has enough capacity to hold these bytes, the ciphertext and the tag, no 66 // allocation and copy operations will be performed. dst and plaintext do not 67 // overlap. 68 func (s *aes128gcm) Encrypt(dst, plaintext []byte) ([]byte, error) { 69 // If we need to allocate an output buffer, we want to include space for 70 // GCM tag to avoid forcing ALTS record to reallocate as well. 71 dlen := len(dst) 72 dst, out := SliceForAppend(dst, len(plaintext)+GcmTagSize) 73 seq, err := s.outCounter.Value() 74 if err != nil { 75 return nil, err 76 } 77 data := out[:len(plaintext)] 78 copy(data, plaintext) // data may alias plaintext 79 80 // Seal appends the ciphertext and the tag to its first argument and 81 // returns the updated slice. However, SliceForAppend above ensures that 82 // dst has enough capacity to avoid a reallocation and copy due to the 83 // append. 84 dst = s.aead.Seal(dst[:dlen], seq, data, nil) 85 s.outCounter.Inc() 86 return dst, nil 87 } 88 89 func (s *aes128gcm) EncryptionOverhead() int { 90 return GcmTagSize 91 } 92 93 func (s *aes128gcm) Decrypt(dst, ciphertext []byte) ([]byte, error) { 94 seq, err := s.inCounter.Value() 95 if err != nil { 96 return nil, err 97 } 98 // If dst is equal to ciphertext[:0], ciphertext storage is reused. 99 plaintext, err := s.aead.Open(dst, seq, ciphertext, nil) 100 if err != nil { 101 return nil, ErrAuth 102 } 103 s.inCounter.Inc() 104 return plaintext, nil 105 }