2025-03-09 15:52:33 -04:00
|
|
|
package identity
|
2025-03-07 21:05:37 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/elliptic"
|
|
|
|
"crypto/rand"
|
2025-03-09 12:33:27 -04:00
|
|
|
"crypto/x509"
|
|
|
|
"encoding/pem"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2025-03-07 21:05:37 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// DefaultSigningCurve is the default elliptic curve used for signing.
|
|
|
|
DefaultSigningCurve = elliptic.P384
|
2025-03-09 17:09:21 -04:00
|
|
|
|
|
|
|
ExportedPublicKeySize = 215
|
2025-03-07 21:05:37 -05:00
|
|
|
)
|
|
|
|
|
2025-03-09 12:33:27 -04:00
|
|
|
func LoadSigningKeyFromFile(filePath string) (*ecdsa.PrivateKey, error) {
|
|
|
|
masterKeyFile, err := os.ReadFile(filePath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// The second argument is not an error.
|
|
|
|
derEncoded, _ := pem.Decode(masterKeyFile)
|
|
|
|
if derEncoded == nil {
|
|
|
|
return nil, fmt.Errorf("failed to decode master key file")
|
|
|
|
}
|
|
|
|
|
|
|
|
masterKey, err := x509.ParseECPrivateKey(derEncoded.Bytes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return masterKey, nil
|
|
|
|
}
|
|
|
|
|
2025-03-09 17:09:21 -04:00
|
|
|
// Generate generates a new ECDSA private key for signing.
|
|
|
|
func Generate() (*ecdsa.PrivateKey, error) {
|
2025-03-07 21:05:37 -05:00
|
|
|
return ecdsa.GenerateKey(DefaultSigningCurve(), rand.Reader)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sign signs the data with the private key.
|
|
|
|
func Sign(priv *ecdsa.PrivateKey, data []byte) ([]byte, error) {
|
|
|
|
return ecdsa.SignASN1(rand.Reader, priv, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify verifies the signature of the data with the public key.
|
|
|
|
func Verify(pub *ecdsa.PublicKey, data, signature []byte) bool {
|
|
|
|
return ecdsa.VerifyASN1(pub, data, signature)
|
|
|
|
}
|
|
|
|
|
2025-03-09 17:09:21 -04:00
|
|
|
// ExportPrivateKey exports the private key as a byte slice.
|
|
|
|
func ExportPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
|
|
|
|
der, err := x509.MarshalECPrivateKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2025-03-07 21:05:37 -05:00
|
|
|
}
|
2025-03-09 17:09:21 -04:00
|
|
|
|
|
|
|
return pem.EncodeToMemory(&pem.Block{
|
|
|
|
Type: "PRIVATE KEY",
|
|
|
|
Bytes: der,
|
|
|
|
}), nil
|
2025-03-07 21:05:37 -05:00
|
|
|
}
|
|
|
|
|
2025-03-09 17:09:21 -04:00
|
|
|
// ExportPublicKey exports the public key as a byte slice.
|
|
|
|
func ExportPublicKey(key *ecdsa.PublicKey) ([]byte, error) {
|
|
|
|
der, err := x509.MarshalPKIXPublicKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2025-03-07 21:05:37 -05:00
|
|
|
}
|
2025-03-09 17:09:21 -04:00
|
|
|
|
|
|
|
return pem.EncodeToMemory(&pem.Block{
|
|
|
|
Type: "PUBLIC KEY",
|
|
|
|
Bytes: der,
|
|
|
|
}), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ImportPrivateKey imports the private key from a byte slice.
|
|
|
|
func ImportPrivateKey(keyBytes []byte) (*ecdsa.PrivateKey, error) {
|
|
|
|
block, _ := pem.Decode(keyBytes)
|
|
|
|
if block == nil {
|
|
|
|
return nil, fmt.Errorf("failed to decode private key")
|
|
|
|
}
|
|
|
|
|
|
|
|
privKey, err := x509.ParseECPrivateKey(block.Bytes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return privKey, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ImportPublicKey imports the public key from a byte slice.
|
|
|
|
func ImportPublicKey(keyBytes []byte) (*ecdsa.PublicKey, error) {
|
|
|
|
block, _ := pem.Decode(keyBytes)
|
|
|
|
if block == nil {
|
|
|
|
return nil, fmt.Errorf("failed to decode public key")
|
|
|
|
}
|
|
|
|
|
|
|
|
pubKeyAny, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
|
|
if err != nil {
|
2025-03-07 21:05:37 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2025-03-09 17:09:21 -04:00
|
|
|
pubKey, ok := pubKeyAny.(*ecdsa.PublicKey)
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("not an ECDSA public key")
|
|
|
|
}
|
2025-03-07 21:05:37 -05:00
|
|
|
|
2025-03-09 17:09:21 -04:00
|
|
|
return pubKey, nil
|
2025-03-07 21:05:37 -05:00
|
|
|
}
|