Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 88 additions & 74 deletions pkcs8.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,70 +140,92 @@ func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, e
return privateKey, nil, err
}

// Use the password provided to decrypt the private key
var privKey encryptedPrivateKeyInfo
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported")
decryptedKey, kdfParams, err := DecryptPKCS8(der, password)
if err != nil {
return nil, nil, nil
}

if !privKey.EncryptionAlgorithm.Algorithm.Equal(oidPBES2) {
return nil, nil, errors.New("pkcs8: only PBES2 supported")
key, err := x509.ParsePKCS8PrivateKey(decryptedKey)
if err != nil {
return nil, nil, errors.New("pkcs8: incorrect password")
}
return key, kdfParams, nil
}

var params pbes2Params
if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, &params); err != nil {
return nil, nil, errors.New("pkcs8: invalid PBES2 parameters")
// MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options.
// Password can be nil.
func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, error) {
if len(password) == 0 {
return x509.MarshalPKCS8PrivateKey(priv)
}

cipher, iv, err := parseEncryptionScheme(params.EncryptionScheme)
// Convert private key into PKCS8 format
pkey, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, nil, err
return nil, err
}

kdfParams, err := parseKeyDerivationFunc(params.KeyDerivationFunc)
if err != nil {
return nil, nil, err
return EncryptPKCS8(pkey, password, opts)
}

// 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) (interface{}, error) {
var password []byte
if len(v) > 0 {
password = v[0]
}
privateKey, _, err := ParsePrivateKey(der, password)
return privateKey, err
}

keySize := cipher.KeySize()
symkey, err := kdfParams.DeriveKey(password, keySize)
// 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, nil, err
return nil, err
}
typedKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("key block is not of type RSA")
}
return typedKey, nil
}

encryptedKey := privKey.EncryptedData
decryptedKey, err := cipher.Decrypt(symkey, iv, encryptedKey)
// 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, nil, err
return nil, err
}
typedKey, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, errors.New("key block is not of type ECDSA")
}
return typedKey, nil
}

key, err := x509.ParsePKCS8PrivateKey(decryptedKey)
if err != nil {
return nil, nil, errors.New("pkcs8: incorrect password")
// 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.
//
// The only supported key types are RSA and ECDSA (*rsa.PrivateKey or *ecdsa.PrivateKey for priv)
func ConvertPrivateKeyToPKCS8(priv interface{}, v ...[]byte) ([]byte, error) {
var password []byte
if len(v) > 0 {
password = v[0]
}
return key, kdfParams, nil
return MarshalPrivateKey(priv, password, nil)
}

// MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options.
// Password can be nil.
func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, error) {
func EncryptPKCS8(pkcs8Bytes []byte, password []byte, opts *Opts) ([]byte, error) {
if len(password) == 0 {
return x509.MarshalPKCS8PrivateKey(priv)
return pkcs8Bytes, nil
}

if opts == nil {
opts = DefaultOpts
}

// Convert private key into PKCS8 format
pkey, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, err
}

encAlg := opts.Cipher
salt := make([]byte, opts.KDFOpts.GetSaltSize())
_, err = rand.Read(salt)
_, err := rand.Read(salt)
if err != nil {
return nil, err
}
Expand All @@ -217,7 +239,7 @@ func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, e
return nil, err
}

encryptedKey, err := encAlg.Encrypt(key, iv, pkey)
encryptedKey, err := encAlg.Encrypt(key, iv, pkcs8Bytes)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -260,50 +282,42 @@ func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, e
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) (interface{}, error) {
var password []byte
if len(v) > 0 {
password = v[0]
func DecryptPKCS8(encryptedPkcs8 []byte, password []byte) ([]byte, KDFParameters, error) {
// Use the password provided to decrypt the private key
var privKey encryptedPrivateKeyInfo
if _, err := asn1.Unmarshal(encryptedPkcs8, &privKey); err != nil {
return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported")
}
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
if !privKey.EncryptionAlgorithm.Algorithm.Equal(oidPBES2) {
return nil, nil, errors.New("pkcs8: only PBES2 supported")
}
typedKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("key block is not of type RSA")

var params pbes2Params
if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, &params); err != nil {
return nil, nil, errors.New("pkcs8: invalid PBES2 parameters")
}
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...)
cipher, iv, err := parseEncryptionScheme(params.EncryptionScheme)
if err != nil {
return nil, err
return nil, nil, err
}
typedKey, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, errors.New("key block is not of type ECDSA")

kdfParams, err := parseKeyDerivationFunc(params.KeyDerivationFunc)
if err != nil {
return nil, nil, err
}
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.
//
// The only supported key types are RSA and ECDSA (*rsa.PrivateKey or *ecdsa.PrivateKey for priv)
func ConvertPrivateKeyToPKCS8(priv interface{}, v ...[]byte) ([]byte, error) {
var password []byte
if len(v) > 0 {
password = v[0]
keySize := cipher.KeySize()
symkey, err := kdfParams.DeriveKey(password, keySize)
if err != nil {
return nil, nil, err
}
return MarshalPrivateKey(priv, password, nil)

encryptedKey := privKey.EncryptedData
decryptedKey, err := cipher.Decrypt(symkey, iv, encryptedKey)
if err != nil {
return nil, nil, err
}
return decryptedKey, kdfParams, nil
}