ethereum / EIPs

The Ethereum Improvement Proposal repository
https://eips.ethereum.org/
Creative Commons Zero v1.0 Universal
12.82k stars 5.24k forks source link

Discussions for EIP: Add DID related methods to the JSON-RPC #2845

Closed oed closed 2 years ago

oed commented 4 years ago

https://eips.ethereum.org/EIPS/eip-2844

oed commented 4 years ago

Replying to @kdenhartog from the duplicate discussion thread #2851

Original message:

My first round of feedback for this:

One of the general topics that's been discussed quite a bit is if we want to restrict the algorithms and key types supported in the JOSE registries. Often times this is done to limit the scope of code that needs to be written by various implementations which in turn should bolster interoperability. I see you've done this via recommendations, but I'd wonder if we want to restrict further usage here via explicitly not supporting certain algorithms. Is that something you think would be beneficial?

Note: This next piece of feedback is based on potentially misunderstanding the paths permission aspect. I'd like to figure out more about this and then we may not need to address the comments below. Additionally, I'd like to understand the architecture of where the operations are being performed because I'm thinking I misunder

Another point that I caught quite quickly is that this EIP is looking to use DIDs to manage discoverability of keys. I'm happy to see this approach being taken further as I think it will help quite a bit. I hope it's an approach that more DApps look to use as well. With that in mind, one of the things that I wasn't sure about was how the API would be integrated with key management to perform the sign and encrypt operations. Is your current assumption that a Key Management architecture will be used within the implementation and it's the responsibility of implementers to be handle this? In general, every JOSE implementation I've looked at has made the assumption that the private key is provided in some way and it will perform the cryptographic operation when necessary. This is slightly different from what's proposed at this point though. I think we may need to think more about what the general expectation is on the implementers and the callers in terms of who's providing which data (private key), who's performing the cryptographic operations, and who's performing the structuring of the data (e.g. creating the JWE with the signed data). From there we'll likely want to take a look at the general API design to make sure it aligns with what's generally done by wallets and other DApps that would be using this API.

I'm also interested to know more about why encrypt and verify were not included. I assume there's back history from the previous attempts that may further explain this. Have they already been added via other APIs or was there some other reason that they were left off?

In general though @oed, I like the direction that you're going with this and I'm curious to hear others opinions on this.

Personally I would be fine with restricting the alg and key types to the ones that are supported by JOSE registries (are those used by default for COSE as well?).

So the JSON-RPC is used for two main things with ethereum. Interacting interacting with chain state, and requesting things from the wallet. This means that it acts as a way for an app to request signatures and account information from a wallet. So in our case here the only things needed to be done wallet side is signing and decrypting. Internally wallets are free to use whichever key management system they prefer. A caller of any of these methods won't need to provide any type of key material. Both verifying and encryption can happen completely client side (without any wallet interaction) so there is no need to add methods for them. Instead a utility library that does this can be implemented (we're thinking about implementing these utility functions in the js-did library).

OR13 commented 4 years ago

Things to consider...

secp256k1 supports ecdsa (ES256K JWS) and Schnorr (SS256K (not registered!)).... and UPort created ES256K-R which is similarly not registered... and it identical to ES256K with appended recovery byte...

IMO, making the header a required RPC argument, and restricting the valid values of alg is a good way of addressing this issue.

There is also detached JWS https://tools.ietf.org/html/rfc7797 ... this is really useful for when you are signing binary... not some JSON.stringify-iable data (lots of issues with canonicalization and JOSE)....

It's also the default JWS format used by Linked Data Proofs.

I'm not sure adding the did_* prefix to RPC calls is wise.... especially if what we are really doing is exposing JOSE / COSE interfaces.... I would prefer to see jose_jws_sign and jose_jws_sign_detached... and the COSE equivalents.

oed commented 4 years ago

Thanks @OR13

secp256k1 supports ecdsa (ES256K JWS) and Schnorr (SS256K (not registered!)).... and UPort created ES256K-R which is similarly not registered... and it identical to ES256K with appended recovery byte...

Good point. I should probably explicitly say ES256K 👍

IMO, making the header a required RPC argument, and restricting the valid values of alg is a good way of addressing this issue.

Hm, seems like this would require the application developer to be aware of which algs the wallet supports. This would mean that there needs to be an additional rpc method for getting this information. I'd rather have the wallet decide this and append the alg that it is using.

There is also detached JWS https://tools.ietf.org/html/rfc7797

Happy to add this if others express interest.

I'm not sure adding the did_* prefix to RPC calls is wise.... especially if what we are really doing is exposing JOSE / COSE interfaces.... I would prefer to see jose_jws_sign and jose_jws_sign_detached... and the COSE equivalents.

The whole point here is to enable DID signed JOSE/COSE objects. Essentially by setting the kid to the DID (and key fragment) for the signing entity. Imo this is critical for this EIP to be successful. Using did_* for decryption also simplifies things because the combination of key discovery and decryption is key for dev UX.

OR13 commented 4 years ago

If the developer is not required to know which signing algorithms are supported and set the header explicitly, a default header should be provided.... which defaults will be used?

+1 to using kid and making its default value of the form did:example:123#fragment

what about all the developers who want JWTs / JWSs but don't care about DIDs?... I agree that the APIs should be simple, but i question why they should start with dids... to me... dids are more of an option for setting the kid.... but I am assuming there would be APIs for retrieving JWKs.... so the entire system can be used with or without DIDs.

oed commented 4 years ago

which defaults will be used?

That's up to the wallet implementer (a reccommendation is provided in the EIP)

but I am assuming there would be APIs for retrieving JWKs

What do you mean by this exactly? To me this is what you would use the DID for. Using did:ethr would be the most straight forward way for wallets to support some way of distributing JWKs, as all ethereum wallets support did:ethr already.

OR13 commented 4 years ago

put another way...

what RPC interfaces will be provided for getting public key bytes....

possibly options:

did_resolve -> didDocument as json jose_get_jwk_by_kid -> JWK did_jws_verify vs jose_jws_verify

For example... Tangem cards support a "getPublicKey" NFC interface. You can then use that interface to verify signatures... the cards themselves don't support "verifying on the card".... thats similar to the concept of "verifying on the rpc server"...

I'd prefer to have a JOSE RPC interface, that happened to work with DIDs... and a DID RPC interface that supported things like:

resolution (which returns a set of keys, and their associated relationships)...

those relationships have nothing to do with JOSE... they are no mentioned in the JOSE RFCs... they were created in DID Core.

oed commented 4 years ago

what RPC interfaces will be provided for getting public key bytes

This is what did_authenticate is for. With it you will get back the DID that was authenticated. To get the public key bytes you can use something like the DID Resolver which works with any DID method (provided a resolver is implemented for it).

The problem with an RPC method like did_resolve is that it's not really the responsibility of a wallet to resolve DIDs for apps. Instead Ethereum clients would need to implement this method, but then there has to be consensus among client implementers which DID methods to support (would be very hard). I also think DID resolution is more of an application on top of blockchains rather than something that should be implemented in blockchain client software.

awoie commented 4 years ago

did_authenticate should return a proof-of-control of the DID and should expect an aud/ domain and nonce / challenge parameter. I don't know which data format the proof should have and whether it would be allowed to support different formats but it could be either a JWS or CWS.

Updated:

You might be able to use the path as the challenge.

awoie commented 4 years ago

I guess did_createCWS should return a CWS, so there might be a typo in the return value.

Returns: A CWE encoded as base64, string

^^should be rather CWS, right?

awoie commented 4 years ago

Is there a reason to not include an API for:

?

Update:

That certainly only makes sense using authcrypt -> e.g., ECDH-1PU

awoie commented 4 years ago

Is the did parameter needed if the kid or something similar could be used to determine the DID in the CWE/JWE?

awoie commented 4 years ago

