github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/cryptogen/csp/csp.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 package csp 7 8 import ( 9 "crypto" 10 "crypto/ecdsa" 11 "crypto/elliptic" 12 "crypto/rand" 13 "crypto/x509" 14 "encoding/asn1" 15 "encoding/pem" 16 "io" 17 "io/ioutil" 18 "math/big" 19 "os" 20 "path/filepath" 21 "strings" 22 23 "github.com/pkg/errors" 24 ) 25 26 // LoadPrivateKey loads a private key from a file in keystorePath. It looks 27 // for a file ending in "_sk" and expects a PEM-encoded PKCS8 EC private key. 28 func LoadPrivateKey(keystorePath string) (*ecdsa.PrivateKey, error) { 29 var priv *ecdsa.PrivateKey 30 31 walkFunc := func(path string, info os.FileInfo, pathErr error) error { 32 if !strings.HasSuffix(path, "_sk") { 33 return nil 34 } 35 36 rawKey, err := ioutil.ReadFile(path) 37 if err != nil { 38 return err 39 } 40 41 priv, err = parsePrivateKeyPEM(rawKey) 42 if err != nil { 43 return errors.WithMessage(err, path) 44 } 45 46 return nil 47 } 48 49 err := filepath.Walk(keystorePath, walkFunc) 50 if err != nil { 51 return nil, err 52 } 53 54 return priv, err 55 } 56 57 func parsePrivateKeyPEM(rawKey []byte) (*ecdsa.PrivateKey, error) { 58 block, _ := pem.Decode(rawKey) 59 if block == nil { 60 return nil, errors.New("bytes are not PEM encoded") 61 } 62 63 key, err := x509.ParsePKCS8PrivateKey(block.Bytes) 64 if err != nil { 65 return nil, errors.WithMessage(err, "pem bytes are not PKCS8 encoded ") 66 } 67 68 priv, ok := key.(*ecdsa.PrivateKey) 69 if !ok { 70 return nil, errors.New("pem bytes do not contain an EC private key") 71 } 72 return priv, nil 73 } 74 75 // GeneratePrivateKey creates an EC private key using a P-256 curve and stores 76 // it in keystorePath. 77 func GeneratePrivateKey(keystorePath string) (*ecdsa.PrivateKey, error) { 78 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 79 if err != nil { 80 return nil, errors.WithMessage(err, "failed to generate private key") 81 } 82 83 pkcs8Encoded, err := x509.MarshalPKCS8PrivateKey(priv) 84 if err != nil { 85 return nil, errors.WithMessage(err, "failed to marshal private key") 86 } 87 88 pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Encoded}) 89 90 keyFile := filepath.Join(keystorePath, "priv_sk") 91 err = ioutil.WriteFile(keyFile, pemEncoded, 0o600) 92 if err != nil { 93 return nil, errors.WithMessagef(err, "failed to save private key to file %s", keyFile) 94 } 95 96 return priv, err 97 } 98 99 /** 100 ECDSA signer implements the crypto.Signer interface for ECDSA keys. The 101 Sign method ensures signatures are created with Low S values since Fabric 102 normalizes all signatures to Low S. 103 See https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#low_s 104 for more detail. 105 */ 106 type ECDSASigner struct { 107 PrivateKey *ecdsa.PrivateKey 108 } 109 110 // Public returns the ecdsa.PublicKey associated with PrivateKey. 111 func (e *ECDSASigner) Public() crypto.PublicKey { 112 return &e.PrivateKey.PublicKey 113 } 114 115 // Sign signs the digest and ensures that signatures use the Low S value. 116 func (e *ECDSASigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { 117 r, s, err := ecdsa.Sign(rand, e.PrivateKey, digest) 118 if err != nil { 119 return nil, err 120 } 121 122 // ensure Low S signatures 123 sig := toLowS( 124 e.PrivateKey.PublicKey, 125 ECDSASignature{ 126 R: r, 127 S: s, 128 }, 129 ) 130 131 // return marshaled aignature 132 return asn1.Marshal(sig) 133 } 134 135 /** 136 When using ECDSA, both (r,s) and (r, -s mod n) are valid signatures. In order 137 to protect against signature malleability attacks, Fabric normalizes all 138 signatures to a canonical form where s is at most half the order of the curve. 139 In order to make signatures compliant with what Fabric expects, toLowS creates 140 signatures in this canonical form. 141 */ 142 func toLowS(key ecdsa.PublicKey, sig ECDSASignature) ECDSASignature { 143 // calculate half order of the curve 144 halfOrder := new(big.Int).Div(key.Curve.Params().N, big.NewInt(2)) 145 // check if s is greater than half order of curve 146 if sig.S.Cmp(halfOrder) == 1 { 147 // Set s to N - s so that s will be less than or equal to half order 148 sig.S.Sub(key.Params().N, sig.S) 149 } 150 return sig 151 } 152 153 type ECDSASignature struct { 154 R, S *big.Int 155 }