# What's in a private key? - 2021-04-16

When you got a PEM to sign or encrypt with, what's inside? Read below to get a grasp on what's inside a PEM file, where schemas for things are and how to read them, and a hint of DER and ASN.1!

To start, let's generate a PKCS#8 private key with a command like so.

```
openssl ecparam -name prime256v1 -genkey -noout | \
openssl pkcs8 -topk8 -nocrypt -outform pem
```

Note:The first generates a SEC 1 EC key, while the second part wraps it in PKCS#8.

```
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSrIgHDO6EP1OBeaF
3qJPL4GJ7IaNYfLrKAWWizN5Lm6hRANCAARK7+/rD5ZRafqYBfECrGHDqYjBXT6a
WtN9IDzZ5nue+eSPbsPFEbY9gzEIggrfnh6i9HnDV4jRXvC84xLoYY3j
-----END PRIVATE KEY-----
```

Let's take a moment and break down this PEM key.

Note:This key is created for this post and is not used for any content outside of this post.

First, let's convert the base64 body to hex, it'll make searching
for repeated sequences such as `044aefef`

easier.

`308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104204ab2201c33ba10fd4e05e685dea24f2f8189ec868d61f2eb2805968b33792e6ea144034200044aefefeb0f965169fa9805f102ac61c3a988c15d3e9a5ad37d203cd9e67b9ef9e48f6ec3c511b63d833108820adf9e1ea2f479c35788d15ef0bce312e8618de3`

Below is another representation of the same hex string, ASN.1 has tags (indicated in blue), the byte size of the tag (indicated in teal), and the contents of each tag (left in black). A more thorough introduction to the binary structure of Distinguished Encoding Rules (or DER) will come in a later post.

If we parse this into ASN.1, we get the structure as follows:

```
{:type :sequence :value (
{:type :integer :value 0}
{:type :sequence :value (
{:type :object-identifier :value "1.2.840.10045.2.1"}
{:type :object-identifier :value "1.2.840.10045.3.1.7"}
)
}
{:type :octet-string :value "306b02010104204ab2201c33ba10fd4e05e685dea24f2f8189ec868d61f2eb2805968b33792e6ea144034200044aefefeb0f965169fa9805f102ac61c3a988c15d3e9a5ad37d203cd9e67b9ef9e48f6ec3c511b63d833108820adf9e1ea2f479c35788d15ef0bce312e8618de3"}
)
}
```

There's an opaque blob in here too. So if we rip it out then

`308187020100301306072a8648ce3d020106082a8648ce3d030107046d`

is responsible for

```
{:type :sequence :value (
{:type :integer :value 0}
{:type :sequence :value (
{:type :object-identifier :value "1.2.840.10045.2.1"}
{:type :object-identifier :value "1.2.840.10045.3.1.7"}
)
}
:omitted-content
)
}
```

Up here you'll see a couple object identifiers, a number, and then the opaque blob. Here's the ASN.1 schema for that, as defined in PKCS#8. These schemas are a bit old and crusty, but they do the job.

```
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
privateKey PrivateKey,
attributes [0] IMPLICIT Attributes OPTIONAL
}
PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
PrivateKey ::= OCTET STRING
Attributes ::= SET OF Attribute
```

And `AlgorithmIdentifier`

comes from X.509

```
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
```

So the opaque section identified above is the private key as an octet string
*(essentially just a byte array)*.
While the version is fixed at ** 0**,
and the algorithm seems to be... Well whatever these object identifiers are.

Inspecting the first: OID 1.2.840.10045.2.1, Elliptic curve public key cryptography, defined by
IETF RFC3279 and RFC5753. So that is the private key algorithm (or class of algorithms)
While it's parameter is.. well that comes next: OID 1.2.840.10045.3.1.7.
Its description is `256 bit elliptic curve (szOID_ECC_CURVE_P256)`

So we can see now that we are using an Elliptic curve cryptography private key with the `secp256r1`

curve.

Note:An elliptic key curve is a complex topic for another post, but in short it's a standardized set of values that can reproduce a mathematical calculation which is hard to reverse.

Note:According to table 3 in SEC 1 ECC keys with 256 bits such as the`secp256r1`

curve (as correlated in SEC 2 table 1) has a security strength of`128`

, a size of`256`

, and an effective RSA comparison of`3072`

