forked from toolshed/abra
		
	
		
			
				
	
	
		
			108 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | |
| package ecc
 | |
| 
 | |
| import (
 | |
| 	"crypto/subtle"
 | |
| 	"io"
 | |
| 
 | |
| 	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | |
| 	x448lib "github.com/cloudflare/circl/dh/x448"
 | |
| )
 | |
| 
 | |
| type x448 struct{}
 | |
| 
 | |
| func NewX448() *x448 {
 | |
| 	return &x448{}
 | |
| }
 | |
| 
 | |
| func (c *x448) GetCurveName() string {
 | |
| 	return "x448"
 | |
| }
 | |
| 
 | |
| // MarshalBytePoint encodes the public point from native format, adding the prefix.
 | |
| // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 | |
| func (c *x448) MarshalBytePoint(point []byte) []byte {
 | |
| 	return append([]byte{0x40}, point...)
 | |
| }
 | |
| 
 | |
| // UnmarshalBytePoint decodes a point from prefixed format to native.
 | |
| // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 | |
| func (c *x448) UnmarshalBytePoint(point []byte) []byte {
 | |
| 	if len(point) != x448lib.Size+1 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return point[1:]
 | |
| }
 | |
| 
 | |
| // MarshalByteSecret encoded a scalar from native format to prefixed.
 | |
| // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
 | |
| func (c *x448) MarshalByteSecret(d []byte) []byte {
 | |
| 	return append([]byte{0x40}, d...)
 | |
| }
 | |
| 
 | |
| // UnmarshalByteSecret decodes a scalar from prefixed format to native.
 | |
| // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
 | |
| func (c *x448) UnmarshalByteSecret(d []byte) []byte {
 | |
| 	if len(d) != x448lib.Size+1 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Store without prefix
 | |
| 	return d[1:]
 | |
| }
 | |
| 
 | |
| func (c *x448) generateKeyPairBytes(rand io.Reader) (sk, pk x448lib.Key, err error) {
 | |
| 	if _, err = rand.Read(sk[:]); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	x448lib.KeyGen(&pk, &sk)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (c *x448) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
 | |
| 	priv, pub, err := c.generateKeyPairBytes(rand)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	return pub[:], priv[:], nil
 | |
| }
 | |
| 
 | |
| func (c *x448) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 | |
| 	var pk, ss x448lib.Key
 | |
| 	seed, e, err := c.generateKeyPairBytes(rand)
 | |
| 	if err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 	copy(pk[:], point)
 | |
| 	x448lib.Shared(&ss, &seed, &pk)
 | |
| 
 | |
| 	return e[:], ss[:], nil
 | |
| }
 | |
| 
 | |
| func (c *x448) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
 | |
| 	var ss, sk, e x448lib.Key
 | |
| 
 | |
| 	copy(sk[:], secret)
 | |
| 	copy(e[:], ephemeral)
 | |
| 	x448lib.Shared(&ss, &sk, &e)
 | |
| 
 | |
| 	return ss[:], nil
 | |
| }
 | |
| 
 | |
| func (c *x448) ValidateECDH(point []byte, secret []byte) error {
 | |
| 	var sk, pk, expectedPk x448lib.Key
 | |
| 
 | |
| 	copy(pk[:], point)
 | |
| 	copy(sk[:], secret)
 | |
| 	x448lib.KeyGen(&expectedPk, &sk)
 | |
| 
 | |
| 	if subtle.ConstantTimeCompare(expectedPk[:], pk[:]) == 0 {
 | |
| 		return errors.KeyInvalidError("ecc: invalid curve25519 public point")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |