owned this note
owned this note
Published
Linked with GitHub
# DIDComm: ECDH-ES + Repudiable Authentication
In essence, this method uses authenticated encryption to bind the message payload to the JWE envelope and authenticate the sender after the message has been decrypted.
While the inner message could be wrapped in a JWS in order to authenticate the sender, that would be considered non-repudiable.
ECDH-1PU allows for the sender key to be authenticated during the message decryption, but remains as a draft standard, and potentially exposes the sender's key identifier.
## Encryption Steps:
1. Start with the message to be sent, for example the following DIDComm v2 message. Augment the message with a specific sender's key as `from_key`:
```json
{
"id": "518be002-de8e-456e-b3d5-8fe472477a86",
"type": "https://didcomm.org/trust_ping/1.0",
"from": "did:example:alice",
// 👇 new addition: corresponds to skid
"from_key": "#keyAgreement1",
"to": ["did:example:bob"],
"body": {
"response_requested": true
}
}
```
2. Convert the message to octets for input to the JWE wrapper.
3. For each recipient, perform a DH key exchange between the sender's private key and recipient's public key producing the shared key Z. Perform a ConcatKDF as per ECDH-ES, setting `apu` and `apv` to the sender and recipient key identifiers (`from_key` and `kid` respectively), producing a key in the same format as the intended CEK (AES256GCM / XC20P). Encrypt an empty (zero byte) message using the key, using the message plaintext as the additional authenticated data, to produce a sender authentication tag.
4. When preparing the message, add the authentication tag for each recipient to the `header` attributes, encoded as unpadded base64-URL for example:
```json
{"kid":"did:example:bob#key1","stag":"<tag>"}
```
## Decryption Steps:
1. Decrypt the JWE as per normal.
2. If `from_key` is not present in the message or `stag` is not included in the recipient header, consider the message unauthenticated (skip to end).
3. Perform a DH key exchange between the recipient's private key and the sender's public key and derive the sender authentication key via ConcatKDF. Encrypt a blank message using the derived key, using the message plaintext as additional authenticated data, to produce the sender authentication tag. Compare the result to the `stag` value (use a constant time comparison). If it matches, consider the message authenticated.
## Benefits
- Message decryption can proceed without resolving the sender key (potentially involving DID resolution), and can be performed by any ECDH-ES library. This allows certain messages to be discarded as invalid or unsupported without proceeding to DID resolution. It could decrease the impact of spam or DDoS messages.
- The same wrapper format is used for authenticated and anonymous messages, instead of switching between ECDH-ES and ECDH-1PU.
- May be slightly more efficient than ECDH-1PU with an encrypted `skid`.
## Caveats
- This method involves an additional KDF and encryption/decryption operation over ECDH-1PU with an unencrypted `skid` (but uses the same key exchanges).
- The key derivation used is essentially the same as in ECDH-ES, but libraries may currently restrict this operation to an ephemeral keypair for security, or only expose higher-level operations.
- The sender authentication tag is not in a protected header as it is recipient-specific. It could be promoted in the case of a single recipient.
- The `stag` attribute name is used here illustratively. Any eventual choice may need to be registered with IANA, made collision resistant, or recognized as a private header.
- The same message with the same sender key and same recipient key will produce matching sender tags. This may be undesirable, but in general messages should include a unique identifier.