7

I'm having a problem where when I export a key from 1password, and use it with ssh -i, I get

Load key "/home/user/.ssh/private_ed25519": invalid format

Doing a google search on this, it seems to be a problem where 1password stores their ED25519 key in PKCS#8, from their developer

Copying a private key will copy it in PKCS#8--the format 1Password stores the key. Unfortunately, OpenSSH does not support ED25519 keys in PKCS#8, only in OpenSSH format. Downloading a key will convert it to OpenSSH format. The reason RSA keys work is because OpenSSH does support RSA keys in PKCS#8.

They suggest using a "Download" feature, but I don't have that feature and many other people also don't have that feature. But there should be more than one way to skin this cat,

You can create an ed25519 keyfile in PKCS#8 with,

openssl genpkey -algorithm ed25519 -out private.pem

Is there any method to convert a private Ed25519 key (private.pem in the above) from PKCS#8 to the OpenSSH format?

When I try, with ssh-keygen, I get

$ ssh-keygen -i -f private.pem -m pkcs8
do_convert_from_pkcs8: private.pem is not a recognised public key format
0

3 Answers 3

12
+50

Let's walk through it. First, we generate a private key in Ed25519:

$ openssl genpkey -algorithm ED25519 -out ed25519.pem
$ cat ed25519.pem
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEID+U9VakauO4Fsv4b/znpDHcdYg74U68siZjnWLPn7Q1
-----END PRIVATE KEY-----

We read the man page on ssh-keygen -i:

 -i    This option will read an unencrypted private (or public)
       key file in the format specified by the -m option and print
       an OpenSSH compatible private (or public) key to stdout.

and think, "oh, so we just do this":

$ ssh-keygen -i -f ed25519.pem -m pkcs8
do_convert_from_pkcs8: ed25519.pem is not a recognised public key format

Nope, maybe the documentation lies and the error is instructive.

So, we grab the public key corresponding to that private key:

$ openssl pkey -in ed25519.pem -pubout > ed25519.pub
$ cat ed25519.pub
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA0IgiJOLeGDwumzkm+wi82nP7wvmbnaoWKmNNHMaq/Mw=
-----END PUBLIC KEY-----

and try again, this time giving the public key:

$ ssh-keygen -i -f ed25519.pub -m pkcs8
do_convert_from_pkcs8: unsupported pubkey type 1087

Dang it. Why?!

Well, it's a bug:

OpenSSH doesn't currently support reading or writing Ed25519 keys in any format other than the OpenSSH native key format.

Not all libcrypto implementations support Ed25519 keys, in particular LibreSSL does not.

This patch adds support for reading PKCS8 Ed25519 keys on recent OpenSSL, but it can't be upstreamed until LibreSSL supports these keys too.

