I generated an ED25519 key pair using OpenSSL as follows:
openssl genpkey -algorithm ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem
Based on this answer, I managed to extract the 32 bytes ED25519 key from the private PEM file with:
openssl asn1parse -in private.pem -offset 14
Output:
0:d=0 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:1E9D38B5274152A78DFF1A86FA464CEADC1F4238CA2C17060C3C507349424A34
So the 32 byte key (encoded as 64 hex characters) is:
1E9D38B5274152A78DFF1A86FA464CEADC1F4238CA2C17060C3C507349424A34
How can I do the same for the PEM public file public.pem?
And how could I create a valid public PEM file for that 32-byte key?
Note: My ultimate goal is to create a public ED25519 PEM file from a known 32 byte public ED25519 key. (without knowing the private key)
How can I do the same for the PEM public file public.pem?
Method 1: General method
OpenSSL provides a built-in method to print out the 32-byte hex keys for both private and public keys, whether they are in the DER or PEM format:
The main options are:
See the OpenSSL pkey documentation for more details.
Example usage:
Corresponding output:
If you leave out the
-nooutoption, you simply also get the PEM (ASCII version) of the key printed out as well.Example:
Method 2: Extract 32-byte keys using xxd
If you need to store the 32-byte keys in a variable, it can be more convenient to convert the key files to the binary DER format and then use xxd to extract them. The 32-byte keys are simply the last 32 bytes of the DER files, whether it is the private or public key.
Create DER files from PEM files if necessary
Here we use the
openssl pkeyutility again:New relevant options:
Getting the last 32-bytes using xxd
Here is what the contents of the private and public DER files look like in hexadecimal:
The last 32-bytes in each case are the keys, i.e. in this case:
To extract them and save them to a variable, you can use this command:
This will print out the last 32 bytes (
-s -32: seek 32 bytes from the end) on one line (-cols 32: 32 byte columns per line), without the extra offset and ASCII information that xxd prints ou by default (-plainoption).Example usage:
You can check that these correspond to the
openssl pkeyoutput we got earlier with the-textoption.Store output in a variable:
And how could I create a valid public PEM file for that 32-byte key?
Based on the xxd output of the DER files seen before, we know that DER files are simply a binary header followed by the 32-byte key. The headers are different for private and public keys, but independent of the 32-byte keys, i.e. any such header followed by 32 bytes is a valid DER file.
The headers are:
This makes creating the DER files easy and they can then be converted to PEM files using
openssl pkey.Note: I do not know why the headers are this way, but it seems to have to do with the RFC 8410 specification. See also this stackoverflow answer.
Creating a 32-bytes public PEM key
Let's assume our 32-byte public key is d164893b1ce11717ab48224ffe26102e9c9c13613690eeed3829aba67d6fb787 in hex format.
First, we create a valid DER file by simply appending those bytes to the standard header of a DER file:
Next, we convert it to the PEM format with:
Creating a 32-bytes private PEM key
Let's assume our 32-byte private key is b74eb32cd805ed82a3580efa5921cdb20aad7f4bf64109057e846111555ea3e9 in hex format.
First, we create a valid DER file by simply appending those bytes to the standard header of a DER file:
Next, we convert it to the PEM format with:
Test the manually created PEM files