main
Raw Download raw file
  1// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
  2package ecc
  3
  4import (
  5	"crypto/ecdsa"
  6	"crypto/elliptic"
  7	"fmt"
  8	"github.com/ProtonMail/go-crypto/openpgp/errors"
  9	"io"
 10	"math/big"
 11)
 12
 13type genericCurve struct {
 14	Curve elliptic.Curve
 15}
 16
 17func NewGenericCurve(c elliptic.Curve) *genericCurve {
 18	return &genericCurve{
 19		Curve: c,
 20	}
 21}
 22
 23func (c *genericCurve) GetCurveName() string {
 24	return c.Curve.Params().Name
 25}
 26
 27func (c *genericCurve) MarshalBytePoint(point []byte) []byte {
 28	return point
 29}
 30
 31func (c *genericCurve) UnmarshalBytePoint(point []byte) []byte {
 32	return point
 33}
 34
 35func (c *genericCurve) MarshalIntegerPoint(x, y *big.Int) []byte {
 36	return elliptic.Marshal(c.Curve, x, y)
 37}
 38
 39func (c *genericCurve) UnmarshalIntegerPoint(point []byte) (x, y *big.Int) {
 40	return elliptic.Unmarshal(c.Curve, point)
 41}
 42
 43func (c *genericCurve) MarshalByteSecret(d []byte) []byte {
 44	return d
 45}
 46
 47func (c *genericCurve) UnmarshalByteSecret(d []byte) []byte {
 48	return d
 49}
 50
 51func (c *genericCurve) MarshalIntegerSecret(d *big.Int) []byte {
 52	return d.Bytes()
 53}
 54
 55func (c *genericCurve) UnmarshalIntegerSecret(d []byte) *big.Int {
 56	return new(big.Int).SetBytes(d)
 57}
 58
 59func (c *genericCurve) GenerateECDH(rand io.Reader) (point, secret []byte, err error) {
 60	secret, x, y, err := elliptic.GenerateKey(c.Curve, rand)
 61	if err != nil {
 62		return nil, nil, err
 63	}
 64
 65	point = elliptic.Marshal(c.Curve, x, y)
 66	return point, secret, nil
 67}
 68
 69func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) {
 70	priv, err := ecdsa.GenerateKey(c.Curve, rand)
 71	if err != nil {
 72		return
 73	}
 74
 75	return priv.X, priv.Y, priv.D, nil
 76}
 77
 78func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 79	xP, yP := elliptic.Unmarshal(c.Curve, point)
 80	if xP == nil {
 81		panic("invalid point")
 82	}
 83
 84	d, x, y, err := elliptic.GenerateKey(c.Curve, rand)
 85	if err != nil {
 86		return nil, nil, err
 87	}
 88
 89	vsG := elliptic.Marshal(c.Curve, x, y)
 90	zbBig, _ := c.Curve.ScalarMult(xP, yP, d)
 91
 92	byteLen := (c.Curve.Params().BitSize + 7) >> 3
 93	zb := make([]byte, byteLen)
 94	zbBytes := zbBig.Bytes()
 95	copy(zb[byteLen-len(zbBytes):], zbBytes)
 96
 97	return vsG, zb, nil
 98}
 99
100func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
101	x, y := elliptic.Unmarshal(c.Curve, ephemeral)
102	zbBig, _ := c.Curve.ScalarMult(x, y, secret)
103	byteLen := (c.Curve.Params().BitSize + 7) >> 3
104	zb := make([]byte, byteLen)
105	zbBytes := zbBig.Bytes()
106	copy(zb[byteLen-len(zbBytes):], zbBytes)
107
108	return zb, nil
109}
110
111func (c *genericCurve) Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) {
112	priv := &ecdsa.PrivateKey{D: d, PublicKey: ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}}
113	return ecdsa.Sign(rand, priv, hash)
114}
115
116func (c *genericCurve) Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool {
117	pub := &ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}
118	return ecdsa.Verify(pub, hash, r, s)
119}
120
121func (c *genericCurve) validate(xP, yP *big.Int, secret []byte) error {
122	// the public point should not be at infinity (0,0)
123	zero := new(big.Int)
124	if xP.Cmp(zero) == 0 && yP.Cmp(zero) == 0 {
125		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", c.Curve.Params().Name))
126	}
127
128	// re-derive the public point Q' = (X,Y) = dG
129	// to compare to declared Q in public key
130	expectedX, expectedY := c.Curve.ScalarBaseMult(secret)
131	if xP.Cmp(expectedX) != 0 || yP.Cmp(expectedY) != 0 {
132		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
133	}
134
135	return nil
136}
137
138func (c *genericCurve) ValidateECDSA(xP, yP *big.Int, secret []byte) error {
139	return c.validate(xP, yP, secret)
140}
141
142func (c *genericCurve) ValidateECDH(point []byte, secret []byte) error {
143	xP, yP := elliptic.Unmarshal(c.Curve, point)
144	if xP == nil {
145		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
146	}
147
148	return c.validate(xP, yP, secret)
149}