forked from toolshed/abra
		
	
		
			
				
	
	
		
			150 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | |
| package ecc
 | |
| 
 | |
| import (
 | |
| 	"crypto/ecdsa"
 | |
| 	"crypto/elliptic"
 | |
| 	"fmt"
 | |
| 	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | |
| 	"io"
 | |
| 	"math/big"
 | |
| )
 | |
| 
 | |
| type genericCurve struct {
 | |
| 	Curve elliptic.Curve
 | |
| }
 | |
| 
 | |
| func NewGenericCurve(c elliptic.Curve) *genericCurve {
 | |
| 	return &genericCurve{
 | |
| 		Curve: c,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) GetCurveName() string {
 | |
| 	return c.Curve.Params().Name
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) MarshalBytePoint(point []byte) []byte {
 | |
| 	return point
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) UnmarshalBytePoint(point []byte) []byte {
 | |
| 	return point
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) MarshalIntegerPoint(x, y *big.Int) []byte {
 | |
| 	return elliptic.Marshal(c.Curve, x, y)
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) UnmarshalIntegerPoint(point []byte) (x, y *big.Int) {
 | |
| 	return elliptic.Unmarshal(c.Curve, point)
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) MarshalByteSecret(d []byte) []byte {
 | |
| 	return d
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) UnmarshalByteSecret(d []byte) []byte {
 | |
| 	return d
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) MarshalIntegerSecret(d *big.Int) []byte {
 | |
| 	return d.Bytes()
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) UnmarshalIntegerSecret(d []byte) *big.Int {
 | |
| 	return new(big.Int).SetBytes(d)
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) GenerateECDH(rand io.Reader) (point, secret []byte, err error) {
 | |
| 	secret, x, y, err := elliptic.GenerateKey(c.Curve, rand)
 | |
| 	if err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 
 | |
| 	point = elliptic.Marshal(c.Curve, x, y)
 | |
| 	return point, secret, nil
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) {
 | |
| 	priv, err := ecdsa.GenerateKey(c.Curve, rand)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	return priv.X, priv.Y, priv.D, nil
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 | |
| 	xP, yP := elliptic.Unmarshal(c.Curve, point)
 | |
| 	if xP == nil {
 | |
| 		panic("invalid point")
 | |
| 	}
 | |
| 
 | |
| 	d, x, y, err := elliptic.GenerateKey(c.Curve, rand)
 | |
| 	if err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 
 | |
| 	vsG := elliptic.Marshal(c.Curve, x, y)
 | |
| 	zbBig, _ := c.Curve.ScalarMult(xP, yP, d)
 | |
| 
 | |
| 	byteLen := (c.Curve.Params().BitSize + 7) >> 3
 | |
| 	zb := make([]byte, byteLen)
 | |
| 	zbBytes := zbBig.Bytes()
 | |
| 	copy(zb[byteLen-len(zbBytes):], zbBytes)
 | |
| 
 | |
| 	return vsG, zb, nil
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
 | |
| 	x, y := elliptic.Unmarshal(c.Curve, ephemeral)
 | |
| 	zbBig, _ := c.Curve.ScalarMult(x, y, secret)
 | |
| 	byteLen := (c.Curve.Params().BitSize + 7) >> 3
 | |
| 	zb := make([]byte, byteLen)
 | |
| 	zbBytes := zbBig.Bytes()
 | |
| 	copy(zb[byteLen-len(zbBytes):], zbBytes)
 | |
| 
 | |
| 	return zb, nil
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) {
 | |
| 	priv := &ecdsa.PrivateKey{D: d, PublicKey: ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}}
 | |
| 	return ecdsa.Sign(rand, priv, hash)
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool {
 | |
| 	pub := &ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}
 | |
| 	return ecdsa.Verify(pub, hash, r, s)
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) validate(xP, yP *big.Int, secret []byte) error {
 | |
| 	// the public point should not be at infinity (0,0)
 | |
| 	zero := new(big.Int)
 | |
| 	if xP.Cmp(zero) == 0 && yP.Cmp(zero) == 0 {
 | |
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", c.Curve.Params().Name))
 | |
| 	}
 | |
| 
 | |
| 	// re-derive the public point Q' = (X,Y) = dG
 | |
| 	// to compare to declared Q in public key
 | |
| 	expectedX, expectedY := c.Curve.ScalarBaseMult(secret)
 | |
| 	if xP.Cmp(expectedX) != 0 || yP.Cmp(expectedY) != 0 {
 | |
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) ValidateECDSA(xP, yP *big.Int, secret []byte) error {
 | |
| 	return c.validate(xP, yP, secret)
 | |
| }
 | |
| 
 | |
| func (c *genericCurve) ValidateECDH(point []byte, secret []byte) error {
 | |
| 	xP, yP := elliptic.Unmarshal(c.Curve, point)
 | |
| 	if xP == nil {
 | |
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
 | |
| 	}
 | |
| 
 | |
| 	return c.validate(xP, yP, secret)
 | |
| }
 |