123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- /*
- *
- * Copyright 2018 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- package conn
- import (
- "crypto/cipher"
- core "google.golang.org/grpc/credentials/alts/internal"
- )
- const (
- // Overflow length n in bytes, never encrypt more than 2^(n*8) frames (in
- // each direction).
- overflowLenAES128GCMRekey = 8
- nonceLen = 12
- aeadKeyLen = 16
- kdfKeyLen = 32
- kdfCounterOffset = 2
- kdfCounterLen = 6
- sizeUint64 = 8
- )
- // aes128gcmRekey is the struct that holds necessary information for ALTS record.
- // The counter value is NOT included in the payload during the encryption and
- // decryption operations.
- type aes128gcmRekey struct {
- // inCounter is used in ALTS record to check that incoming counters are
- // as expected, since ALTS record guarantees that messages are unwrapped
- // in the same order that the peer wrapped them.
- inCounter Counter
- outCounter Counter
- inAEAD cipher.AEAD
- outAEAD cipher.AEAD
- }
- // NewAES128GCMRekey creates an instance that uses aes128gcm with rekeying
- // for ALTS record. The key argument should be 44 bytes, the first 32 bytes
- // are used as a key for HKDF-expand and the remainining 12 bytes are used
- // as a random mask for the counter.
- func NewAES128GCMRekey(side core.Side, key []byte) (ALTSRecordCrypto, error) {
- inCounter := NewInCounter(side, overflowLenAES128GCMRekey)
- outCounter := NewOutCounter(side, overflowLenAES128GCMRekey)
- inAEAD, err := newRekeyAEAD(key)
- if err != nil {
- return nil, err
- }
- outAEAD, err := newRekeyAEAD(key)
- if err != nil {
- return nil, err
- }
- return &aes128gcmRekey{
- inCounter,
- outCounter,
- inAEAD,
- outAEAD,
- }, nil
- }
- // Encrypt is the encryption function. dst can contain bytes at the beginning of
- // the ciphertext that will not be encrypted but will be authenticated. If dst
- // has enough capacity to hold these bytes, the ciphertext and the tag, no
- // allocation and copy operations will be performed. dst and plaintext do not
- // overlap.
- func (s *aes128gcmRekey) Encrypt(dst, plaintext []byte) ([]byte, error) {
- // If we need to allocate an output buffer, we want to include space for
- // GCM tag to avoid forcing ALTS record to reallocate as well.
- dlen := len(dst)
- dst, out := SliceForAppend(dst, len(plaintext)+GcmTagSize)
- seq, err := s.outCounter.Value()
- if err != nil {
- return nil, err
- }
- data := out[:len(plaintext)]
- copy(data, plaintext) // data may alias plaintext
- // Seal appends the ciphertext and the tag to its first argument and
- // returns the updated slice. However, SliceForAppend above ensures that
- // dst has enough capacity to avoid a reallocation and copy due to the
- // append.
- dst = s.outAEAD.Seal(dst[:dlen], seq, data, nil)
- s.outCounter.Inc()
- return dst, nil
- }
- func (s *aes128gcmRekey) EncryptionOverhead() int {
- return GcmTagSize
- }
- func (s *aes128gcmRekey) Decrypt(dst, ciphertext []byte) ([]byte, error) {
- seq, err := s.inCounter.Value()
- if err != nil {
- return nil, err
- }
- plaintext, err := s.inAEAD.Open(dst, seq, ciphertext, nil)
- if err != nil {
- return nil, ErrAuth
- }
- s.inCounter.Inc()
- return plaintext, nil
- }
|