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  }