# PKCS#8 private key format

PKCS#8 is the standard private key format, recognisable from its `-----BEGIN PRIVATE KEY-----` header. It wraps the raw key material in a structure that also records an algorithm identifier, so a single parser can read RSA, EC, Ed25519 and future key types alike. The older PKCS#1 format (`BEGIN RSA PRIVATE KEY`) has no such field and is RSA-only. Java, Go and most modern libraries accept PKCS#8 exclusively, which makes converting to it the most common key-format task there is.

Source: https://certguru.io/formats/pkcs8/
Last updated: 2026-08-19
Commands verified against OpenSSL 3.5.7.

---

## The structure

A PKCS#8 key is two fields: an algorithm identifier and the key material itself.

*See both*

```bash
openssl asn1parse -in private.key
```

Expected output:

```
0:d=0  hl=4 l= 630 cons: SEQUENCE
    4:d=1  hl=2 l=   1 prim: INTEGER           :00
    7:d=1  hl=2 l=  13 cons: SEQUENCE
    9:d=2  hl=2 l=   9 prim: OBJECT            :rsaEncryption
   20:d=2  hl=2 l=   0 prim: NULL
   22:d=1  hl=4 l= 608 prim: OCTET STRING
```

The `OBJECT :rsaEncryption` line is the part PKCS#1 does not have. It is what lets a parser know
what is in the `OCTET STRING` without being told.

## Compared with the older formats

| | PKCS#1 | SEC1 | PKCS#8 |
| --- | --- | --- | --- |
| PEM header | `BEGIN RSA PRIVATE KEY` | `BEGIN EC PRIVATE KEY` | `BEGIN PRIVATE KEY` |
| Algorithms | RSA only | EC only | Any |
| Records its own algorithm | No | No | Yes |
| Standard encryption | `Proc-Type` header, weak | `Proc-Type` header, weak | PBES2 / PBKDF2 |
| Accepted by Java, Go | No | No | Yes |

## Converting to PKCS#8

*From PKCS#1, unencrypted output*

```bash
openssl pkcs8 -topk8 -in pkcs1.key -out pkcs8.key -nocrypt
```

Full detail at [convert PKCS#1 to PKCS#8](/convert/pkcs1-to-pkcs8/).

## Encrypted PKCS#8

The encrypted variant uses PBES2 — PBKDF2 to stretch the passphrase, then a real cipher:

*Encrypt with AES-256 rather than the default*

```bash
openssl pkcs8 -topk8 -in plain.key -out encrypted.key -v2 aes-256-cbc
```

*Inspect what a file was encrypted with*

```bash
openssl asn1parse -in encrypted.key | head -n 12
```

> **The default is not always what you want**
>
> Older OpenSSL builds default `-v2` to `des-ede3-cbc` (3DES). Specify `aes-256-cbc` explicitly
>   rather than relying on the default, particularly in scripts that may run on a range of versions.

## Generating PKCS#8 directly

`openssl genpkey` writes PKCS#8 natively, so there is nothing to convert:

```bash
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.key
```

*EC key, same format*

```bash
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ec.key
```

This is why `genpkey` is preferred over the older `genrsa` — see
[generate a private key](/openssl/generate-private-key/).


## Frequently asked questions

### How do I recognise a PKCS#8 key?

The header reads `-----BEGIN PRIVATE KEY-----` when unencrypted, or `-----BEGIN ENCRYPTED PRIVATE KEY-----` when it has a passphrase. PKCS#1 keys say `BEGIN RSA PRIVATE KEY` instead.

### Why do Java and Go only accept PKCS#8?

Because it is self-describing. The algorithm identifier inside the structure means one code path loads any key type, rather than requiring the caller to know in advance whether they are holding RSA or EC material.

### Is PKCS#8 more secure than PKCS#1?

Not inherently — an unencrypted PKCS#8 key is exactly as exposed as an unencrypted PKCS#1 one. What PKCS#8 adds is a standard way to encrypt the key with a modern KDF and cipher, which PKCS#1 handles through an older and weaker header-based mechanism.

### Can PKCS#8 hold an EC key?

Yes, and Ed25519, and anything else with a registered algorithm identifier. That generality is the whole reason it replaced the per-algorithm formats.


## References

- [RFC 5958: asymmetric key packages](https://www.rfc-editor.org/rfc/rfc5958) — PKCS#8, the self-describing private key container
- [RFC 8017: PKCS #1 RSA cryptography](https://www.rfc-editor.org/rfc/rfc8017) — the RSA-only key format that PKCS#8 generalised

## Related pages

- https://certguru.io/convert/pkcs1-to-pkcs8/
- https://certguru.io/convert/pkcs8-to-pkcs1/
- https://certguru.io/formats/key/
- https://certguru.io/openssl/generate-private-key/
- https://certguru.io/openssl/remove-passphrase-from-key/

--
CertGuru — https://certguru.io
