Skip to main content

Openssl and Rust libp2p ED25519 Key Pairs

· 3 min read
Steve Taylor

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


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
  1. Generate a PEM file ED25519 format openssl genpkey -algorithm Ed25519 -out ed25519.pem

  2. 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

  3. Generate the public key part skipping over the header openssl pkey -in ed25519.pem -pubout -outform DER | tail -c +13 >

    Note: The resulting file should be 32 bytes

  4. Combine the private and public parts to create the key pair that Rust ED25519 can use cat ed25519.pri > 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


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
  1. Generate a temporary PEM file to get the ED25519 header from openssl genpkey -algorithm Ed25519 -out working.pem

  2. 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

  3. Split the Rust ED25519 key pair and grab the private key (first 32 bytes) cat ed25519.ser | head -c 32 > ed25519.pri

  4. 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

  5. Convert the openssl formatted private key to PEM openssl pkey -in ed25519_with_header.pri -out ed25519.pem

  6. Verify the new PEM file openssl pkey -in ed25519.pem -pubout -text

    Expected Output"

    -----BEGIN PUBLIC KEY-----
    -----END PUBLIC KEY-----
    ED25519 Public-Key: