decred.org/dcrwallet/v3@v3.1.0/internal/cfgutil/curve.go (about)

     1  // Copyright (c) 2016 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package cfgutil
     6  
     7  import (
     8  	"crypto/ecdsa"
     9  	"crypto/ed25519"
    10  	"crypto/elliptic"
    11  	"io"
    12  	"time"
    13  
    14  	"decred.org/dcrwallet/v3/errors"
    15  	"github.com/decred/dcrd/certgen"
    16  )
    17  
    18  // CurveID specifies a recognized curve through a constant value.
    19  type CurveID int
    20  
    21  // Recognized curve IDs.
    22  const (
    23  	CurveP256 CurveID = iota
    24  	CurveP384
    25  	CurveP521
    26  	Ed25519
    27  
    28  	// PreferredCurve is the curve that should be used as the application default.
    29  	PreferredCurve = Ed25519
    30  )
    31  
    32  // CurveFlag describes a curve and implements the flags.Marshaler and
    33  // Unmarshaler interfaces so it can be used as a config struct field.
    34  type CurveFlag struct {
    35  	curveID CurveID
    36  }
    37  
    38  // NewCurveFlag creates a CurveFlag with a default curve.
    39  func NewCurveFlag(defaultValue CurveID) *CurveFlag {
    40  	return &CurveFlag{defaultValue}
    41  }
    42  
    43  // ECDSACurve returns the elliptic curve described by f, or (nil, false) if the
    44  // curve is not one of the elliptic curves suitable for ECDSA.
    45  func (f *CurveFlag) ECDSACurve() (elliptic.Curve, bool) {
    46  	switch f.curveID {
    47  	case CurveP256:
    48  		return elliptic.P256(), true
    49  	case CurveP384:
    50  		return elliptic.P384(), true
    51  	case CurveP521:
    52  		return elliptic.P521(), true
    53  	default:
    54  		return nil, false
    55  	}
    56  }
    57  
    58  // MarshalFlag satisfies the flags.Marshaler interface.
    59  func (f *CurveFlag) MarshalFlag() (name string, err error) {
    60  	switch f.curveID {
    61  	case CurveP256:
    62  		name = "P-256"
    63  	case CurveP384:
    64  		name = "P-384"
    65  	case CurveP521:
    66  		name = "P-521"
    67  	case Ed25519:
    68  		name = "Ed25519"
    69  	default:
    70  		err = errors.Errorf("unknown curve ID %v", int(f.curveID))
    71  	}
    72  	return
    73  }
    74  
    75  // UnmarshalFlag satisfies the flags.Unmarshaler interface.
    76  func (f *CurveFlag) UnmarshalFlag(value string) error {
    77  	switch value {
    78  	case "P-256":
    79  		f.curveID = CurveP256
    80  	case "P-384":
    81  		f.curveID = CurveP384
    82  	case "P-521":
    83  		f.curveID = CurveP521
    84  	case "Ed25519":
    85  		f.curveID = Ed25519
    86  	default:
    87  		return errors.Errorf("unrecognized curve %v", value)
    88  	}
    89  	return nil
    90  }
    91  
    92  func (f *CurveFlag) GenerateKeyPair(rand io.Reader) (pub, priv interface{}, err error) {
    93  	if ec, ok := f.ECDSACurve(); ok {
    94  		var key *ecdsa.PrivateKey
    95  		key, err = ecdsa.GenerateKey(ec, rand)
    96  		if err != nil {
    97  			return
    98  		}
    99  		pub, priv = key.Public(), key
   100  		return
   101  	}
   102  	if f.curveID == Ed25519 {
   103  		seed := make([]byte, ed25519.SeedSize)
   104  		_, err = io.ReadFull(rand, seed)
   105  		if err != nil {
   106  			return
   107  		}
   108  		key := ed25519.NewKeyFromSeed(seed)
   109  		pub, priv = key.Public(), key
   110  		return
   111  	}
   112  	return nil, nil, errors.New("unknown curve ID")
   113  }
   114  
   115  func (f *CurveFlag) CertGen(org string, validUntil time.Time, extraHosts []string) (cert, key []byte, err error) {
   116  	if ec, ok := f.ECDSACurve(); ok {
   117  		return certgen.NewTLSCertPair(ec, org, validUntil, extraHosts)
   118  	}
   119  	if f.curveID == Ed25519 {
   120  		return certgen.NewEd25519TLSCertPair(org, validUntil, extraHosts)
   121  	}
   122  	return nil, nil, errors.New("unknown curve ID")
   123  }