Is it needed to recommend a decryption algorithm for decryption? The decryption algorithm can be determined from the CWE/JWE directly, trying to decrypt the CWE/JWE with a different algorithm, would fail anyways. In general I agree that ECDH-ES (X25519) + XChacha20Poly1305 should be recommended.

pedrouid commented 4 years ago

did_authenticate should return a proof-of-control of the DID and should expect an aud/ domain and nonce / challenge parameter. I don't know which data format the proof should have and whether it would be allowed to support different formats but it could be either a JWS or CWS. This definitely would be super useful and best practice that should be adopted by all Ethereum wallets IMO

Me and @wighawag drafted a similar proposal last year where accounts would be exposed with signatures for a given challenge.

https://ethereum-magicians.org/t/automatic-authentication-signature/2429

If this pattern would be possible with did_authenticate by default then we could replace the current eth_requestAccounts with this method instead to include proof-of-control

Same dapps currently after getting the user's accounts follow up with a personal_sign request to attest for the private key ownership or even to access the public key of the account.

I think this should just be the default behavior for all dapp and wallet interoperability

oed commented 4 years ago

Adding a challenge makes sense! Thanks for suggesting @awoie and clarifying @pedrouid. Will add this when I update the draft. Might make sense to make this an actual JWT/CWT with an expiry actually. A challenge should definitely be included. What is your thinking on aud @awoie? Is it strictly needed?

I guess did_createCWS should return a CWS, so there might be a typo in the return value.

Nice catch!

That certainly only makes sense using authcrypt -> e.g., ECDH-1PU

Would you mind expanding on this? And yeah for the suggested encryption alg you can just do the encryption client side.

Is it needed to recommend a decryption algorithm for decryption?

It's really up to the wallet to decide what to use, and state that in their DID document.

Is the did parameter needed if the kid or something similar could be used to determine the DID in the CWE/JWE?

The kid should not specified in the JWE/CWE. That would leak information about the ciphertext.

awoie commented 4 years ago

Adding a challenge makes sense! Thanks for suggesting @awoie and clarifying @pedrouid. Will add this when I update the draft. Might make sense to make this an actual JWT/CWT with an expiry actually. A challenge should definitely be included.

nonce has that purpose in id_token JWTs in OIDC (see IANA claims registry). If you introduce a new claim for this purpose, then registering a new claim name in the IANA should be considered.

What is your thinking on aud @awoie? Is it strictly needed?

aud can be optional and it can be any arbitrary stringOrUri. I think it would be good practice to make use of that. Everyone that receives the JWS would have to identify itself and then decide whether to reject the JWS. Not sure what is the CWS equivalent.

That certainly only makes sense using authcrypt -> e.g., ECDH-1PU

Would you mind expanding on this? And yeah for the suggested encryption alg you can just do the encryption client side.

ECDH-1PU is for example used in DIDComm-messaging to encrypt a message to a DID while enabling the receiver of the encrypted message to verify some sort of authenticity that the sender is has a certain DID (or more general keys) by avoiding the sign-JWS-then-encrypt-JWE pattern. In that case, only the wallet would be able to create such a JWE/CWE because only the wallet controls the private key.

Is the did parameter needed if the kid or something similar could be used to determine the DID in the CWE/JWE?

The kid should not specified in the JWE/CWE. That would leak information about the ciphertext.

The kid won't be in the Ciphertext of the JWE. It would be in the unprotected header field per recipient: see https://tools.ietf.org/html/rfc7516#section-4.1.6. You could use the same pattern as you described for JWS/CWS and use a DID URL.

oed commented 4 years ago

nonce has that purpose in id_token JWTs in OIDC (see IANA claims registry).

Great, let's use nonce 👍

aud can be optional and it can be any arbitrary stringOrUri.

Ok, so this would be optionally set by the wallet?

ECDH-1PU is for example used in DIDComm-messaging to encrypt a message to a DID while enabling the receiver of the encrypted message to verify some sort of authenticity that the sender is has a certain DID (or more general keys) by avoiding the sign-JWS-then-encrypt-JWE pattern.

