Code Monkey home page Code Monkey logo

pkcs8's People

Contributors

aspenneberg avatar briansan avatar conradoplg avatar genisysram avatar haraldnordgren avatar rautammi avatar t0xiccode avatar umayr avatar xocasdashdash avatar youmark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pkcs8's Issues

Fix Security Vulerabilities by Upgrading Crypto To Version 0.21.0

Problem

Any application that depends on this library will indirectly require golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect

Currently mongo uses this library in its Go driver. Which my library uses. Resulting in security warnings.

Proposal

Bumping golang.org/x/crypto to at least version 0.21.0 will patch:

  • CVE-2023-48795 5.9 Insufficient Verification of Data Authenticity vulnerability with Medium severity found
  • CVE-2023-42818 9.8 Improper Restriction of Excessive Authentication Attempts vulnerability with High severity found

Add DES-CBC block cipher support

Hi there,

I need the DES-CBC block cipher, it's relatively easy to do with a new file cipher_des.go:

var (
	oidDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
)

func init() {
	RegisterCipher(oidDESCBC, func() Cipher {
		return DESCBC
	})
}

// DESCBC is the DES cipher in CBC mode.
var DESCBC = cipherWithBlock{
	ivSize:   des.BlockSize,
	keySize:  8,
	newBlock: des.NewCipher,
	oid:      oidDESCBC,
}

Let me know if you want me to PR this or if you would see any problem with this. Thanks!

Runtime error while converting encrypted private key to PKCS#8

Consider the following snippet:

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"

	"github.com/youmark/pkcs8"
)

func generate(bits int, passphrase string) ([]byte, error) {
	key, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return nil, err
	}

	block := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key),
	}

	if passphrase != "" {
		block, err = x509.EncryptPEMBlock(rand.Reader, block.Type, block.Bytes, []byte(passphrase), x509.PEMCipherAES256)
		if err != nil {
			return nil, err
		}
	}

	return pem.EncodeToMemory(block), nil
}

func convert(pemBytes []byte, passphrase string) ([]byte, error) {
	block, _ := pem.Decode(pemBytes)
	if block == nil {
		return nil, fmt.Errorf("no valid private key found")
	}

	var (
		privateKeyBytes []byte
		privateKey      interface{}
		err             error
	)

	if x509.IsEncryptedPEMBlock(block) {
		privateKeyBytes, err = x509.DecryptPEMBlock(block, []byte(passphrase))
		if err != nil {
			return nil, fmt.Errorf("couldn't decrypt private key")
		}
	} else {
		privateKeyBytes = block.Bytes
	}

	switch block.Type {
	case "RSA PRIVATE KEY":
		privateKey, err = x509.ParsePKCS1PrivateKey(privateKeyBytes)
		if err != nil {
			return nil, fmt.Errorf("couldn't parse der encoded key: %v", privateKeyBytes)
		}
	default:
		return nil, fmt.Errorf("unsupported key type %q", block.Type)
	}

	return pkcs8.ConvertPrivateKeyToPKCS8(privateKey, []byte(passphrase))
}

func main() {
	passphrase := "unicorn"
	pemBytes, err := generate(1024, passphrase)
	if err != nil {
		panic(err)
	}

	_, err = convert(pemBytes, passphrase)
	if err != nil {
		panic(err)
	}
}

I'm trying to generate an encrypted RSA based private key and then converting it to PKCS#8. This results into a runtime error:

panic: runtime error: slice bounds out of range

goroutine 1 [running]:
github.com/youmark/pkcs8.convertPrivateKeyToPKCS8Encrypted(0x521b80, 0xc4201583c0, 0xc420010b58, 0x7, 0x8, 0x8, 0x43d483, 0xc42004be90, 0x53a0cf, 0x7)
	/home/umayr/Code/go/src/github.com/youmark/pkcs8/pkcs8.go:210 +0x6d5
github.com/youmark/pkcs8.ConvertPrivateKeyToPKCS8(0x521b80, 0xc4201583c0, 0xc42004bee8, 0x1, 0x1, 0x20, 0x270, 0x0, 0x0, 0xc42014e8d0)
	/home/umayr/Code/go/src/github.com/youmark/pkcs8/pkcs8.go:243 +0xc8
main.convert(0xc420164000, 0x3da, 0x778, 0x53a0cf, 0x7, 0x778, 0x0, 0x0, 0xc420000340, 0xc420000340)
	/home/umayr/Code/go/src/github.com/umayr/pkcs8/ref.go:65 +0x3d6
main.main()
	/home/umayr/Code/go/src/github.com/umayr/pkcs8/ref.go:75 +0xa4
exit status 2

With a little debugging, I think this line is causing the issue in pkcs8.go:

pkey = pkey[0 : n+padding]

Here n is the length of pkey and above line is trying to create a slice from 0 to length of pkey + padding which should return an error as demonstrated in this example.

Replacing this line with:

