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 }