So, full stop, Ed25519 support is incomplete in the openssl available upstream (which is what we're familiar with in Linux, for example).

We have two possible choices:

  1. Compile a patched version of Portable OpenSSH and convert using the command above; or,
  2. Use the alternative tool mentioned by the bug reporter, sshpk, to convert.

Let's try the latter, since it's just a NPM package:

$ npm install -g sshpk
$ sshpk-conv ed25519.pem -t ssh -p
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDQiCIk4t4YPC6bOSb7CLzac/vC+ZudqhYqY00cxqr8zAAAAJAyR1o6Mkda
OgAAAAtzc2gtZWQyNTUxOQAAACDQiCIk4t4YPC6bOSb7CLzac/vC+ZudqhYqY00cxqr8zA
AAAEA/lPVWpGrjuBbL+G/856Qx3HWIO+FOvLImY51iz5+0NdCIIiTi3hg8Lps5JvsIvNpz
+8L5m52qFipjTRzGqvzMAAAAC2VkMjU1MTkucGVtAQI=
-----END OPENSSH PRIVATE KEY-----

and there we go: the private key in OpenSSH format.

2
  • 1
    Wow, I would have bountied this more for this quality of answer. Thanks a ton all around. The only follow-up question I have is wtf does a patch to openssl require landing in libressl too? If they're different projects, why does one require support in the other? Jan 17 at 15:55
  • 1
    May also be worth pointing out that it looks like LibreSSL got ed25519 on December 12, when 3.7 landed ftp.openbsd.org/pub/OpenBSD/LibreSSL/… Jan 17 at 16:21
2

Not my (original) work, copied from another thread when I was trying to find out something related (bugs fixed / added by me)

-- a shell script that converts openssl-generated ed25519 private key to a format understood by openssh

tested the following way:

$ openssl genpkey -algorithm ED25519 -out ed25519.pem
$ ./eddsa-ssl-to-ossh.sh ed25519.pem > okey
$ ssh-keygen -l -f okey
#!/bin/sh

set -euf

ssl_priv=$(cat ${1:+"$1"})

pub64=$(echo "$ssl_priv" | openssl pkey -pubout -outform der 2>/dev/null | dd bs=12 skip=1 status=none | base64)

test "$pub64" || { echo "Cannot get public key" >&2; exit 1; }

priv64=$(echo "$ssl_priv" | grep -v '^-' | base64 -d | dd bs=16 skip=1 status=none | base64)

echo '-----BEGIN OPENSSH PRIVATE KEY-----'

{
    printf openssh-key-v1'\000\000\000\000\004'none'\000\000\000\004'none'\000\000\000\000\000\000\000\001\000\000\000'3
    printf '\000\000\000\013'ssh-ed25519'\000\000\000 '
    echo $pub64 | base64 -d
    printf '\000\000\000'
    printf '\210\000\000\000\000\000\000\000\000'
    printf '\000\000\000\013'ssh-ed25519'\000\000\000 '
    echo $pub64 | base64 -d
    printf '\000\000\000@'
    echo $priv64| base64 -d
    echo $pub64 | base64 -d
    printf '\000\000\000\000\001\002\003\004\005'
} | base64

echo '-----END OPENSSH PRIVATE KEY-----'
2
  • Hi @Tomi, I know you provided your answer 6 months ago but can you explain where are those printf lines coming from? Or if you can point me to the right place so I'll find out myself.. Many thanks in advance!
    – Greg0ry
    Aug 26 at 22:54
  • 1
    I don't think I ever got explanation -- It was a while before I wrote that comment I saw the text in some stack* page (the above was converted (back) from one perl program where I used it). Most of those separated substrings crearly contain length parameters (also ' ' for 32 and @ for 64).
    – Tomi
    Nov 6 at 11:20
-1

Yes, there is a method to convert a private Ed25519 key from PKCS#8 to the OpenSSH format. You can use the ssh-keygen command-line tool that comes with OpenSSH to convert the key. The basic syntax of the command is as follows:

ssh-keygen -i -f keyfile.pem -m pkcs8

Where keyfile.pem is the file name of your PKCS#8 private key. The -i flag tells ssh-keygen to import a key, the -f flag specifies the input file and the -m flag specifies the key format as pkcs8.

When you run this command, ssh-keygen will convert the key and output it to the terminal. You can then redirect the output to a file to save it in the OpenSSH format:

ssh-keygen -i -f keyfile.pem -m pkcs8 > openssh-keyfile.pem

If you're trying to convert the key to be used in ssh-agent or ssh-add, you'll have to remove the passphrase from the key first, otherwise it will still prompt you for it when adding the key to the agent

The below command will prompt you to enter a new passphrase:

ssh-keygen -i -f keyfile.pem -m pkcs8 | ssh-keygen -p -m pem
1
  • 1
    This doesn't work on ed25519 keys. Try it openssl genpkey -algorithm ed25519 -out keyfile.pem; ssh-keygen -i -f keyfile2.pem -m pkcs8 Jan 16 at 17:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .