Skip to content
Recovering a private key without MicroB2B

Recovering a private key without MicroB2B

This page shows how to get a certificate’s private key back with OpenSSL alone. Use it when MicroB2B cannot run, or when you must move a key to another product.

MicroB2B never stores a private key in the clear. It encrypts each key with the master key, SECRETS_KEY. To recover a key, you need two things:

  • the database, or a backup of it
  • the master key that the key was encrypted with

Without the master key, the private key cannot be recovered. See secrets for how to keep the master key safe.

What you need

  • OpenSSL 3
  • bash, base64, od, tr and cut
  • a shell on a safe machine, away from where the database is kept

A test runs the commands on this page against a key that MicroB2B encrypted. So they match what this version of MicroB2B does.

Step 1: Find the certificate’s ID

Open the certificate in the web UI. Its ID is the number in the address: /ui/certificates/<id>. If the web UI does not run, list the certificates from the database:

sqlite3 microb2b.db "SELECT id, description FROM certificates"

Step 2: Read the key from the database

The table certificates holds two columns for a certificate with a private key:

ColumnWhat it holds
private_key_bytesThe encrypted key, a PEM that starts with -----BEGIN ENCRYPTED PRIVATE KEY-----
private_key_kidThe ID of the master key it was encrypted with: 8 lowercase hex characters

Write the key to key.pem and keep the key ID in KID. With SQLite, for certificate 3:

sqlite3 microb2b.db "SELECT private_key_bytes FROM certificates WHERE id = 3" > key.pem
KID=$(sqlite3 microb2b.db "SELECT private_key_kid FROM certificates WHERE id = 3")

With PostgreSQL, use psql "$DB_URL" -At -c "<the same SELECT>" instead.

Step 3: Set the master key

Set SECRETS_KEY to the master key, exactly as MicroB2B is configured with it:

SECRETS_KEY='<the base64 master key>'

If MicroB2B reads the key from a file (SECRETS_KEY_FILE), use SECRETS_KEY=$(cat <that file>).

If your key is written in hex, not base64, set MASTER_KEY to the hex value instead. Then skip the first line of the commands in step 4.

Step 4: Decrypt the key

Run these commands in the directory where key.pem is:

MASTER_KEY=$(printf '%s' "$SECRETS_KEY" | base64 -d | od -An -tx1 | tr -d ' \n')

# The key id of this master key: it must be the row's private_key_kid.
printf '%s' 'microb2b secret key id' | openssl dgst -sha256 -mac HMAC -macopt hexkey:"$MASTER_KEY" -r | cut -c1-8

PASSWORD=$(openssl kdf -keylen 32 -kdfopt digest:SHA256 -kdfopt hexkey:"$MASTER_KEY" \
  -kdfopt info:'microb2b private key v1' HKDF | tr -d ':' | tr 'A-F' 'a-f')

openssl pkcs8 -in key.pem -passin pass:"$PASSWORD" -out recovered.pem

The commands do three things:

  1. They turn the master key into hex.
  2. They print the ID of this master key.
  3. They work out the key’s password from the master key, and decrypt key.pem into recovered.pem.

Step 5: Check the result

Compare the printed key ID with KID.

  • They are the same. recovered.pem is the private key, as an unencrypted PKCS#8 PEM. Most products import this format.
  • They differ. This is not the master key the row was encrypted with. During a key rotation, the row may name an earlier key. Try each key from SECRETS_PREVIOUS_KEYS in step 3.

If openssl pkcs8 fails with a decryption error, the master key is wrong, or key.pem is not complete. Check that key.pem starts with -----BEGIN ENCRYPTED PRIVATE KEY----- and ends with the matching END line.

Protect the recovered key. recovered.pem is not encrypted. Keep it and the master key away from the database and its backups. Delete recovered.pem when you no longer need it.

How the password is made

You only need this to write your own tool. Everything is derived from the 32 bytes of the master key:

ValueHow it is made
Key IDThe first 4 bytes of HMAC-SHA256(master key, microb2b secret key id), as 8 lowercase hex characters
PasswordHKDF-SHA256 of the master key, empty salt, info microb2b private key v1, 32 bytes, as 64 lowercase hex characters

The PEM is encrypted with PBES2, using PBKDF2-HMAC-SHA256 and AES-256-CBC. This is what openssl pkcs8 -topk8 -v2 aes-256-cbc -v2prf hmacWithSHA256 writes. The salt, iteration count and IV are in the PEM itself.

Other secrets

MicroB2B also encrypts the secret values of its configuration: passwords, header values, signing secrets and webhook URLs. This page does not cover them. If you lose one, enter it again.