Makes sense, but seems a bit out of scope for now. Could easily be addressed in an additional EIP! Q: Is the receiver the only party that can verify sender authenticity or can everyone do it?

The kid won't be in the Ciphertext of the JWE.

That's my point :) In some cases you might not want to leak information about whom the ciphertext is intended for.

OR13 commented 4 years ago

kid is optional everywhere, but for JWS, its pretty critical for handling resolution of public key bytes for verification, see this list of JOSE /. DID issues:

https://github.com/decentralized-identity/did-jose-extensions/blob/master/options.md

TL;DR; I'd rather see use of kid defined consistently as pointing to a verificationMethod id... than see people keep creating 1 off spec text to handle key lookups without using JSON-LD.

OR13 commented 4 years ago

I agree we should postpone encryption until we have signatures. can we take an inventory of the proposed RPC methods?

awoie commented 4 years ago

There is also detached JWS https://tools.ietf.org/html/rfc7797 ... this is really useful for when you are signing binary... not some JSON.stringify-iable data (lots of issues with canonicalization and JOSE)....

@oed @OR13 Does it make sense to also support JWS JSON serialization? What happens if a DID has more than one signature key attached to it?

OR13 commented 4 years ago

I assume the API interface would support specifying the exact key to use for signing....

For example: https://github.com/transmute-industries/did-key.js/blob/master/packages/secp256k1/src/__fixtures__/index.ts#L58

did:example:123#fragment is a URI that identifies the public "verification side" of the private "signing side"...

I would consider a wallet API that didn't let me choose the signing key pretty broken, in all cases where there was more than 1 signing key.... its not clear to me that is the case for did:ethr or secp256k1 did:key however... since the did identifies a particular public / private key pair.

awoie commented 4 years ago

I assume the API interface would support specifying the exact key to use for signing....

For example: https://github.com/transmute-industries/did-key.js/blob/master/packages/secp256k1/src/__fixtures__/index.ts#L58

did:example:123#fragment is a URI that identifies the public "verification side" of the private "signing side"...

I would consider a wallet API that didn't let me choose the signing key pretty broken, in all cases where there was more than 1 signing key.... its not clear to me that is the case for did:ethr or secp256k1 did:key however... since the did identifies a particular public / private key pair.

With JSON Serialization you would be able to send multiple signatures back in case the DID controls a few signing keys. That was why I brought that up.

OR13 commented 4 years ago

@awoie hm so the interface would be kid: array<did_uri>, payload: any, header: any=> json serialized JWS

Seems useful.

oed commented 4 years ago

TL;DR; I'd rather see use of kid defined consistently as pointing to a verificationMethod id...

Makes sense. This was my intention. Maybe that was unclear?

Does it make sense to also support JWS JSON serialization? What happens if a DID has more than one signature key attached to it?

I'm agnostic as to which serialization to use. I'm curious though what the use case is for signing with multiple keys from the same DID? If you want to have two different DIDs sign the same payload you can just take two JWS with compact serialization and reserialize them using the JSON serlialization (which is trivial).

I assume the API interface would support specifying the exact key to use for signing....

Yeah exactly. You can already specify the fragment in the did param of did_createJWS.

kdenhartog commented 4 years ago

take two JWS with compact serialization and reserialize them

Would this break the signatures of the two because of the non-payload data being signed (e.g. protected headers)?

If not, it would be cool to enable multi-signature supports as a separate API where a JWS can be passed in with the DID and it will de-assemble the JWS and sign the payload/header data and then that JSON serialized JWS could be passed as a form of a multi-signature to something like a smart contract or any other verifier for that matter.

wighawag commented 4 years ago

Thanks for creating this proposal.

Regarding did_authenticate. From the discussion, It looks like it has multiple purpose

The current draft of this proposal specify that did_authenticate requires user permission. This seems important if authentication is used for something other than ensuring that the user indeed control the did (the private key of the ethereum address presented).

