3

i have generated an ed2215 private key as follows:

$ ssh-keygen -o -a 100 -t ed25519 -f id_ed25519

and it looks like

-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----

where ... is truncated data.

although it feels like base64, i see that each truncated line has at most 64 characters, where regular base64 encoding does not hold that charactristics.

what is the format (or encoding) of the private key? (if i have the private key in byte array, which transformation do i need to apply before i write it to a file that coincide with openssh output)

Mr.
  • 143
  • 1
  • 5

1 Answers1

3

although it feels like base64, i see that each truncated line has at most 64 characters

It is base64 encoded. Remove the -----BEGIN OPENSSH PRIVATE KEY----- and -----END OPENSSH PRIVATE KEY----- and the new lines ("\n") and then you can parse as per https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD . Quoting that file:

This document describes the private key format for OpenSSH.

1. Overall format

The key consists of a header, a list of public keys, and
an encrypted list of matching private keys.

#define AUTH_MAGIC      "openssh-key-v1"

    byte[]  AUTH_MAGIC
    string  ciphername
    string  kdfname
    string  kdfoptions
    int number of keys N
    string  publickey1
    string  publickey2
    ...
    string  publickeyN
    string  encrypted, padded list of private keys

2. KDF options for kdfname "bcrypt"

The options:

    string salt
    uint32 rounds

are concatenated and represented as a string.

3. Unencrypted list of N private keys

The list of privatekey/comment pairs is padded with the
bytes 1, 2, 3, ... until the total length is a multiple
of the cipher block size.

    uint32  checkint
    uint32  checkint
    string  privatekey1
    string  comment1
    string  privatekey2
    string  comment2
    ...
    string  privatekeyN
    string  commentN
    char    1
    char    2
    char    3
    ...
    char    padlen % 255

Before the key is encrypted, a random integer is assigned
to both checkint fields so successful decryption can be
quickly checked by verifying that both checkint fields
hold the same value.

4. Encryption

The KDF is used to derive a key, IV (and other values required by
the cipher) from the passphrase. These values are then used to
encrypt the unencrypted list of private keys.

5. No encryption

For unencrypted keys the cipher "none" and the KDF "none"
are used with empty passphrases. The options if the KDF "none"
are the empty string.
neubert
  • 2,969
  • 1
  • 29
  • 58