nist.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package noiseutil
  2. import (
  3. "crypto/ecdh"
  4. "crypto/rand"
  5. "fmt"
  6. "io"
  7. "github.com/flynn/noise"
  8. )
  9. // DHP256 is the NIST P-256 ECDH function
  10. var DHP256 noise.DHFunc = newNISTCurve("P256", ecdh.P256(), 32)
  11. type nistCurve struct {
  12. name string
  13. curve ecdh.Curve
  14. dhLen int
  15. pubLen int
  16. }
  17. func newNISTCurve(name string, curve ecdh.Curve, byteLen int) nistCurve {
  18. return nistCurve{
  19. name: name,
  20. curve: curve,
  21. dhLen: byteLen,
  22. // Standard uncompressed format, type (1 byte) plus both coordinates
  23. pubLen: 1 + 2*byteLen,
  24. }
  25. }
  26. func (c nistCurve) GenerateKeypair(rng io.Reader) (noise.DHKey, error) {
  27. if rng == nil {
  28. rng = rand.Reader
  29. }
  30. privkey, err := c.curve.GenerateKey(rng)
  31. if err != nil {
  32. return noise.DHKey{}, err
  33. }
  34. pubkey := privkey.PublicKey()
  35. return noise.DHKey{Private: privkey.Bytes(), Public: pubkey.Bytes()}, nil
  36. }
  37. func (c nistCurve) DH(privkey, pubkey []byte) ([]byte, error) {
  38. ecdhPubKey, err := c.curve.NewPublicKey(pubkey)
  39. if err != nil {
  40. return nil, fmt.Errorf("unable to unmarshal pubkey: %w", err)
  41. }
  42. ecdhPrivKey, err := c.curve.NewPrivateKey(privkey)
  43. if err != nil {
  44. return nil, fmt.Errorf("unable to unmarshal private key: %w", err)
  45. }
  46. return ecdhPrivKey.ECDH(ecdhPubKey)
  47. }
  48. func (c nistCurve) DHLen() int {
  49. // NOTE: Noise Protocol specifies "DHLen" to represent two things:
  50. // - The size of the public key
  51. // - The return size of the DH() function
  52. // But for standard NIST ECDH, the sizes of these are different.
  53. // Luckily, the flynn/noise library actually only uses this DHLen()
  54. // value to represent the public key size, so that is what we are
  55. // returning here. The length of the DH() return bytes are unaffected by
  56. // this value here.
  57. return c.pubLen
  58. }
  59. func (c nistCurve) DHName() string { return c.name }