Otherwise, as @pedrouid mentions, did_authenticate could simply replace eth_requestAccounts, see in particular: https://ethereum-magicians.org/t/eip-1102-opt-in-provider-access/414/58 which would already require user to accept showing their did.

But looking at the current draft of the proposal here, it seems that did_authenticate performs more than simply checking if the user control the did being advertised.

It accept a path parameter. And then further in the proposal it is mentioned that decryption happen without user confirmation only if did_authenticate was already accepted for a particular path.

If we go with the idea that did_authenticate replace eth_requestAccount, the path should default to the application origin (like in eth_requestAccount) then the only prompt should be about accepting to reveal your did, the authentication is then done automatically so the application can be sure the user is indeed in control of that did and is not someone faking it.

Any other path would require user confirmation.

Furthermore as mentioned here and explained in Proposal 1: Non-Interactive Decryption If we consider the default path being the application origin, Then decryption should happen automatically for every encryption performed from that same origin. No user confirmation should be required there. For that a mechanism should be put in place so that encryption include the origin in the data.

diagram

This would allow a seamless encrypted storage for application, that can then be safely shared across devices. Of course this is only fully under user control for application on content-addressable system like ipfs, but as mentioned in my comment and blog, an ENS or even DNS name that point to an ipfs hash should use the ipfs hash as the origin (not the ENS name).

Now if the content change (and so the uri), the user would be requested to did_authenticate the new "path"

Now, I am not very knowledgeable with JWS and I might abuse term "path" here by allowing it to represent URI. If that is the case, we could separate the 2.

Note: for traditional URI (non content-addressable) it could be up to the wallet to decide whether a user confirmation is required as there is a security risk that the application get compromised.

oed commented 4 years ago

Would this break the signatures of the two because of the non-payload data being signed (e.g. protected headers)?

It wouldn't. Each signer is free to choose what to put in their protected header. For example they would need to put their own kid in there.

oed commented 4 years ago

@wighawag While we could use path like that I would strongly advise against it since it would incentivize apps to silo data around their origins. Where as if you just use a path unrelated to origin this would make it easier to share data across apps.

I'm saying this mainly because I believe data should always be independent of the app that is bee used to display the data.

wighawag commented 4 years ago

@oed I agree that we should not silo data. But here the proposal is to remove the need for approval for the default case. This is better for the uers and that's why I think it should be that way. No reason to request a confirmation when the application that request decryption was the one encrypting it. Other application can alwasy request user to approve them for that origin. not big deal

oed commented 4 years ago

@wighawag i don't think the UX of approving both access to the account and a path is worse than just the account. It also makes it clear for the user what's going on. Origins also doesn't make sense for mobile apps.

wighawag commented 4 years ago

@oed I personally think it does make it worse, It could also lead to authorization fatigue

Re mobile app, this is not true. application has also some unique identifier. And for case where getting a unique identifier is not possible, the permission request would show up. We should not sacrifice one use case because it is not possible in all scenario.

I should precise though that this not for all use case. You would obviously not use an ipfs hash as path for data that you expect to be globally shared like name, profile picture, etc

This is mostly for specific data that would be a pain to request authentication for.

But maybe, a better alternative is to request authentication at the time of encryption (even if is is technically unnecessary) so a user is not surprised to have to accept an application after already interacting with it.

But I guess the application could simple call did_authenticate before hand and there would be no issue.

My aim is to remove all unnecessary confirmation, as this is a real pain from the user perspective.

wighawag commented 4 years ago

Actually if did_authenticate replace eth_requestAccount as @pedrouid mentioned, then this get reduced to one confirmation.

And this is I guess what you @oed were referring to with UX of approving both access to the account and a path

PaulLeCam commented 4 years ago

I agree it would be nice to prevent authorization fatigue. I think there are 2 main cases for calling did_authenticate:

  1. The app needs to access the user account and/or specific data, identified by the paths in order to provide its basic functionality, and prompts for the user consent when starting the app, similar to a login prompt.
  2. A user-initiated action requires additional authorization(s).

I think beyond the paths, it would be useful to add more granular permissions the user could have control over:

So rather than having a paths field in did_authenticate, we could have a grants array with the following shape:

type Grant = {
  path: string
  access: {
    create?: boolean
    read?: boolean
    update?: boolean
    delete?: boolean
  }
  duration?: 'session' | 'permanent'
}

An example "login" prompt could be something like:

{
  did: "...",
  grants: [
    { path: "/profiles", access: { read: true }, duration: "permanent" },
    { path: "/media/pictures/albums/<id>", access: { read: true, update: true }, duration: "permanent" }
  ]
}

Then a subsequent grant to edit profile for the session duration could be:

{
  did: "...",
  grants: [
    { path: "/profiles/basic", access: { update: true }, duration: "session" }
  ]
}

A one-off "add album" prompt could be:

{
  did: "...",
  grants: [
    { path: "/media/pictures/albums", access: { create: true } }
  ]
}

This way it wouldn't be an "all or nothing" choice for the user, but rather a more similar experience to what mobile OS are already providing to some extend.

oed commented 4 years ago

@PaulLeCam are you implying that did_createJWs also relies on path somehow? How do you imagine that working?

PaulLeCam commented 4 years ago

I don't know enough about DID to have a good idea of how it should work, but I'd imagine if the JWS identifies a known resource, the user agent could check the user grants?

OR13 commented 4 years ago

I'm struggling to understand why we have moved from JOSE APIs for DIDs to ABAC... I assume it's because there is no permissions model for accessing those APIs? Last time I used JSON-RPC it was game over if you accidentally exposed it to the internet... what changed that we need a permissions model?

PaulLeCam commented 4 years ago

Yes sorry that's probably out of scope for this EIP, should be another discussion.

oed commented 4 years ago

I suggest that for simplicity and ease of implementation we reduce this EIP to only include JOSE related method and remove the COSE related ones. These can be added as an additional EIP at some later point.

I will follow up in the next few days with a full list of modifications to this EIP based on the current feedback, and then follow up with a new PR that modifies the EIP.

wilwade commented 4 years ago

@oed Thanks for your work on this. I'm confused about a few of the pieces and have concerns which might be just due to my own confusion.

  1. How does the wallet know which did to return with multiple eth did standards?
  2. How does the wallet derive and store private keys? One of the nice things about #1098 was that it derived the encryption keys from the ethereum key. Thus if you had a backup of your ethereum keys (such as a BIP-39 Mnemonic code), you also had a backup of your encryption keys.
  3. How does one retrieve the data from the wallet needed to publish the did information? For example the public key and associated algorithm type?

My largest concern is portability. It looks to me like so much of the implementation is left up to the individual wallets that it will be difficult to port between wallets even if they both implement this EIP. Could you explain some about how you see backing up and porting data working?

oed commented 4 years ago

