The ED25519 crate (libp2p::identity) can generate and load key pairs. These key pairs are 64 bytes long. First 32 bytes are the private key and last 32 bytes the public key.
Openssl generates the ED25519 key pairs with a header in front of the public and private keys.
As a result, the Openssl keys pairs and Rust key pairs are not interchangeable. Therefore, if you want to use a key pair generated by openssl with Rust then it must be converted. Conversion is also needed to go from Rust to openssl.
Below are the steps needed to convert key pairs from one format to another.
Generate a Key Pair using Rust libp2p
let keypair = identity::ed25519::Keypair::generate();
Using openssl to generate a key pair that Rust identity::ed25519::Keypair::decode()
can understand
Note: openssl 3.X is required
TL;DR - PEM to Rust ED25519 Key Pair
#/usr/bin/env bash
KEYNAME=$1
PATH=/usr/local/Cellar/openssl@3/3.0.7/bin:$PATH
openssl genpkey -algorithm Ed25519 -out ${KEYNAME}.pem
openssl pkey -in ${KEYNAME}.pem -out - -outform DER | tail -c +17 > ${KEYNAME}.ser
openssl pkey -in ${KEYNAME}.pem -pubout -outform DER | tail -c +13 >> ${KEYNAME}.ser
Generate a PEM file ED25519 format
openssl genpkey -algorithm Ed25519 -out ed25519.pem
Generate the private key part skipping over the header
openssl pkey -in ed25519.pem -out - -outform DER | tail -c +17 > ed25519.pri
Note: The resulting file should be 32 bytes
Generate the public key part skipping over the header
openssl pkey -in ed25519.pem -pubout -outform DER | tail -c +13 > ed25519.pub
Note: The resulting file should be 32 bytes
Combine the private and public parts to create the key pair that Rust ED25519 can use
cat ed25519.pri ed25519.pub > ed25519.ser
Note: The resulting file should be 64 bytes
Loading Rust libp2p Key Pair into a Rust Object
let mut keypair_file = fs::File::open("ed25519.ser")?;
let mut buffer = vec![0; 64]; // buffer containing the key pair from disk
keypair_file.read_exact(&mut buffer)?; // read the file into the buffer
let keypair = identity::ed25519::Keypair::decode(&mut buffer); // decode the buffer into a Keypair object
Converting a Rust ED25519 key pair to PEM
TL;DR - Rust ED25519 Key Pair to PEM
#/usr/bin/env bash
KEYNAME=$1
export PATH=/usr/local/Cellar/openssl@3/3.0.7/bin:$PATH
openssl genpkey -algorithm Ed25519 -out working.pem
openssl pkey -in working.pem -out - -outform DER | head -c 16 > header.pri
cat ${KEYNAME}.ser | head -c 32 > ${KEYNAME}.pri
cat header.pri ${KEYNAME}.pri > ${KEYNAME}_with_header.pri
openssl pkey -in ${KEYNAME}_with_header.pri -out ${KEYNAME}.pem
openssl pkey -in ${KEYNAME}.pem -pubout -text
rm working.pem
Generate a temporary PEM file to get the ED25519 header from
openssl genpkey -algorithm Ed25519 -out working.pem
Get the ED25519 header. Note: All ED25519 headers are the same length since the key is fixed length
openssl pkey -in working.pem -out - -outform DER | head -c 16 > header.pri
Split the Rust ED25519 key pair and grab the private key (first 32 bytes)
cat ed25519.ser | head -c 32 > ed25519.pri
Concatenate the header to the private key to create an openssl formatted private key that openssl can work with.
cat header.pri ed25519.pri > ed25519_with_header.pri
Convert the openssl formatted private key to PEM
openssl pkey -in ed25519_with_header.pri -out ed25519.pem
Verify the new PEM file
openssl pkey -in ed25519.pem -pubout -text
Expected Output"
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEARicanp19ZUl5nANQL7bOFh5emlXo6s2U3MElkMwLYM4=
-----END PUBLIC KEY-----
ED25519 Public-Key:
pub:
46:27:1a:9e:9d:7d:65:49:79:9c:03:50:2f:b6:ce:
16:1e:5e:9a:55:e8:ea:cd:94:dc:c1:25:90:cc:0b:
60:ce