Skip to content

Instantly share code, notes, and snippets.

@rhenium
Created October 6, 2020 08:48
Show Gist options
  • Save rhenium/c3fd53d706f4f218f7ba354c0e1fad6d to your computer and use it in GitHub Desktop.
Save rhenium/c3fd53d706f4f218f7ba354c0e1fad6d to your computer and use it in GitHub Desktop.
path = ARGV[0]
pem = File.binread(path)
unless pem =~ /^-----BEGIN OPENSSH PRIVATE KEY-----(.*)-----END OPENSSH PRIVATE KEY-----$/m
raise "invalid OpenSSH private key"
end
binary = $1.unpack1("m")
magic = binary.byteslice(0, 15)
raise "invalid magic" if magic != "openssh-key-v1\0"
encry = binary.byteslice(15, 20)
raise "encrypted key?" if encry != "\0\0\0\4none\0\0\0\4none\0\0\0\0"
numkeys = binary.byteslice(35, 4).unpack1("N")
raise "invalid number of keys" if numkeys != 1
pubkeylen = binary.byteslice(39, 4).unpack1("N")
pubkey = binary.byteslice(43, pubkeylen)
datalen = binary.byteslice(43 + pubkeylen, 4).unpack1("N")
data = binary.byteslice(47 + pubkeylen, datalen)
raise "invalid total length" if binary.size != 47 + pubkeylen + datalen
# Now parse data
c1, c2, data1 = data.unpack("NNa*")
raise "invalid check" if c1 != c2
d1headlen = data1.byteslice(0, 4).unpack1("N")
d1headbody = data1.byteslice(4, d1headlen)
raise "invalid head" if d1headbody != "ssh-ed25519"
d1pub1len = data1.byteslice(4 + d1headlen, 4).unpack1("N")
d1pub1body = data1.byteslice(8 + d1headlen, d1pub1len)
d1privpublen = data1.byteslice(8 + d1headlen + d1pub1len, 4).unpack1("N")
d1privpubbody = data1.byteslice(12 + d1headlen + d1pub1len, d1privpublen)
raise "invalid body length" if d1privpublen != 64
privkeyraw = d1privpubbody.byteslice(0, 32)
# Construct PKCS #8 private key
p8hdr = %w{30 2e 02 01 00 30 05 06 03 2b 65 70 04 22 04 20}.map{ |x| x.to_i(16) }.pack("C*")
p8der = p8hdr + privkeyraw
puts <<~EOF
-----BEGIN PRIVATE KEY-----
#{[p8der].pack("m0")}
-----END PRIVATE KEY-----
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment