cornfeedhobo / ssh-keydgen

Generate Deterministic SSH keys
Apache License 2.0
41 stars 9 forks source link

Generated keys from the same passphrase are different #10

Open WhiteBlackGoose opened 1 year ago

WhiteBlackGoose commented 1 year ago

Hello.

For some reason, when some time between runs passes, key's value changes:

image image

WhiteBlackGoose commented 1 year ago

hmmm, with ed25519 it looks reproducible

cornfeedhobo commented 1 year ago

@WhiteBlackGoose the hacky way this is slapped together means that it's tightly coupled to the implementation for the go version you compile with. For now, the releases available here are reliable, but I haven't gone about revisiting this yet.

The issues stem from the different ways each language and release handles or throws away entropy.

I'm open to suggestions. Preferably something that could be validated against a python implementation as well.

WhiteBlackGoose commented 1 year ago

Thanks for the info. I'll try to pack a nix package of your app to ensure reproducibility, when I have time.

catwith1hat commented 1 month ago

With all due respect to your project, but this project has fundamental flaws in its current form.

crypto/rsa, and crypto/ecdas both say very specifically that their GenerateKey method is not guaranteed to be deterministic between different releases or even different calls to that function. No crypto library, that I know off, makes those deterministic guarantees for key generation. And pinning crypto libraries or Go itself to a specific version forever is a bad fix.

I personally would only see one way forward. Remove ecdsa and rsa. Their implementations are way too complex to have a key generation implementation enshrined forever. ed25519 is the only SSH key format that I see some hope for.

For ed25519, I would enshrine the implementation inside of djb's ed25519 implementation:

  crypto_hash_sha512(az,sk,32);
  az[0] &= 248;
  az[31] &= 63;
  az[31] |= 64;

SHA512 is probably a fine choice even in the long run. Clamping of the output az derives directly from the Curve25519 paper Page 5, quote:

The set of Curve25519 secret keys is, by definition, {0, 8, 16, 24, . . ., 248} × {0, 1, . . ., 255}^30 × {64, 65, 66, . . ., 127};

That is very easy to implement deterministically. There are probably other methods, e.g. left-shifting the whole 512 bit vector by 3 bits to clear the bottom 3 bits. But at the end, that's not more or less effective. djb's implementation is fast and straight forward, and spec-compliant. It feels okay to enshrine it.

The above could be easily ported to Go. crypto/ed25519 allows you to compute the public key from the raw private key.

I would appreciate if you can mark the project as experimental on your main page until this issue is resolved. I consider it a deployment risk in its current form.

catwith1hat commented 3 weeks ago

https://github.com/catwith1hat/det_ssh_key is an implementation of deterministic ed25519 keys as envisioned above.