mirror of https://github.com/cheat/cheat.git
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)
|
||
|
}
|