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 }