Great questions @wilwade!

  1. As you observed it's really up to the wallet to choose which DID method to use. Different ones might have different trade offs and advantages for different use cases. The goal of this EIP is not to force the use of a specific DID method. Also note that wallets that do not support ethereum could in theory implement the same did_* methods described here and be compatible.
  2. Seems like this would always be specific to a particular DID method. I would recommend that another EIP is created to do this for a particular DID method (e.g. did:ethr.
  3. Once you got the DID into your application you can use a DID Resolver to get the DID Document from the DID identifier string. The DID Document contains public key information needed for verifying signatures and doing key exchange. See the DID Core spec for more info.

I think leaving the implementation up to wallets is a key aspect of this EIP, since we want to support different types of DID methods. It would however be a really good idea to standardize key management around particular DID methods!

oed commented 3 years ago

List of updates to be added to the EIP soon:

  1. Add a challenge to the did_authenticate method. The request should include a nonce. The response must now include a signed JWS that includes the nonce and optionally aud.
  2. Change the did param of did_createJWS to kid which now takes an array of DID-uris
  3. Change the response serialization to be JSON based JOSE
  4. Remove all COSE related methods

Please let me know if any of the above doesn't make sense of if I'm missing something. Will be making the updates to the EIP shortly.

kdenhartog commented 3 years ago
  1. Add a challenge to the ´did_authenticatemethod. The request should include anonce. The response must now include a signed JWS that includes the nonceand optionallyaud`.

Are you thinking that the JWS will essentially be a signed JWT by following the claims format of the payload in JWTs?

oed commented 3 years ago

@kdenhartog It could be. I don't really have a preference and would opt for simplicity. Do you have any suggestion of what would be optimal?

I guess just creating a JWT compatible with did-jwt could make sense?

kdenhartog commented 3 years ago

I guess it depends on what the intent of the architecture is meant to be more of a messaging system then I'd lean towards the JWM stuff we've been working on. This comes with the advantage of getting closer alignment to the DIDCommV2 work as well.

oed commented 3 years ago

Interesting @kdenhartog what would the payload and header look like if we would use JWM? Would also be interested in input from @awoie here!

oed commented 3 years ago

Something that came up as I've been looking closer at JWE encryption is that the spec never mentions how to do padding of the cleartext before doing the encryption. Is there a recommended way of doing this or is it simply left to the application layer?

Perhaps you have some insights @kdenhartog @OR13 @awoie @selfissued ?

OR13 commented 3 years ago

https://tools.ietf.org/html/rfc7516#section-11.5

https://github.com/panva/jose/blob/1876669a192e0c5d6b8c29a7408a8a8128d0b8b1/lib/jwe/decrypt.js

https://tools.ietf.org/html/rfc3218

oed commented 3 years ago

Thanks @OR13, but I can't find anything on cleartext padding anywhere in there.

OR13 commented 3 years ago

https://crypto.stackexchange.com/questions/40731/minimum-plaintext-length-for-aes-gcm

@oed I guess it probably depends on the JWE algorithm, for example https://github.com/StableLib/stablelib/blob/master/packages/aes-kw/aes-kw.test.ts

https://github.com/panva/jose/blob/1876669a192e0c5d6b8c29a7408a8a8128d0b8b1/test/jwe/sanity.test.js

If you are implementing your own JWE, best to start with conformance tests against another library, and a set of test vectors committed to source control (that you pulled / generated from their implementation if possible).

oed commented 3 years ago

Thanks, I did actually implement JWE here: https://github.com/decentralized-identity/did-jwt/pull/132 using xchacha20poly1305 and xC20PKW with test vectors generated by the panva/jose library. However it seems like that does not pad the cleartext in any way.

I observed both the panva/jose library as well as the digitalbazaar/minimal-cipher library and could not see that the cleartext gets padded anywhere. The reason I ended up with doing a new implemetation was because:

OR13 commented 3 years ago

ECDH-ES+A256KW works with keys other than x25519... I added support for the NIST Curves, and could add support for secp256k1.

https://github.com/transmute-industries/did-key.js/blob/master/packages/did-key-web-crypto/src/__fixtures__/did-key-cipher-jwe.json

I suppose you are right that this combination of algorithms is a bit complex, but.... it works 'out of the box' with many different key types: https://github.com/w3c-ccg/lds-jws2020/search?q=ECDH-ES%2BA256KW

in general, "new crypto" is "poorly supported" :)

I think the important part is supporting 1 older stable option, and 1 new (believed to be safer / faster) option. (stole this line from manu).

As the suite author those choices are up to you.

On my list of todos is to add secp256k1 support for producing JWE or type ECDH-ES+A256KW... that use xchacha20poly1305.... if thats a thing you are also interested in doing thats great.

if you plan to use something else, I would love to hear why...

This post frequently gets raised: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid

everyone has their own favorite cryptos to use, the important part is to make it clear which standards you support in your library and beware that not supporting old / new crypto, might lead folks to not use your tooling / fork it to add backwards / forwards compatibility.

ping @msporny @dlongley :)