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  }