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 }