And yes, that representation is what I'm having trouble with adding to
Curve25519.
OK. The first thing to do here is undo the Base64 encoding:
Code Block % base64 -D > id_ed25519.bin |
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW |
QyNTUxOQAAACAoSm6+8gO6/Tej0dPOstvZUg8nJfIz291HEN8BpBylcAAAAJidoAf+naAH |
/gAAAAtzc2gtZWQyNTUxOQAAACAoSm6+8gO6/Tej0dPOstvZUg8nJfIz291HEN8BpBylcA |
AAAEDHZrwc6IPx2KQNQZodJLwuQ511eG6BkNEFg9flDpOKjyhKbr7yA7r9N6PR086y29lS |
Dycl8jPb3UcQ3wGkHKVwAAAAE3F1aW5uQHNsaW1leS5sb2NhbC4BAg== |
^D |
% xxd id_ed25519.bin |
00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1.. |
00000010: 0000 046e 6f6e 6500 0000 046e 6f6e 6500 ...none....none. |
00000020: 0000 0000 0000 0100 0000 3300 0000 0b73 ..........3....s |
00000030: 7368 2d65 6432 3535 3139 0000 0020 284a sh-ed25519... (J |
00000040: 6ebe f203 bafd 37a3 d1d3 ceb2 dbd9 520f n.....7.......R. |
00000050: 2725 f233 dbdd 4710 df01 a41c a570 0000 '%.3..G......p.. |
00000060: 0098 9da0 07fe 9da0 07fe 0000 000b 7373 ..............ss |
00000070: 682d 6564 3235 3531 3900 0000 2028 4a6e h-ed25519... (Jn |
00000080: bef2 03ba fd37 a3d1 d3ce b2db d952 0f27 .....7.......R.' |
00000090: 25f2 33db dd47 10df 01a4 1ca5 7000 0000 %.3..G......p... |
000000a0: 40c7 66bc 1ce8 83f1 d8a4 0d41 9a1d 24bc @.f........A..$. |
000000b0: 2e43 9d75 786e 8190 d105 83d7 e50e 938a .C.uxn.......... |
000000c0: 8f28 4a6e bef2 03ba fd37 a3d1 d3ce b2db .(Jn.....7...... |
000000d0: d952 0f27 25f2 33db dd47 10df 01a4 1ca5 .R.'%.3..G...... |
000000e0: 7000 0000 1371 7569 6e6e 4073 6c69 6d65 p....quinn@slime |
000000f0: 792e 6c6f 6361 6c2e 0102 y.local... |
The
openssh-key-v1 header confirms that this is OpenSSH’s ‘new’ key format. AFAICT this isn’t formally documented, although there’s tonnes of info about it lurking on the ’net. Based on some digging (primarily
this) I believe that the Curve25519 public key appears 3 times in that data:
Code Block 00000030: 284a |
00000040: 6ebe f203 bafd 37a3 d1d3 ceb2 dbd9 520f |
00000050: 2725 f233 dbdd 4710 df01 a41c a570 |
|
00000070: 28 4a6e |
00000080: bef2 03ba fd37 a3d1 d3ce b2db d952 0f27 |
00000090: 25f2 33db dd47 10df 01a4 1ca5 70 |
|
000000c0: 28 4a6e bef2 03ba fd37 a3d1 d3ce b2db |
000000d0: d952 0f27 25f2 33db dd47 10df 01a4 1ca5 |
000000e0: 70 |
And the private key just once:
Code Block 000000a0: c7 66bc 1ce8 83f1 d8a4 0d41 9a1d 24bc |
000000b0: 2e43 9d75 786e 8190 d105 83d7 e50e 938a |
000000c0: 8f |
I plugged these into CryptoKit and they seem to work:
Code Block let privateKeyBytes: [UInt8] = [ |
0xC7, 0x66, 0xBC, 0x1C, 0xE8, 0x83, 0xF1, 0xD8, |
0xA4, 0x0D, 0x41, 0x9A, 0x1D, 0x24, 0xBC, 0x2E, |
0x43, 0x9D, 0x75, 0x78, 0x6E, 0x81, 0x90, 0xD1, |
0x05, 0x83, 0xD7, 0xE5, 0x0E, 0x93, 0x8A, 0x8F, |
] |
let publicKeyBytes: [UInt8] = [ |
0x28, 0x4A, 0x6E, 0xBE, 0xF2, 0x03, 0xBA, 0xFD, |
0x37, 0xA3, 0xD1, 0xD3, 0xCE, 0xB2, 0xDB, 0xD9, |
0x52, 0x0F, 0x27, 0x25, 0xF2, 0x33, 0xDB, 0xDD, |
0x47, 0x10, 0xDF, 0x01, 0xA4, 0x1C, 0xA5, 0x70, |
] |
let privateKey = try! Curve25519.Signing.PrivateKey(rawRepresentation: privateKeyBytes) |
let publicKey = try! Curve25519.Signing.PublicKey(rawRepresentation: publicKeyBytes) |
let signature = try! privateKey.signature(for: Data("Hello Cruel World!".utf8)) |
let isValid = publicKey.isValidSignature(signature, for: Data("Hello Cruel World!".utf8)) |
print(isValid) // -> true |
So, to summarise:
You are working with a Curve25519 key in OpenSSH’s ‘new’ key format.
CryptoKit has no facilities for importing or exporting this format.
If you want to do that then you’ll need write (or find) code that extracts the Curve25519 from this format (or the reverse).
As always, if you’d like to see better support for this sort of thing, you should file an
enhancement request describing your requirements. If you do, please post your bug number, just for the record.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"