diff --git a/pkcs8.go b/pkcs8.go
index 0b6c6e0..dde6818 100644
--- a/pkcs8.go
+++ b/pkcs8.go
@@ -207,7 +207,7 @@ func convertPrivateKeyToPKCS8Encrypted(priv interface{}, password []byte) ([]byt
        padding := aes.BlockSize - len(pkey)%aes.BlockSize
        if padding > 0 {
                n := len(pkey)
-               pkey = pkey[0 : n+padding]
+               pkey = append(pkey, make([]byte, padding)...)
                for i := 0; i < padding; i++ {
                        pkey[n+i] = byte(padding)
                }

fixes this issue temporarily. I can have a PR ready for this with more efficient fix.

Using semver tags

I was checking rclone's dependencies and when updating pkcs8 I see the following

$ go get -u github.com/youmark/pkcs8@latest
go: downloading github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76
(...)
go: upgraded github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a => v0.0.0-20240424034433-3c2c7870ae76

It's not pointing to the 1.2 version as go requires using "semver" release numbers X.Y.Z.

https://go.dev/blog/publishing-go-modules

Would it be possible in the future, or for current release, to tag releases with MAJOR.MINOR.PATCH format?

Mismatch for decrypted AES-128-CBC key

Hello, I'm having some trouble where the decrypted RSA key from openssl differs from the one decrypted by this library. Here is a test running an openssl command to generate an encrypted key, running the decryption using this library and running the decryption using openssl, showing the two results differences. Am I doing something wrong or is the library at fault here? ๐Ÿค”

package main

import (
	"crypto/x509"
	"encoding/pem"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	"github.com/youmark/pkcs8"
)

func TestXxx(t *testing.T) {
	const password = "password"

	directory := t.TempDir()
	encryptedFilepath := filepath.Join(directory, "encrypted.pem")
	decryptedFilepath := filepath.Join(directory, "decrypted.pem")

	// Generate RSA AES-128-CBC encrypted key using the password
	err := exec.Command("openssl", "genpkey", "-algorithm", "RSA",
		"-aes-128-cbc", "-pass", "pass:"+password, "-out", encryptedFilepath).Run()
	failOnError(t, err)

	// Read and decrypt encrypted key with pkcs8 library
	encryptedPEMBytes, err := os.ReadFile(encryptedFilepath)
	failOnError(t, err)
	encryptedPEMBlock, _ := pem.Decode(encryptedPEMBytes)
	decryptedPrivateKey, err := pkcs8.ParsePKCS8PrivateKey(encryptedPEMBlock.Bytes, []byte(password))
	failOnError(t, err)

	// Encode decrypted private key to PKCS8
	decryptedDER, err := x509.MarshalPKCS8PrivateKey(decryptedPrivateKey)
	failOnError(t, err)
	decryptedPEMBlock := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: decryptedDER,
	}
	decryptedPEMBytes := pem.EncodeToMemory(decryptedPEMBlock)

	// Decrypt RSA AES-128-CBC encrypted key with openssl
	err = exec.Command("openssl", "rsa", "-in", encryptedFilepath,
		"-passin", "pass:"+password, "-out", decryptedFilepath).Run()
	failOnError(t, err)

	// Compare the two results
	expectedDecryptedPEM, err := os.ReadFile(decryptedFilepath)
	failOnError(t, err)
	if string(expectedDecryptedPEM) != string(decryptedPEMBytes) {
		t.Fatalf("expected: %s\nactual: %s", string(expectedDecryptedPEM), string(decryptedPEMBytes))
	}
}

func failOnError(t *testing.T, err error) {
	t.Helper()
	if err != nil {
		t.Fatal(err)
	}
}

Create new release

Following #13 and some other pull requests it would be interesting to create a new release (1.1) so that we could easily import it with glide/dep.

Not able to parse encrypted private key using ParsePKCS8PrivateKey method : Getting error pkcs8: only PKCS #5 v2.0 supported

Private key format :

var encryptedKey = []byte(-----BEGIN ENCRYPTED PRIVATE KEY----- s+2e0UnZEGxw0JRV8+D4lY3Em+2KuaUkjxWduHSpLFT55FdRSLW1BL2zsbqdWgSO wvkbvTLkJZ6fouCOjfdIhRYuCg== -----END ENCRYPTED PRIVATE KEY----- )
openssl asn1parse -in key.pem -i -dlimit 16
0:d=0 hl=4 l=2463 cons: SEQUENCE
4:d=1 hl=2 l= 73 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :PBES2
17:d=2 hl=2 l= 60 cons: SEQUENCE
19:d=3 hl=2 l= 27 cons: SEQUENCE
21:d=4 hl=2 l= 9 prim: OBJECT :PBKDF2
32:d=4 hl=2 l= 14 cons: SEQUENCE
34:d=5 hl=2 l= 8 prim: OCTET STRING
0000 - d5 82 19 ef 1a d5 51 3e- ......Q>
44:d=5 hl=2 l= 2 prim: INTEGER :0800
48:d=3 hl=2 l= 29 cons: SEQUENCE
50:d=4 hl=2 l= 9 prim: OBJECT :aes-256-cbc
61:d=4 hl=2 l= 16 prim: OCTET STRING
0000 - 69 d8 7f 79 2a f8 62 58-f9 52 29 03 32 39 95 ac i..y*.bX.R).29..
79:d=1 hl=4 l=2384 prim: OCTET STRING
0000 - 44 17 d7 a2 8b 73 9b 51-6b a3 79 f6 53 d5 28 6d D....s.Qk.y.S.(m

how to determine different hash function for password

I create a private key by openssl pkcs8 like this:
openssl pkcs8 -in rsa.key -out pkcs8.key -topk8 -passout pass:xxxxx -v2 aes-256-cbc -iter 4096
when i call the function ParsePKCS8PrivateKey, got this error "pkcs8: incorrect password"

i'm sure my password is correct, so i think maybe something was wrong with password check.
at this line:

pkcs8/pkcs8.go

Line 204 in 7e063b7

key := pbkdf2.Key(password, salt, iter, 32, sha1.New)

it's hard code with sha1.New function.

then i go back to check my key file.
openssl asn1parse -in pkcs8.key

0:d=0 hl=4 l=2478 cons: SEQUENCE
4:d=1 hl=2 l= 88 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :PBES2
17:d=2 hl=2 l= 75 cons: SEQUENCE
19:d=3 hl=2 l= 42 cons: SEQUENCE
21:d=4 hl=2 l= 9 prim: OBJECT :PBKDF2
32:d=4 hl=2 l= 29 cons: SEQUENCE
34:d=5 hl=2 l= 8 prim: OCTET STRING [HEX DUMP]:5624B6B1D069090A
44:d=5 hl=2 l= 3 prim: INTEGER :0F4240
49:d=5 hl=2 l= 12 cons: SEQUENCE
51:d=6 hl=2 l= 8 prim: OBJECT :hmacWithSHA256
61:d=6 hl=2 l= 0 prim: NULL
63:d=3 hl=2 l= 29 cons: SEQUENCE
65:d=4 hl=2 l= 9 prim: OBJECT :aes-256-cbc

As i checked the openssl manual page, it show this option:

-v2prf alg
This option sets the PRF algorithm to use with PKCS#5 v2.0. A typical value value would be hmacWithSHA256. If this option isn't set then the default for the cipher is used or hmacWithSHA256 if there is no default.
ใ€€
Some implementations may not support custom PRF algorithms and may require the hmacWithSHA1 option to work.

So i tried again with sha1 hash function to convert the key:
openssl pkcs8 -in rsa.key -out pkcs8.key -topk8 -passout pass:xxxxx -v2 aes-256-cbc -iter 4096 -v2prf hmacWithSHA1

ParsePKCS8PrivateKey worked fine this time.
ใ€€
Is there any way to auto determine the hash function with sha1 and sha256 ?

This only compiles with go1.22

In this commit

2fd42e2

The go version was updated to go1.22 in the go.mod here

pkcs8/go.mod

Line 3 in 3c2c787

go 1.22

This means this package no longer compiles with pre go1.22

I don't know if that was your intention? I suspect not, so I'd suggest changing it go go1.20 or lower to allow a few versions grace.

Add AES-CFB Cipher support

Couldn't able to parse password encrypted aes-256-cfb pkcs8 private keys. The library throws the below error,
pkcs8: unsupported cipher (OID: 2.16.840.1.101.3.4.1.44)
Can you please add the support for this?

var oidAES256CFB = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 44}

