cipher_suite.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. package noise
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "crypto/sha256"
  7. "crypto/sha512"
  8. "encoding/binary"
  9. "hash"
  10. "io"
  11. "golang.org/x/crypto/blake2b"
  12. "golang.org/x/crypto/blake2s"
  13. "golang.org/x/crypto/chacha20poly1305"
  14. "golang.org/x/crypto/curve25519"
  15. )
  16. // A DHKey is a keypair used for Diffie-Hellman key agreement.
  17. type DHKey struct {
  18. Private []byte
  19. Public []byte
  20. }
  21. // A DHFunc implements Diffie-Hellman key agreement.
  22. type DHFunc interface {
  23. // GenerateKeypair generates a new keypair using random as a source of
  24. // entropy.
  25. GenerateKeypair(random io.Reader) (DHKey, error)
  26. // DH performs a Diffie-Hellman calculation between the provided private and
  27. // public keys and returns the result.
  28. DH(privkey, pubkey []byte) ([]byte, error)
  29. // DHLen is the number of bytes returned by DH.
  30. DHLen() int
  31. // DHName is the name of the DH function.
  32. DHName() string
  33. }
  34. // A HashFunc implements a cryptographic hash function.
  35. type HashFunc interface {
  36. // Hash returns a hash state.
  37. Hash() hash.Hash
  38. // HashName is the name of the hash function.
  39. HashName() string
  40. }
  41. // A CipherFunc implements an AEAD symmetric cipher.
  42. type CipherFunc interface {
  43. // Cipher initializes the algorithm with the provided key and returns a Cipher.
  44. Cipher(k [32]byte) Cipher
  45. // CipherName is the name of the cipher.
  46. CipherName() string
  47. }
  48. // A Cipher is a AEAD cipher that has been initialized with a key.
  49. type Cipher interface {
  50. // Encrypt encrypts the provided plaintext with a nonce and then appends the
  51. // ciphertext to out along with an authentication tag over the ciphertext
  52. // and optional authenticated data.
  53. Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte
  54. // Decrypt authenticates the ciphertext and optional authenticated data and
  55. // then decrypts the provided ciphertext using the provided nonce and
  56. // appends it to out.
  57. Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error)
  58. }
  59. // A CipherSuite is a set of cryptographic primitives used in a Noise protocol.
  60. // It should be constructed with NewCipherSuite.
  61. type CipherSuite interface {
  62. DHFunc
  63. CipherFunc
  64. HashFunc
  65. Name() []byte
  66. }
  67. // NewCipherSuite returns a CipherSuite constructed from the specified
  68. // primitives.
  69. func NewCipherSuite(dh DHFunc, c CipherFunc, h HashFunc) CipherSuite {
  70. return ciphersuite{
  71. DHFunc: dh,
  72. CipherFunc: c,
  73. HashFunc: h,
  74. name: []byte(dh.DHName() + "_" + c.CipherName() + "_" + h.HashName()),
  75. }
  76. }
  77. type ciphersuite struct {
  78. DHFunc
  79. CipherFunc
  80. HashFunc
  81. name []byte
  82. }
  83. func (s ciphersuite) Name() []byte { return s.name }
  84. // DH25519 is the Curve25519 ECDH function.
  85. var DH25519 DHFunc = dh25519{}
  86. type dh25519 struct{}
  87. func (dh25519) GenerateKeypair(rng io.Reader) (DHKey, error) {
  88. privkey := make([]byte, 32)
  89. if rng == nil {
  90. rng = rand.Reader
  91. }
  92. if _, err := io.ReadFull(rng, privkey); err != nil {
  93. return DHKey{}, err
  94. }
  95. pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)
  96. if err != nil {
  97. return DHKey{}, err
  98. }
  99. return DHKey{Private: privkey, Public: pubkey}, nil
  100. }
  101. func (dh25519) DH(privkey, pubkey []byte) ([]byte, error) {
  102. return curve25519.X25519(privkey, pubkey)
  103. }
  104. func (dh25519) DHLen() int { return 32 }
  105. func (dh25519) DHName() string { return "25519" }
  106. type cipherFn struct {
  107. fn func([32]byte) Cipher
  108. name string
  109. }
  110. func (c cipherFn) Cipher(k [32]byte) Cipher { return c.fn(k) }
  111. func (c cipherFn) CipherName() string { return c.name }
  112. // CipherAESGCM is the AES256-GCM AEAD cipher.
  113. var CipherAESGCM CipherFunc = cipherFn{cipherAESGCM, "AESGCM"}
  114. func cipherAESGCM(k [32]byte) Cipher {
  115. c, err := aes.NewCipher(k[:])
  116. if err != nil {
  117. panic(err)
  118. }
  119. gcm, err := cipher.NewGCM(c)
  120. if err != nil {
  121. panic(err)
  122. }
  123. return aeadCipher{
  124. gcm,
  125. func(n uint64) []byte {
  126. var nonce [12]byte
  127. binary.BigEndian.PutUint64(nonce[4:], n)
  128. return nonce[:]
  129. },
  130. }
  131. }
  132. // CipherChaChaPoly is the ChaCha20-Poly1305 AEAD cipher construction.
  133. var CipherChaChaPoly CipherFunc = cipherFn{cipherChaChaPoly, "ChaChaPoly"}
  134. func cipherChaChaPoly(k [32]byte) Cipher {
  135. c, err := chacha20poly1305.New(k[:])
  136. if err != nil {
  137. panic(err)
  138. }
  139. return aeadCipher{
  140. c,
  141. func(n uint64) []byte {
  142. var nonce [12]byte
  143. binary.LittleEndian.PutUint64(nonce[4:], n)
  144. return nonce[:]
  145. },
  146. }
  147. }
  148. type aeadCipher struct {
  149. cipher.AEAD
  150. nonce func(uint64) []byte
  151. }
  152. func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte {
  153. return c.Seal(out, c.nonce(n), plaintext, ad)
  154. }
  155. func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) {
  156. return c.Open(out, c.nonce(n), ciphertext, ad)
  157. }
  158. type hashFn struct {
  159. fn func() hash.Hash
  160. name string
  161. }
  162. func (h hashFn) Hash() hash.Hash { return h.fn() }
  163. func (h hashFn) HashName() string { return h.name }
  164. // HashSHA256 is the SHA-256 hash function.
  165. var HashSHA256 HashFunc = hashFn{sha256.New, "SHA256"}
  166. // HashSHA512 is the SHA-512 hash function.
  167. var HashSHA512 HashFunc = hashFn{sha512.New, "SHA512"}
  168. func blake2bNew() hash.Hash {
  169. h, err := blake2b.New512(nil)
  170. if err != nil {
  171. panic(err)
  172. }
  173. return h
  174. }
  175. // HashBLAKE2b is the BLAKE2b hash function.
  176. var HashBLAKE2b HashFunc = hashFn{blake2bNew, "BLAKE2b"}
  177. func blake2sNew() hash.Hash {
  178. h, err := blake2s.New256(nil)
  179. if err != nil {
  180. panic(err)
  181. }
  182. return h
  183. }
  184. // HashBLAKE2s is the BLAKE2s hash function.
  185. var HashBLAKE2s HashFunc = hashFn{blake2sNew, "BLAKE2s"}