// Package pkcs8 implements functions to parse and convert private keys in PKCS#8 format with ShangMi(SM) support, as defined in RFC5208 and RFC5958. package pkcs8 import ( "crypto/ecdsa" "crypto/rand" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "errors" "github.com/emmansun/gmsm/pkcs" "github.com/emmansun/gmsm/sm2" "github.com/emmansun/gmsm/sm9" "github.com/emmansun/gmsm/smx509" ) type Opts = pkcs.PBES2Opts type PBKDF2Opts = pkcs.PBKDF2Opts type ScryptOpts = pkcs.ScryptOpts var ( DefaultOpts = pkcs.DefaultOpts SM3 = pkcs.SM3 SHA1 = pkcs.SHA1 SHA224 = pkcs.SHA224 SHA256 = pkcs.SHA256 SHA384 = pkcs.SHA384 SHA512 = pkcs.SHA512 SHA512_224 = pkcs.SHA512_224 SHA512_256 = pkcs.SHA512_256 ) // for encrypted private-key information type encryptedPrivateKeyInfo struct { EncryptionAlgorithm pkix.AlgorithmIdentifier EncryptedData []byte } var ( ErrUnsupportedPBES = errors.New("pkcs8: only part of PBES1/PBES2 supported") ErrUnexpectedKeyType = errors.New("pkcs8: unexpected key type") ) // ParsePrivateKey parses a DER-encoded PKCS#8 private key. // Password can be nil. // This is equivalent to ParsePKCS8PrivateKey. func ParsePrivateKey(der []byte, password []byte) (any, pkcs.KDFParameters, error) { // No password provided, assume the private key is unencrypted if len(password) == 0 { privateKey, err := smx509.ParsePKCS8PrivateKey(der) return privateKey, nil, err } // Use the password provided to decrypt the private key var privKey encryptedPrivateKeyInfo if _, err := asn1.Unmarshal(der, &privKey); err != nil { if block, _ := pem.Decode(der); block != nil { return nil, nil, errors.New("pkcs8: this method just supports DER-encoded key") } return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported") } var kdfParams pkcs.KDFParameters var decryptedKey []byte var err error switch { case pkcs.IsPBES2(privKey.EncryptionAlgorithm) || pkcs.IsSMPBES(privKey.EncryptionAlgorithm): var params pkcs.PBES2Params if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, ¶ms); err != nil { return nil, nil, errors.New("pkcs8: invalid PBES2 parameters") } decryptedKey, kdfParams, err = params.Decrypt(password, privKey.EncryptedData) case pkcs.IsPBES1(privKey.EncryptionAlgorithm): pbes1 := &pkcs.PBES1{Algorithm: privKey.EncryptionAlgorithm} decryptedKey, kdfParams, err = pbes1.Decrypt(password, privKey.EncryptedData) default: return nil, nil, ErrUnsupportedPBES } if err != nil { return nil, nil, err } key, err := smx509.ParsePKCS8PrivateKey(decryptedKey) if err != nil { return nil, nil, err } return key, kdfParams, nil } // MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options. // Password can be nil. func MarshalPrivateKey(priv any, password []byte, encrypter pkcs.PBESEncrypter) ([]byte, error) { if len(password) == 0 { return smx509.MarshalPKCS8PrivateKey(priv) } if encrypter == nil { encrypter = DefaultOpts } // Convert private key into PKCS8 format pkey, err := smx509.MarshalPKCS8PrivateKey(priv) if err != nil { return nil, err } encryptionAlgorithm, encryptedKey, err := encrypter.Encrypt(rand.Reader, password, pkey) if err != nil { return nil, err } encryptedPkey := encryptedPrivateKeyInfo{ EncryptionAlgorithm: *encryptionAlgorithm, EncryptedData: encryptedKey, } return asn1.Marshal(encryptedPkey) } // ParsePKCS8PrivateKey parses encrypted/unencrypted private keys in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParsePKCS8PrivateKey(der []byte, v ...[]byte) (any, error) { var password []byte if len(v) > 0 { password = v[0] } privateKey, _, err := ParsePrivateKey(der, password) return privateKey, err } // ParsePKCS8PrivateKeyRSA parses encrypted/unencrypted private keys in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParsePKCS8PrivateKeyRSA(der []byte, v ...[]byte) (*rsa.PrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*rsa.PrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ParsePKCS8PrivateKeyECDSA parses encrypted/unencrypted private keys in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParsePKCS8PrivateKeyECDSA(der []byte, v ...[]byte) (*ecdsa.PrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*ecdsa.PrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ParsePKCS8PrivateKeySM2 parses encrypted/unencrypted SM2 private key in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParsePKCS8PrivateKeySM2(der []byte, v ...[]byte) (*sm2.PrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*sm2.PrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ParseSM9SignMasterPrivateKey parses encrypted/unencrypted SM9 sign master private key in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParseSM9SignMasterPrivateKey(der []byte, v ...[]byte) (*sm9.SignMasterPrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*sm9.SignMasterPrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ParseSM9SignPrivateKey parses encrypted/unencrypted SM9 sign private key in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParseSM9SignPrivateKey(der []byte, v ...[]byte) (*sm9.SignPrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*sm9.SignPrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ParseSM9EncryptMasterPrivateKey parses encrypted/unencrypted SM9 encrypt master private key in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParseSM9EncryptMasterPrivateKey(der []byte, v ...[]byte) (*sm9.EncryptMasterPrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*sm9.EncryptMasterPrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ParseSM9EncryptPrivateKey parses encrypted/unencrypted SM9 encrypt private key in PKCS#8 format. // To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. func ParseSM9EncryptPrivateKey(der []byte, v ...[]byte) (*sm9.EncryptPrivateKey, error) { key, err := ParsePKCS8PrivateKey(der, v...) if err != nil { return nil, err } typedKey, ok := key.(*sm9.EncryptPrivateKey) if !ok { return nil, ErrUnexpectedKeyType } return typedKey, nil } // ConvertPrivateKeyToPKCS8 converts the private key into PKCS#8 format. // To encrypt the private key, the password of []byte type should be provided as the second parameter. func ConvertPrivateKeyToPKCS8(priv any, v ...[]byte) ([]byte, error) { var password []byte if len(v) > 0 { password = v[0] } return MarshalPrivateKey(priv, password, nil) }