123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- /*
- *
- * 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/aes"
- "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).
- overflowLenAES128GCM = 5
- )
- // aes128gcm 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 aes128gcm 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
- aead cipher.AEAD
- }
- // NewAES128GCM creates an instance that uses aes128gcm for ALTS record.
- func NewAES128GCM(side core.Side, key []byte) (ALTSRecordCrypto, error) {
- c, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- a, err := cipher.NewGCM(c)
- if err != nil {
- return nil, err
- }
- return &aes128gcm{
- inCounter: NewInCounter(side, overflowLenAES128GCM),
- outCounter: NewOutCounter(side, overflowLenAES128GCM),
- aead: a,
- }, 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 *aes128gcm) 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.aead.Seal(dst[:dlen], seq, data, nil)
- s.outCounter.Inc()
- return dst, nil
- }
- func (s *aes128gcm) EncryptionOverhead() int {
- return GcmTagSize
- }
- func (s *aes128gcm) Decrypt(dst, ciphertext []byte) ([]byte, error) {
- seq, err := s.inCounter.Value()
- if err != nil {
- return nil, err
- }
- // If dst is equal to ciphertext[:0], ciphertext storage is reused.
- plaintext, err := s.aead.Open(dst, seq, ciphertext, nil)
- if err != nil {
- return nil, ErrAuth
- }
- s.inCounter.Inc()
- return plaintext, nil
- }
|