aes128gcmrekey.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. package conn
  19. import (
  20. "crypto/cipher"
  21. core "google.golang.org/grpc/credentials/alts/internal"
  22. )
  23. const (
  24. // Overflow length n in bytes, never encrypt more than 2^(n*8) frames (in
  25. // each direction).
  26. overflowLenAES128GCMRekey = 8
  27. nonceLen = 12
  28. aeadKeyLen = 16
  29. kdfKeyLen = 32
  30. kdfCounterOffset = 2
  31. kdfCounterLen = 6
  32. sizeUint64 = 8
  33. )
  34. // aes128gcmRekey 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 aes128gcmRekey 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. inAEAD cipher.AEAD
  44. outAEAD cipher.AEAD
  45. }
  46. // NewAES128GCMRekey creates an instance that uses aes128gcm with rekeying
  47. // for ALTS record. The key argument should be 44 bytes, the first 32 bytes
  48. // are used as a key for HKDF-expand and the remainining 12 bytes are used
  49. // as a random mask for the counter.
  50. func NewAES128GCMRekey(side core.Side, key []byte) (ALTSRecordCrypto, error) {
  51. inCounter := NewInCounter(side, overflowLenAES128GCMRekey)
  52. outCounter := NewOutCounter(side, overflowLenAES128GCMRekey)
  53. inAEAD, err := newRekeyAEAD(key)
  54. if err != nil {
  55. return nil, err
  56. }
  57. outAEAD, err := newRekeyAEAD(key)
  58. if err != nil {
  59. return nil, err
  60. }
  61. return &aes128gcmRekey{
  62. inCounter,
  63. outCounter,
  64. inAEAD,
  65. outAEAD,
  66. }, nil
  67. }
  68. // Encrypt is the encryption function. dst can contain bytes at the beginning of
  69. // the ciphertext that will not be encrypted but will be authenticated. If dst
  70. // has enough capacity to hold these bytes, the ciphertext and the tag, no
  71. // allocation and copy operations will be performed. dst and plaintext do not
  72. // overlap.
  73. func (s *aes128gcmRekey) Encrypt(dst, plaintext []byte) ([]byte, error) {
  74. // If we need to allocate an output buffer, we want to include space for
  75. // GCM tag to avoid forcing ALTS record to reallocate as well.
  76. dlen := len(dst)
  77. dst, out := SliceForAppend(dst, len(plaintext)+GcmTagSize)
  78. seq, err := s.outCounter.Value()
  79. if err != nil {
  80. return nil, err
  81. }
  82. data := out[:len(plaintext)]
  83. copy(data, plaintext) // data may alias plaintext
  84. // Seal appends the ciphertext and the tag to its first argument and
  85. // returns the updated slice. However, SliceForAppend above ensures that
  86. // dst has enough capacity to avoid a reallocation and copy due to the
  87. // append.
  88. dst = s.outAEAD.Seal(dst[:dlen], seq, data, nil)
  89. s.outCounter.Inc()
  90. return dst, nil
  91. }
  92. func (s *aes128gcmRekey) EncryptionOverhead() int {
  93. return GcmTagSize
  94. }
  95. func (s *aes128gcmRekey) Decrypt(dst, ciphertext []byte) ([]byte, error) {
  96. seq, err := s.inCounter.Value()
  97. if err != nil {
  98. return nil, err
  99. }
  100. plaintext, err := s.inAEAD.Open(dst, seq, ciphertext, nil)
  101. if err != nil {
  102. return nil, ErrAuth
  103. }
  104. s.inCounter.Inc()
  105. return plaintext, nil
  106. }