aes128gcm.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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/aes"
  21. "crypto/cipher"
  22. core "google.golang.org/grpc/credentials/alts/internal"
  23. )
  24. const (
  25. // Overflow length n in bytes, never encrypt more than 2^(n*8) frames (in
  26. // each direction).
  27. overflowLenAES128GCM = 5
  28. )
  29. // aes128gcm is the struct that holds necessary information for ALTS record.
  30. // The counter value is NOT included in the payload during the encryption and
  31. // decryption operations.
  32. type aes128gcm struct {
  33. // inCounter is used in ALTS record to check that incoming counters are
  34. // as expected, since ALTS record guarantees that messages are unwrapped
  35. // in the same order that the peer wrapped them.
  36. inCounter Counter
  37. outCounter Counter
  38. aead cipher.AEAD
  39. }
  40. // NewAES128GCM creates an instance that uses aes128gcm for ALTS record.
  41. func NewAES128GCM(side core.Side, key []byte) (ALTSRecordCrypto, error) {
  42. c, err := aes.NewCipher(key)
  43. if err != nil {
  44. return nil, err
  45. }
  46. a, err := cipher.NewGCM(c)
  47. if err != nil {
  48. return nil, err
  49. }
  50. return &aes128gcm{
  51. inCounter: NewInCounter(side, overflowLenAES128GCM),
  52. outCounter: NewOutCounter(side, overflowLenAES128GCM),
  53. aead: a,
  54. }, nil
  55. }
  56. // Encrypt is the encryption function. dst can contain bytes at the beginning of
  57. // the ciphertext that will not be encrypted but will be authenticated. If dst
  58. // has enough capacity to hold these bytes, the ciphertext and the tag, no
  59. // allocation and copy operations will be performed. dst and plaintext do not
  60. // overlap.
  61. func (s *aes128gcm) Encrypt(dst, plaintext []byte) ([]byte, error) {
  62. // If we need to allocate an output buffer, we want to include space for
  63. // GCM tag to avoid forcing ALTS record to reallocate as well.
  64. dlen := len(dst)
  65. dst, out := SliceForAppend(dst, len(plaintext)+GcmTagSize)
  66. seq, err := s.outCounter.Value()
  67. if err != nil {
  68. return nil, err
  69. }
  70. data := out[:len(plaintext)]
  71. copy(data, plaintext) // data may alias plaintext
  72. // Seal appends the ciphertext and the tag to its first argument and
  73. // returns the updated slice. However, SliceForAppend above ensures that
  74. // dst has enough capacity to avoid a reallocation and copy due to the
  75. // append.
  76. dst = s.aead.Seal(dst[:dlen], seq, data, nil)
  77. s.outCounter.Inc()
  78. return dst, nil
  79. }
  80. func (s *aes128gcm) EncryptionOverhead() int {
  81. return GcmTagSize
  82. }
  83. func (s *aes128gcm) Decrypt(dst, ciphertext []byte) ([]byte, error) {
  84. seq, err := s.inCounter.Value()
  85. if err != nil {
  86. return nil, err
  87. }
  88. // If dst is equal to ciphertext[:0], ciphertext storage is reused.
  89. plaintext, err := s.aead.Open(dst, seq, ciphertext, nil)
  90. if err != nil {
  91. return nil, ErrAuth
  92. }
  93. s.inCounter.Inc()
  94. return plaintext, nil
  95. }