Ring: X25519 (and/or ECDH in general) with static keys

Created on 5 Nov 2016  路  13Comments  路  Source: briansmith/ring

Hi, while attempting to add ring as a backend to a Noise implementation, I found that ring does not support DH key agreement with static keys. Static DH is required for the protocol. Is static DH support planned? Are there any workarounds in the meantime (perhaps a way to unsafely clone the key?).

All 13 comments

Are there any workarounds in the meantime (perhaps a way to unsafely clone the key?).

We do everything we can do to ensure that isn't possible.

Hi, while attempting to add ring as a backend to a Noise implementation, I found that ring does not support DH key agreement with static keys. Static DH is required for the protocol. Is static DH support planned?

Yes, it is. In particular, I explicitly want to make it possible to implement Noise using _ring_.

Basically, we need to create a ring::agreement::StaticKeyPair to go alongside ring::agreement::EphemeralPrivateKey. In fact, ring::signature::Ed25519KeyPair isn't too far from what we need.

So, at this point, it's simply a matter of getting the code and tests written.

To clarify some things:

  • The key generation function should be like Ed25519KeyPairs, not like EphemeralPrivateKey's generate_serializable(), which returns the key pair object _and_ a serialized representation of the private + public key. Otherwise, the caller won't be able to save the key pair bytes to disk.
  • Also like Ed25519KeyPair, StaticKeyPair needs to save the public key within the StaticKeyPair object. This is different from EphemeralPrivateKey. EphemeralPrivateKey's public key handling is optimized for the fact that the public key is only needed once and isn't always needed at the same time as the private key. This is why we have EphemeralPrivateKey and not EphemeralKeyPair.
  • As stated above, generate_serializable() needs to give the caller a serialized sequence of bytes that encodes the key pair. That means there needs to be a function that de-serializes that sequence of bytes, again similar to Ed25519KeyPair. For now, it is OK to do this the same way as Ed25519KeyPair for X25519 keys. In the future I will almost definitely switch this to use a self-describing typed file format.
  • Since you only need X25519 for Noise, it is OK to defer the work on the P-256 and P-384 variants. In fact, you can just name it X25519StaticKeyPair and avoid all the agreement::Algorithm stuff, for now. Eventually we'll generalize it to work for P-256 and P-384.

Hi @danburkert, I took a peek at your fork and saw that you started working on this a couple weeks ago. Are you planning to keep working on it? Is there anything I can do to help, beyond the writing of notes in my previous comment above? Thanks!

Hi @briansmith. Unfortunately I will not have any time soon to wrap it up. The notes you gave are good, and if I get time to revisit in the future I will definitely take them into account, I just can't promise when that would be.

Hi @briansmith. Unfortunately I will not have any time soon to wrap it up. The notes you gave are good, and if I get time to revisit in the future I will definitely take them into account, I just can't promise when that would be.

Understood. Thanks!

Is there no way to simply create an ec private key from DER/PEM/etc?

It's coming soon. ECDSA code is already written. X25519 and P-256/P-384 ECDH will follow shortly.

Depends on #508.

Hi, I have a similar problem. I want to be able to perform DH key agreement with static keys, but it seems like ring's agreement::EphemeralPrivateKey interface doesn't allow to import my own private key.

Edit: I added a bounty for this issue.

Bountysource

Hi, @briansmith
I am trying to implement the X25519StaticKeyPair, what I want to do is the following:

Introduce a struct name X25519StaticPair as you mentioned above,

pub struct X22519StaticKeyPair {
    private_key: ec::PrivateKey,
    public_key: [u8; 32usize],
    alg: &'static Algorithm,
}

then implement it with the following function:

  • pub fn generate(rng: &rand::SecureRandom) -> Result<Self, error::Unspecified> to generate a pair of keys.
  • pub fn from_private_key(private_key: ec::PrivateKey) -> Result<Self, error::Unspecified> to generate a pair of keys according the given PrivateKey
  • pub fn from_bytes(bytes: untrusted::Input) -> Result<Self, error::Unspecified> to generate a pair of keys according the given serialized private key.

and some helper function, like the private_key() -> &ec::PrivateKey and so on...

Finally, the place of the agree() function is confusing me, if place it inside the impl X25519StaticKeyPair block, that will make the API inconsistent(compare with agree_ephemeral), but if I place it outside the impl block, the naming is a problem, maybe x25519_agree() will be a choice? Notice that this function doesn't consume PrivateKey.

Anything I miss?

I'm interested in this functionality. It seems like #602 implements this. Do you think this will be merged soon?

I'm also interested! Please don't make me use OpenSSL. I don't want to go back into the dark. :(

Adding my interest for non ethereal Agreement using X25519. Trying to implement whisper systems double ratcheting algorithm and recommended in their docs https://signal.org/docs/specifications/doubleratchet/#recommended-cryptographic-algorithms

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tarcieri picture tarcieri  路  9Comments

est31 picture est31  路  6Comments

neoeinstein picture neoeinstein  路  5Comments

Ianleeclark picture Ianleeclark  路  9Comments

bruceadams picture bruceadams  路  9Comments