mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-22 02:06:18 +08:00
239 lines
7.6 KiB
Go
239 lines
7.6 KiB
Go
// 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)
|
|
}
|