boring.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. //go:build boringcrypto
  2. // +build boringcrypto
  3. package noiseutil
  4. import (
  5. "crypto/aes"
  6. "crypto/cipher"
  7. "encoding/binary"
  8. // unsafe needed for go:linkname
  9. _ "unsafe"
  10. "github.com/flynn/noise"
  11. )
  12. // EncryptLockNeeded indicates if calls to Encrypt need a lock
  13. // This is true for boringcrypto because the Seal function verifies that the
  14. // nonce is strictly increasing.
  15. const EncryptLockNeeded = true
  16. // NewGCMTLS is no longer exposed in go1.19+, so we need to link it in
  17. // See: https://github.com/golang/go/issues/56326
  18. //
  19. // NewGCMTLS is the internal method used with boringcrypto that provices a
  20. // validated mode of AES-GCM which enforces the nonce is strictly
  21. // monotonically increasing. This is the TLS 1.2 specification for nonce
  22. // generation (which also matches the method used by the Noise Protocol)
  23. //
  24. // - https://github.com/golang/go/blob/go1.19/src/crypto/tls/cipher_suites.go#L520-L522
  25. // - https://github.com/golang/go/blob/go1.19/src/crypto/internal/boring/aes.go#L235-L237
  26. // - https://github.com/golang/go/blob/go1.19/src/crypto/internal/boring/aes.go#L250
  27. // - https://github.com/google/boringssl/blob/ae223d6138807a13006342edfeef32e813246b39/include/openssl/aead.h#L379-L381
  28. // - https://github.com/google/boringssl/blob/ae223d6138807a13006342edfeef32e813246b39/crypto/fipsmodule/cipher/e_aes.c#L1082-L1093
  29. //
  30. //go:linkname newGCMTLS crypto/internal/boring.NewGCMTLS
  31. func newGCMTLS(c cipher.Block) (cipher.AEAD, error)
  32. type cipherFn struct {
  33. fn func([32]byte) noise.Cipher
  34. name string
  35. }
  36. func (c cipherFn) Cipher(k [32]byte) noise.Cipher { return c.fn(k) }
  37. func (c cipherFn) CipherName() string { return c.name }
  38. // CipherAESGCM is the AES256-GCM AEAD cipher (using NewGCMTLS when GoBoring is present)
  39. var CipherAESGCM noise.CipherFunc = cipherFn{cipherAESGCMBoring, "AESGCM"}
  40. func cipherAESGCMBoring(k [32]byte) noise.Cipher {
  41. c, err := aes.NewCipher(k[:])
  42. if err != nil {
  43. panic(err)
  44. }
  45. gcm, err := newGCMTLS(c)
  46. if err != nil {
  47. panic(err)
  48. }
  49. return aeadCipher{
  50. gcm,
  51. func(n uint64) []byte {
  52. var nonce [12]byte
  53. binary.BigEndian.PutUint64(nonce[4:], n)
  54. return nonce[:]
  55. },
  56. }
  57. }
  58. type aeadCipher struct {
  59. cipher.AEAD
  60. nonce func(uint64) []byte
  61. }
  62. func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte {
  63. return c.Seal(out, c.nonce(n), plaintext, ad)
  64. }
  65. func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) {
  66. return c.Open(out, c.nonce(n), ciphertext, ad)
  67. }