fips140.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. //go:build fips140v1.0
  2. // +build fips140v1.0
  3. package noiseutil
  4. import (
  5. "crypto/cipher"
  6. "encoding/binary"
  7. // unsafe needed for go:linkname
  8. _ "unsafe"
  9. "github.com/flynn/noise"
  10. )
  11. // EncryptLockNeeded indicates if calls to Encrypt need a lock
  12. // This is true for fips140 because the Seal function verifies that the
  13. // nonce is strictly increasing.
  14. const EncryptLockNeeded = true
  15. // TODO: Use NewGCMWithCounterNonce once available:
  16. // - https://github.com/golang/go/issues/73110
  17. // Using tls.aeadAESGCM gives us the TLS 1.2 GCM, which also verifies
  18. // that the nonce is strictly increasing.
  19. //
  20. //go:linkname aeadAESGCM crypto/tls.aeadAESGCM
  21. func aeadAESGCM(key, noncePrefix []byte) cipher.AEAD
  22. type cipherFn struct {
  23. fn func([32]byte) noise.Cipher
  24. name string
  25. }
  26. func (c cipherFn) Cipher(k [32]byte) noise.Cipher { return c.fn(k) }
  27. func (c cipherFn) CipherName() string { return c.name }
  28. // CipherAESGCM is the AES256-GCM AEAD cipher (using aeadAESGCM when fips140 is enabled)
  29. var CipherAESGCM noise.CipherFunc = cipherFn{cipherAESGCM, "AESGCM"}
  30. // tls.aeadAESGCM uses a 4 byte static prefix and an 8 byte nonce
  31. var emptyPrefix = []byte{0, 0, 0, 0}
  32. func cipherAESGCM(k [32]byte) noise.Cipher {
  33. gcm := aeadAESGCM(k[:], emptyPrefix)
  34. return aeadCipher{
  35. gcm,
  36. func(n uint64) []byte {
  37. // tls.aeadAESGCM uses a 4 byte static prefix and an 8 byte nonce
  38. var nonce [8]byte
  39. binary.BigEndian.PutUint64(nonce[:], n)
  40. return nonce[:]
  41. },
  42. }
  43. }
  44. type aeadCipher struct {
  45. cipher.AEAD
  46. nonce func(uint64) []byte
  47. }
  48. func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte {
  49. return c.Seal(out, c.nonce(n), plaintext, ad)
  50. }
  51. func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) {
  52. return c.Open(out, c.nonce(n), ciphertext, ad)
  53. }
  54. func (c aeadCipher) EncryptDanger(out, ad, plaintext []byte, n uint64, nb []byte) ([]byte, error) {
  55. binary.BigEndian.PutUint64(nb[4:], n)
  56. out = c.Seal(out, nb[4:], plaintext, ad)
  57. return out, nil
  58. }
  59. func (c aeadCipher) DecryptDanger(out, ad, ciphertext []byte, n uint64, nb []byte) ([]byte, error) {
  60. binary.BigEndian.PutUint64(nb[4:], n)
  61. return c.Open(out, nb[4:], ciphertext, ad)
  62. }