dchest / tweetnacl-js

Port of TweetNaCl cryptographic library to JavaScript
https://tweetnacl.js.org
The Unlicense
1.78k stars 294 forks source link

How to use ed25519 secret key in php (Should I convert it to to PEM/OpenSSH compatible format?) #231

Closed zhil closed 2 years ago

zhil commented 2 years ago

Sample OpenSSH key generation

ssh-keygen -t ed25519

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBR+M3uYYyqmvhZZaNaX8G0Gd/EThx2PmOJ7tqeYqzgSwAAAJADzBXQA8wV
0AAAAAtzc2gtZWQyNTUxOQAAACBR+M3uYYyqmvhZZaNaX8G0Gd/EThx2PmOJ7tqeYqzgSw
AAAECAnoUofYaz1kK7+vqPnVZpXfkEWM46TaP35BZzgPTHxFH4ze5hjKqa+Fllo1pfwbQZ
38ROHHY+Y4nu2p5irOBLAAAACHpoaWxAcGMxAQIDBAU=
-----END OPENSSH PRIVATE KEY-----

public key ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFH4ze5hjKqa+Fllo1pfwbQZ38ROHHY+Y4nu2p5irOBL

I created sandbox https://codesandbox.io/s/testing-near-signature-cx6xlt?file=/src/TestSignature.js

zhil commented 2 years ago

As I understand, by default you encode secret key with base58 (Bitcoin characters set?) and I need to convert it to base64?

zhil commented 2 years ago

ok, I am pretty confused. I have converted secret key to Uint8Array using bs58.decode(), but its 64 bytes? And Ed25519 private key length should be 32 bytes? https://github.com/openssl/openssl/issues/6357

dchest commented 2 years ago

You need to convert keys generated by TweetNaCl to Base64. The secret key consists of 32 bytes secret and 32 bytes public key (for OpenSSH you'll need the first part). Also, there's some encoding likely needed for the key before you convert it to Base64 for OpenSSH format.

zhil commented 2 years ago

@dchest thanks for your help. I failed to generate OpenSSH key but still solved my main target. Quick info for somebody, who will google this.

Basically, I need to reuse Near signature functionality https://docs.near.org/ru/docs/api/naj-cookbook#verify-signature in PHP code. So I planned to convert Near private keys to something compatible with PEM key format. And since Near uses tweetnacl-js - I created this one issue.

But everything is way more simple. PHP has sodium_* functions and sodium Ed25519 have the same 64 bytes length.

print strlen(sodium_crypto_sign_secretkey(sodium_crypto_sign_keypair()));
// 64

So, I basically converted NEAR (tweetnacl-js) key from base58 format to raw bytes and used them in sodium. It worked just fine!

         $nearPrivateKey = 'qZQEGDN5wQmiVtEQZgHQ3Y4uZJ3EBKuFGydAcM84pVbfnDxiq2Ufp38WaE8wyV6MELRMV9jZtT9RfCqKPELWe98';
        $base58Decoder = new Tuupola\Base58(["characters" => Base58::BITCOIN]);
        $rawNearKey = $base58Decoder->decode($nearPrivateKey);
        print bin2hex(sodium_crypto_sign('Test message', $rawNearKey));