github.com/futurehomeno/fimpgo@v1.14.0/security/ecdsa-key.go (about)

     1  package security
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	"crypto/rand"
     8  	"crypto/x509"
     9  	"encoding/pem"
    10  	"errors"
    11  	"math/big"
    12  
    13  	"github.com/golang-jwt/jwt"
    14  )
    15  
    16  type JsonEcKey struct {
    17  	T string `json:"t"` //type - private/public
    18  	X string `json:"x"`
    19  	Y string `json:"y"`
    20  	D string `json:"d"` // only for private key
    21  }
    22  
    23  type EcdsaKey struct {
    24  	privateKey *ecdsa.PrivateKey
    25  	publicKey  *ecdsa.PublicKey
    26  }
    27  
    28  func (kp *EcdsaKey) SetPrivateKey(privateKey *ecdsa.PrivateKey) {
    29  	kp.privateKey = privateKey
    30  }
    31  
    32  func (kp *EcdsaKey) PublicKey() *ecdsa.PublicKey {
    33  	return kp.publicKey
    34  }
    35  
    36  func (kp *EcdsaKey) PrivateKey() *ecdsa.PrivateKey {
    37  	return kp.privateKey
    38  }
    39  
    40  func NewEcdsaKey() *EcdsaKey {
    41  	return &EcdsaKey{}
    42  }
    43  
    44  func (kp *EcdsaKey) Generate() error {
    45  	var err error
    46  	kp.privateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    47  	if err != nil {
    48  		return err
    49  	}
    50  	kp.publicKey = &kp.privateKey.PublicKey
    51  	return nil
    52  }
    53  
    54  func (kp *EcdsaKey) ExportX509EncodedKeys() (string, string) {
    55  	var pemEncodedStr, pemEncodedPubStr string
    56  	if kp.privateKey != nil {
    57  		x509Encoded, _ := x509.MarshalECPrivateKey(kp.privateKey)
    58  		pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded})
    59  		pemEncodedStr = string(pemEncoded)
    60  	}
    61  	if kp.publicKey != nil {
    62  		x509EncodedPub, _ := x509.MarshalPKIXPublicKey(kp.publicKey)
    63  		pemEncodedPub := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: x509EncodedPub})
    64  		pemEncodedPubStr = string(pemEncodedPub)
    65  	}
    66  	return pemEncodedStr, pemEncodedPubStr
    67  }
    68  
    69  func (kp *EcdsaKey) ExportJsonEncodedKeys() (JsonEcKey, JsonEcKey) {
    70  	privateKey := JsonEcKey{
    71  		T: "private",
    72  		X: kp.privateKey.X.Text(16),
    73  		Y: kp.privateKey.Y.Text(16),
    74  		D: kp.privateKey.D.Text(16),
    75  	}
    76  	pubKey := JsonEcKey{
    77  		T: "public",
    78  		X: kp.publicKey.X.Text(16),
    79  		Y: kp.publicKey.Y.Text(16),
    80  	}
    81  	return privateKey, pubKey
    82  }
    83  
    84  func (kp *EcdsaKey) ImportX509PublicKey(pemEncodedPub string) error {
    85  	blockPub, _ := pem.Decode([]byte(pemEncodedPub))
    86  	if blockPub == nil {
    87  		return errors.New("incorrect PEM format")
    88  	}
    89  	x509EncodedPub := blockPub.Bytes
    90  	genericPublicKey, err := x509.ParsePKIXPublicKey(x509EncodedPub)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	kp.publicKey = genericPublicKey.(*ecdsa.PublicKey)
    95  	return nil
    96  }
    97  
    98  func (kp *EcdsaKey) ImportX509PrivateKey(pemEncoded string) error {
    99  	var err error
   100  	block, _ := pem.Decode([]byte(pemEncoded))
   101  	x509Encoded := block.Bytes
   102  	kp.privateKey, err = x509.ParseECPrivateKey(x509Encoded)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	return nil
   107  }
   108  
   109  func (kp *EcdsaKey) ImportJsonPublicKey(jkey JsonEcKey) error {
   110  	x, xok := big.NewInt(0).SetString(jkey.X, 16)
   111  	y, yok := big.NewInt(0).SetString(jkey.Y, 16)
   112  	if !xok || !yok {
   113  		return errors.New("json key parse error")
   114  	}
   115  	kp.publicKey = &ecdsa.PublicKey{
   116  		Curve: elliptic.P256(),
   117  		X:     x,
   118  		Y:     y,
   119  	}
   120  	return nil
   121  }
   122  
   123  func (kp *EcdsaKey) ImportJsonPrivateKey(jkey JsonEcKey) error {
   124  	x, xok := big.NewInt(0).SetString(jkey.X, 16)
   125  	y, yok := big.NewInt(0).SetString(jkey.Y, 16)
   126  	d, dok := big.NewInt(0).SetString(jkey.D, 16)
   127  	if !xok || !yok || !dok {
   128  		return errors.New("json key parse error")
   129  	}
   130  	kp.privateKey = &ecdsa.PrivateKey{
   131  		PublicKey: ecdsa.PublicKey{
   132  			Curve: elliptic.P256(),
   133  			X:     x,
   134  			Y:     y,
   135  		},
   136  		D: d,
   137  	}
   138  	return nil
   139  }
   140  
   141  // SignStringES256 signs string and returns as result .
   142  func SignStringES256(payload string, keys *EcdsaKey) (string, error) {
   143  	signingMethodES256 := &jwt.SigningMethodECDSA{Name: "ES256", Hash: crypto.SHA256, KeySize: 32, CurveBits: 256}
   144  	signature, err := signingMethodES256.Sign(payload, keys.PrivateKey())
   145  	if err != nil {
   146  		return "", err
   147  	}
   148  	return signature, nil
   149  }
   150  
   151  func VerifyStringES256(payload, sig string, key *EcdsaKey) bool {
   152  	signingMethodES256 := &jwt.SigningMethodECDSA{Name: "ES256", Hash: crypto.SHA256, KeySize: 32, CurveBits: 256}
   153  	err := signingMethodES256.Verify(payload, sig, key.PublicKey())
   154  	if err == nil {
   155  		return true
   156  	} else {
   157  		return false
   158  	}
   159  }