var AES256CFB = cipherWithBlock{
	ivSize:   aes.BlockSize,
	keySize:  32,
	newBlock: aes.NewCipher,
	oid:      oidAES256CFB,
}

func init() {
	RegisterCipher(oidAES256CFB, func() Cipher {
		return AES256CFB
	})
}

type cipherWithBlock struct {
	oid      asn1.ObjectIdentifier
	ivSize   int
	keySize  int
	newBlock func(key []byte) (cipher.Block, error)
}

func (c cipherWithBlock) IVSize() int {
	return c.ivSize
}

func (c cipherWithBlock) KeySize() int {
	return c.keySize
}

func (c cipherWithBlock) OID() asn1.ObjectIdentifier {
	return c.oid
}

func (c cipherWithBlock) Encrypt(key, iv, plaintext []byte) ([]byte, error) {
	block, err := c.newBlock(key)
	if err != nil {
		return nil, err
	}
	return cfbEncrypt(block, key, iv, plaintext)
}

func (c cipherWithBlock) Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
	block, err := c.newBlock(key)
	if err != nil {
		return nil, err
	}
	return cfbDecrypt(block, key, iv, ciphertext)
}

func cfbEncrypt(block cipher.Block, key, iv, plaintext []byte) ([]byte, error) {
	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
	return ciphertext, nil
}

func cfbDecrypt(block cipher.Block, key, iv, ciphertext []byte) ([]byte, error) {
	stream := cipher.NewCFBDecrypter(block, iv)
	plaintext := make([]byte, len(ciphertext))
	stream.XORKeyStream(plaintext, ciphertext)
	return plaintext, nil
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.