gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/credentials/alts/internal/conn/aeadrekey.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  	"bytes"
    23  	"crypto/aes"
    24  	"crypto/cipher"
    25  	"crypto/hmac"
    26  	"crypto/sha256"
    27  	"encoding/binary"
    28  	"fmt"
    29  	"strconv"
    30  )
    31  
    32  // rekeyAEAD holds the necessary information for an AEAD based on
    33  // AES-GCM that performs nonce-based key derivation and XORs the
    34  // nonce with a random mask.
    35  type rekeyAEAD struct {
    36  	kdfKey     []byte
    37  	kdfCounter []byte
    38  	nonceMask  []byte
    39  	nonceBuf   []byte
    40  	gcmAEAD    cipher.AEAD
    41  }
    42  
    43  // KeySizeError signals that the given key does not have the correct size.
    44  type KeySizeError int
    45  
    46  func (k KeySizeError) Error() string {
    47  	return "alts/conn: invalid key size " + strconv.Itoa(int(k))
    48  }
    49  
    50  // newRekeyAEAD creates a new instance of aes128gcm with rekeying.
    51  // The key argument should be 44 bytes, the first 32 bytes are used as a key
    52  // for HKDF-expand and the remainining 12 bytes are used as a random mask for
    53  // the counter.
    54  func newRekeyAEAD(key []byte) (*rekeyAEAD, error) {
    55  	k := len(key)
    56  	if k != kdfKeyLen+nonceLen {
    57  		return nil, KeySizeError(k)
    58  	}
    59  	return &rekeyAEAD{
    60  		kdfKey:     key[:kdfKeyLen],
    61  		kdfCounter: make([]byte, kdfCounterLen),
    62  		nonceMask:  key[kdfKeyLen:],
    63  		nonceBuf:   make([]byte, nonceLen),
    64  		gcmAEAD:    nil,
    65  	}, nil
    66  }
    67  
    68  // Seal rekeys if nonce[2:8] is different than in the last call, masks the nonce,
    69  // and calls Seal for aes128gcm.
    70  func (s *rekeyAEAD) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
    71  	if err := s.rekeyIfRequired(nonce); err != nil {
    72  		panic(fmt.Sprintf("Rekeying failed with: %s", err.Error()))
    73  	}
    74  	maskNonce(s.nonceBuf, nonce, s.nonceMask)
    75  	return s.gcmAEAD.Seal(dst, s.nonceBuf, plaintext, additionalData)
    76  }
    77  
    78  // Open rekeys if nonce[2:8] is different than in the last call, masks the nonce,
    79  // and calls Open for aes128gcm.
    80  func (s *rekeyAEAD) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    81  	if err := s.rekeyIfRequired(nonce); err != nil {
    82  		return nil, err
    83  	}
    84  	maskNonce(s.nonceBuf, nonce, s.nonceMask)
    85  	return s.gcmAEAD.Open(dst, s.nonceBuf, ciphertext, additionalData)
    86  }
    87  
    88  // rekeyIfRequired creates a new aes128gcm AEAD if the existing AEAD is nil
    89  // or cannot be used with given nonce.
    90  func (s *rekeyAEAD) rekeyIfRequired(nonce []byte) error {
    91  	newKdfCounter := nonce[kdfCounterOffset : kdfCounterOffset+kdfCounterLen]
    92  	if s.gcmAEAD != nil && bytes.Equal(newKdfCounter, s.kdfCounter) {
    93  		return nil
    94  	}
    95  	copy(s.kdfCounter, newKdfCounter)
    96  	a, err := aes.NewCipher(hkdfExpand(s.kdfKey, s.kdfCounter))
    97  	if err != nil {
    98  		return err
    99  	}
   100  	s.gcmAEAD, err = cipher.NewGCM(a)
   101  	return err
   102  }
   103  
   104  // maskNonce XORs the given nonce with the mask and stores the result in dst.
   105  func maskNonce(dst, nonce, mask []byte) {
   106  	nonce1 := binary.LittleEndian.Uint64(nonce[:sizeUint64])
   107  	nonce2 := binary.LittleEndian.Uint32(nonce[sizeUint64:])
   108  	mask1 := binary.LittleEndian.Uint64(mask[:sizeUint64])
   109  	mask2 := binary.LittleEndian.Uint32(mask[sizeUint64:])
   110  	binary.LittleEndian.PutUint64(dst[:sizeUint64], nonce1^mask1)
   111  	binary.LittleEndian.PutUint32(dst[sizeUint64:], nonce2^mask2)
   112  }
   113  
   114  // NonceSize returns the required nonce size.
   115  func (s *rekeyAEAD) NonceSize() int {
   116  	return s.gcmAEAD.NonceSize()
   117  }
   118  
   119  // Overhead returns the ciphertext overhead.
   120  func (s *rekeyAEAD) Overhead() int {
   121  	return s.gcmAEAD.Overhead()
   122  }
   123  
   124  // hkdfExpand computes the first 16 bytes of the HKDF-expand function
   125  // defined in RFC5869.
   126  func hkdfExpand(key, info []byte) []byte {
   127  	mac := hmac.New(sha256.New, key)
   128  	mac.Write(info)
   129  	mac.Write([]byte{0x01}[:])
   130  	return mac.Sum(nil)[:aeadKeyLen]
   131  }