decentralized-identity / ethr-did-resolver

DID resolver for Ethereum Addresses with support for key management

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[proposal] compute X25519 encryption keys automatically for Ed25519 key entries

mirceanis opened this issue · comments

Is your feature request related to a problem? Please describe.
Ed25519/X25519 keys have a special relationship, where the public X25519 key usable for keyAgreement can be computed from the public Ed25519 key usable for signing.
did:key already uses this relationship to express X25519 keyAgreement relationships automatically from Ed25519 keys.

Describe the solution you'd like
When a Ed25519 signing key is added to one of the "signing" verification relationships, or to the verificationMethod array the resolver should automatically add a derived X25519 key to the verificationMethods and reference it under the keyAgreement relationship.

Describe alternatives you've considered
The alternative is to manually compute the X25519 key and add it using a new transaction, but any new transaction implies additional gas costs.

Additional context

Coincidence that you wrote this issue. We just tried some Veramo didcomm stuff out on Friday and had almost the exact same thought. 😄

Is this something that would happen implicitly? What happens if a user decides he wants to rotate or remove this key? IMHO the lower the entry barrier to send authcrypt didcomm messages the better.

This is also coming out oulf our didcomm experiments :)

If the user rotates the Ed25519 key, the X25519 derived key would be rotated too.

I like the implicit keyAgreement entry based on an already existing Ed25519 key. Would there be a way to remove this implicit key? Could you target a revokeAttribute at this to make the resolver ignore it/ not do the derivation?

I like the implicit keyAgreement entry based on an already existing Ed25519 key. Would there be a way to remove this implicit key? Could you target a revokeAttribute at this to make the resolver ignore it/ not do the derivation?

Good point, I was also trying to figure that out, and I suppose that could be done.
But I don't really see the benefit in revoking only the derived encryption key.
This paper says it should be safe to use the derived encryption key, and since that key can't be used for signing, it doesn't grant anyone extra power, except if they were able to intercept messages encrypted to that key as well, but to do that they'd need the private key. And if the private Ed25519 key is compromised, then it doesn't make sense to keep that one and revoke the X25519.

Am I missing something?

I totally agree that this is not an issue from a this point of view. But what if you wanted to create a did:ethr that you don't want to be used for encrypting data because its sole purpose is to sign credentials? We would now impose an implicit, non-removable key for encrypting data that some peoples SSI wallet with a did:ethr should not even have to capability to do. Is this a valid concern?

I totally agree that this is not an issue from a this point of view. But what if you wanted to create a did:ethr that you don't want to be used for encrypting data because its sole purpose is to sign credentials? We would now impose an implicit, non-removable key for encrypting data that some peoples SSI wallet with a did:ethr should not even have to capability to do. Is this a valid concern?

So the concern is that if I have a did:ethr with an Ed25519 key that I can only use for signing, someone resolving my DID would also see a X25519 encryption key and assume that I can decrypt messages, which might not be true.
Is this it?

If so, then I don't think it's that big of a concern.
I mean, it is a valid concern, but one I can live with :)

Just a quick update: We discussed this topic now internally and really want to look into implementing the derivation of the X25519 key for the keyAgreement field from an already existing Ed25519 key. We also want to take a look how/ if we can do an opt-out mechanism via revokeAttribute of this implicit keyAgreement field.

I was just going through your resources, @mirceanis, and a few problems came up imo. First off, the Sodium library only exposes some signing methods. So I had a look into the did key resolver package from digitalbazaar and quickly got to some other library from them where they do the derivation: https://github.com/digitalbazaar/x25519-key-agreement-key-2020/blob/main/lib/X25519KeyAgreementKey2020.js#L190

This is when I noticed that you (obviously) need a public key from the corresponding Ed25519 to get to the X25519 which is on a high-level, if I understand correctly, a Point on the curve. Now the problem:
You might not have a public key looking into the verificationMethod array, but only a blockchainAccountId from which we can't derive the public key without a signature (that we don't have in the resolver). I guess we could do a derivation on a verification key that has been added via setAttribute on another occasion?

... look into implementing the derivation of the X25519 key for the keyAgreement field from an already existing Ed25519 key.

That should be possible by simulating a fictional attribute change event. for the keyAgreement(enc) key.

We also want to take a look how/ if we can do an opt-out mechanism via revokeAttribute of this implicit keyAgreement field.

That should be possible without any special treatment at the resolver level, as revokeAttribute emits the same event as setAttribute, but setting the expiry timestamp to 0.
So if the way you are adding the derived key is by simulating a fictional event, the real revocation event would match against the fictional "add" event and remove the encryption key from the document.

const eventIndex = `${event._eventName}-${

The fictional event should have an eventIndex such that a real revocation event matches against it.
It would probably be something like: fictionalEventIndex = 'DIDAttributeChanged-did/pub/X25519/enc-0x<hex encoded bytes of the X25519 public key>'

If this fictional event is pushed to the list of events, probably this for loop should be replaced by a while loop with unshift:

for (const event of history) {

I was just going through your resources, @mirceanis, and a few problems came up imo. First off, the Sodium library only exposes some signing methods. So I had a look into the did key resolver package from digitalbazaar and quickly got to some other library from them where they do the derivation: https://github.com/digitalbazaar/x25519-key-agreement-key-2020/blob/main/lib/X25519KeyAgreementKey2020.js#L190

They seem to use the @noble stack, based on bigint, which is not available in all JS environments and not designed for crypto operations.
We've been using @stablelib/ed25519 in other libraries. It's a pure JS implementation of the libsodium libraries.
https://github.com/StableLib/stablelib/blob/a89a438fcbf855de6b2e9faa2630f03c3f3b3a54/packages/ed25519/ed25519.ts#L861

This is when I noticed that you (obviously) need a public key from the corresponding Ed25519 to get to the X25519 which is on a high-level, if I understand correctly, a Point on the curve. Now the problem: You might not have a public key looking into the verificationMethod array, but only a blockchainAccountId from which we can't derive the public key without a signature (that we don't have in the resolver). I guess we could do a derivation on a verification key that has been added via setAttribute on another occasion?

Yes, the derivation would be done on a Ed25519 key that has been added via setAttribute.
You don't need to worry about blockchainAccountId since that only applies to secp256k1 keys, that cannot be converted to X25519

Thanks so much for clarifying this. To be honst, I never really read up on the different key types and their differences. I have some general assumptions in my head and just expected you could do the same on secp256k1. :) Do you know by any chance some good resources to read up on with a general overview maybe? We'll start picking this up tomorrow if nothing else comes up internally.

EDIT for transparency: We are currently re-evaluating the urgency of this for us. So we might not pick this up as quickly as we thought.

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.