bits. Other references include.. NIST Special Publication 800-56A Table 24, NIST Special Publication 800-57 Part 1, Draft NIST Special Publication 800-186, RFC5903. According to NIST Recommendations (keylength.com), this curve security strength may be used until 2030 and beyond.

So what's in the opaque section?
Actually it's a SEC 1 key! And according to the PKCS#8 private key info above, a `secp256r1`

key.

```
{:type :sequence :value (
{:type :integer :value 1}
{:encoding :hex :type :octet-string
:value "4ab2201c33ba10fd4e05e685dea24f2f8189ec868d61f2eb2805968b33792e6e"
}
{:constructed true :tag 1 :type :context-specific
:value ({:bits 520 :encoding :hex :type :bit-string
:value "044aefefeb0f965169fa9805f102ac61c3a988c15d3e9a5ad37d203cd9e67b9ef9e48f6ec3c511b63d833108820adf9e1ea2f479c35788d15ef0bce312e8618de3"
})
})
}
```

The ASN.1 schema, according to the SEC 1 for an EC Private key is

```
ECPrivateKey ::= SEQUENCE {
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
privateKey OCTET STRING,
parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
publicKey [1] BIT STRING OPTIONAL
}
```

So you can see the private key has a version (a constant set to `1`

)
and an `OCTET STRING`

for the private key value (an arbitrary in value with the appropriate bit length).
The private key's length and contents are specific to the key type,
which was designated via the object identifiers in the PKCS8 key wrap above.
Following that are any domain parameters, in this case none were included
as the key type specifies the parameters for the curve.
Lastly the public key, which again is specific to the type of key in particular.
For whatever reason, it is a common trope for the public key to be a bit string, rather than an octet string.

Note:The first byte of a bit string is usually how many bits should be shifted for the big-endian integer that follows. When it is divisible by 8, meaning the whole number is represented with full byte values, then you'll find the hex`0x00`

prior to the contents, the contents starting with`0x04`

.

According to SEC 1, the private key content is a big-endian big integer for this particular type of ECC key. There's no further meaning in this integer, besides keeping it secret.

For the public key, this is actually described in SEC 1 Section 2.3.3
In this example, point compression is not used, as indicated by the leading byte `0x04`

.
What follows is the X coordinate fit to 32 bytes (as the key is 256 bits, per the curve configuration),
and the Y coordinate likewise.

Note:Point compression allows an already short public key, at least in comparison to RSA, to be even shorter, such that only a single byte is used to signify if it is an "odd" or "even" prime. Some call the bit for this thesign, but these numbers don't occur below zero. If the public key starts with`0x02`

or`0x03`

, then point compression is used. Again, the above example has`0x04`

for an uncompressed point.

If you'd like to inspect this key file, what you can do is:

```
$ openssl ec -text -in key.pem -noout
read EC key
Private-Key: (256 bit)
priv:
4a:b2:20:1c:33:ba:10:fd:4e:05:e6:85:de:a2:4f:
2f:81:89:ec:86:8d:61:f2:eb:28:05:96:8b:33:79:
2e:6e
pub:
04:4a:ef:ef:eb:0f:96:51:69:fa:98:05:f1:02:ac:
61:c3:a9:88:c1:5d:3e:9a:5a:d3:7d:20:3c:d9:e6:
7b:9e:f9:e4:8f:6e:c3:c5:11:b6:3d:83:31:08:82:
0a:df:9e:1e:a2:f4:79:c3:57:88:d1:5e:f0:bc:e3:
12:e8:61:8d:e3
ASN1 OID: prime256v1
NIST CURVE: P-256
```

Note:Printing key content is specific to the key type, so for rsa use`openssl rsa`

instead of`openssl ec`

That was quite a wandering way to peer into a key file, but it demonstrates how to approach dissecting PEM content going forward.

So, what's the private key?

`d: 33785871188901339266591346360023059825676061520759082182150047705565125750382`

And the public key?

```
x: 33895083098249617942691657925075450393182366388506933082364507268911843745529
y: 103380753077289600266558146853629830711510703014701325542323242537280776277475
```

Not too riveting I know. But what you can do with this can be!

That wraps it up for this post, I hope you've learned more about
what's in a key `.pem`

file and a basic understanding of navigating
standards documents and schemas.