tel / saltine

Cryptography that's easy to digest (NaCl/libsodium bindings)
https://github.com/tel/saltine
MIT License
61 stars 29 forks source link

Add binding to crypto_sign_seed_keypair #18

Open mithrandi opened 9 years ago

mithrandi commented 9 years ago

There is already a binding (newKeypair) for crypto_sign_keypair which generates a keypair from random bytes; however, there is no binding for crypto_sign_seed_keypair which generates a keypair from a seed the caller provides.

tel commented 9 years ago

Can you explain the use case for that? It is listed here but isn't documented anywhere that I can find it.

mithrandi commented 9 years ago

It's mentioned here as well, although not really discussed at all. I'd hesitate to try to enumerate all of the possible uses of this function as the functionality is very general, but I think the interesting use cases involve deriving a key either directly or indirectly from some existing secret material.

My specific use case was writing this proof-of-concept; the README explains in more detail, but I'm hashing a "master secret" with some additional (non-secret) data in order to produce multiple unique keypairs from a single secret. I ended up just binding the function myself; I could try clean the code up for inclusion in saltine, although I'm not sure the way I bound the function was ideal (this was my first time writing Haskell FFI / bytestrings code).

tel commented 9 years ago

So, the tradeoff I have in my mind (though I haven't had much time to develop this thought) is that NaCl is most interesting for providing a high-level low-mistake API. In particular with things like crypto_sign_keypair the API intentionally does not expose a deterministic keypair generator since it is a major design goal to ensure that all entropy comes through the same system entropy source to minimize the entropy attack surface area.

The tradeoff is a less-flexible API, of course.

I'd be interested in entertaining exposure of an "unsafe" API which includes functions like crypto_sign_seed_keypair. I believe "unsafe" is the proper term over merely "internal"—it's almost certainly a bad idea to use these functions in production code (according to the original NaCl design anyway).

Again, I don't have a lot of time to think about this issue carefully, but please let me know what you think.

mithrandi commented 9 years ago

I realised that having this API in Saltine wouldn't help me anyway, since the SecretKey and PublicKey constructors are not exposed, so there's no way for me to store the keys anyway (unless I missed something?).

I should note that "generating a keypair" really just means "calculate the public key", since the seed bytes are left as-is; however, everyone seems to treat the 64-byte secret key (which is just the 32-byte secret seed concatenated with the 32-byte public key) as opaque (resulting in the SSH private key format containing 3 copies of the public key, for example), so it seems your reasoning is inline with how other people are using the code.

As far as NaCl itself goes, this sort of use may indeed be out of scope (this function is in libsodium, but not libnacl, I believe); it's just a bit frustrating to have half a dozen libraries wrapping Ed25519 code, and not a single one of them exposing this functionality!

tel commented 9 years ago

To be clear, I'm interested in exploring this space more. The current design of Saltine was both practical for my needs at the time and naive (it was one of my first C binding libraries).

I think any NaCl binding (including libsodium, frankly) ought to respect the design goals of NaCl itself if for no other reason than preventing weakening of security due to erosion of their API.

But that said, I also think Haskell libraries benefit a lot from meaningful transparency. My types today are not great about this! I would be willing to entertain changes here.

In particular, the tradeoff is between safety and flexibility (as always) and I think safety can be maintained in the face of greater flexibility so long as it's always the easy, obvious path.

So, I think you're asking for something reasonable, even with the key type exposure, so long as it's done carefully.

I don't want to just add any function not documented in the main NaCl docs to any major module, basically.

On Thu, Dec 18, 2014 at 9:13 AM, Tristan Seligmann notifications@github.com wrote:

I realised that having this API in Saltine wouldn't help me anyway, since the SecretKey and PublicKey constructors are not exposed, so there's no way for me to store the keys anyway (unless I missed something?). I should note that "generating a keypair" really just means "calculate the public key", since the seed bytes are left as-is; however, everyone seems to treat the 64-byte secret key (which is just the 32-byte secret seed concatenated with the 32-byte public key) as opaque (resulting in the SSH private key format containing 3 copies of the public key, for example), so it seems your reasoning is inline with how other people are using the code.

As far as NaCl itself goes, this sort of use may indeed be out of scope (this function is in libsodium, but not libnacl, I believe); it's just a bit frustrating to have half a dozen libraries wrapping Ed25519 code, and not a single one of them exposing this functionality!

Reply to this email directly or view it on GitHub: https://github.com/tel/saltine/issues/18#issuecomment-67490617