package utils import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "encoding/asn1" "encoding/pem" "fmt" "github.com/pkg/errors" "github.com/tjfoc/gmsm/sm2" ) type pkcs8Info struct { Version int PrivateKeyAlgorithm []asn1.ObjectIdentifier PrivateKey []byte } type ecPrivateKey struct { Version int PrivateKey []byte NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` } var ( oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} ) var oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { switch curve { case elliptic.P256(): return oidNamedCurveP256, true } return nil, false } func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { if len(pwd) != 0 { return privateKeyToEncryptedPEM(privateKey, pwd) } if privateKey == nil { return nil, errors.New("Invalid key. It must be different from nil.") } switch k := privateKey.(type) { case *ecdsa.PrivateKey: if k == nil { return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") } oidNamedCurve, ok := oidFromNamedCurve(k.Curve) if !ok { return nil, errors.New("unknown elliptic curve") } privateKeyBytes := k.D.Bytes() paddedPrivateKey := make([]byte, (k.Curve.Params().N.BitLen()+7)/8) copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) asn1Bytes, err := asn1.Marshal(ecPrivateKey{ Version: 1, PrivateKey: paddedPrivateKey, PublicKey: asn1.BitString{Bytes: elliptic.Marshal(k.Curve, k.X, k.Y)}, }) if err != nil { return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) } var pkcs8Key pkcs8Info pkcs8Key.Version = 0 pkcs8Key.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 2) pkcs8Key.PrivateKeyAlgorithm[0] = oidPublicKeyECDSA pkcs8Key.PrivateKeyAlgorithm[1] = oidNamedCurve pkcs8Key.PrivateKey = asn1Bytes pkcs8Bytes, err := asn1.Marshal(pkcs8Key) if err != nil { return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) } return pem.EncodeToMemory( &pem.Block{ Type: "PRIVATE KEY", Bytes: pkcs8Bytes, }, ), nil case *sm2.PrivateKey: if k == nil { return nil, errors.New("Invalid sm2 private key. It must be different from nil.") } return sm2.WritePrivateKeytoMem(k, nil) default: return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey or *rsa.PrivateKey") } } func privateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) { if privateKey == nil { return nil, errors.New("Invalid private key. It must be different from nil.") } switch k := privateKey.(type) { case *ecdsa.PrivateKey: if k == nil { return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") } raw, err := x509.MarshalECPrivateKey(k) if err != nil { return nil, err } block, err := x509.EncryptPEMBlock( rand.Reader, "PRIVATE KEY", raw, pwd, x509.PEMCipherAES256) if err != nil { return nil, err } return pem.EncodeToMemory(block), nil default: return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey") } } func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { if len(pwd) != 0 { return publicKeyToEncryptedPEM(publicKey, pwd) } if publicKey == nil { return nil, errors.New("Invalid public key. It must be different from nil.") } switch k := publicKey.(type) { case *ecdsa.PublicKey: if k == nil { return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") } PubASN1, err := x509.MarshalPKIXPublicKey(k) if err != nil { return nil, err } return pem.EncodeToMemory( &pem.Block{ Type: "PUBLIC KEY", Bytes: PubASN1, }, ), nil case *sm2.PublicKey: if k == nil { return nil, errors.New("Invalid sm2 public key. It must be different from nil.") } return sm2.WritePublicKeytoMem(k, nil) default: return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey or *rsa.PublicKey") } } func publicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) { if publicKey == nil { return nil, errors.New("Invalid public key. It must be different from nil.") } if len(pwd) == 0 { return nil, errors.New("Invalid password. It must be different from nil.") } switch k := publicKey.(type) { case *ecdsa.PublicKey: if k == nil { return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") } raw, err := x509.MarshalPKIXPublicKey(k) if err != nil { return nil, err } block, err := x509.EncryptPEMBlock( rand.Reader, "PUBLIC KEY", raw, pwd, x509.PEMCipherAES256) if err != nil { return nil, err } return pem.EncodeToMemory(block), nil default: return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey") } } func DERToPublicKey(raw []byte) (pub interface{}, err error) { if len(raw) == 0 { return nil, errors.New("Invalid DER. It must be different from nil.") } key, err := x509.ParsePKIXPublicKey(raw) if err != nil { key, err = sm2.ParseSm2PublicKey(raw) } return key, err } func Clone(src []byte) []byte { clone := make([]byte, len(src)) copy(clone, src) return clone }