Aries RFC 0334: JWE envelope 1.0¶
- Authors: Baha A. Shaaban (SecureKey Technologies Inc.), Troy Ronda (SecureKey Technologies Inc.)
- Status: STALLED
- Since: 2024-04-03
- Status Note: No implementations have been created.
- Supersedes:
- Start Date: 2019-11-01
- Tags: feature
Summary¶
Agents need to use a common set of algorithms when exchanging and persisting data. This RFC supplies a cipher suite and examples for DIDComm envelopes.
Motivation¶
The goal of this RFC is to define cipher suites for Anoncrypt and Authcrypt such that we can achieve better compatibility with JOSE. We also aim to supply both a compliant suite and a constrained device suite. The compliant suite is suitable for implementations that contain AES hardware acceleration or desire to use NIST / FIPS algorithms (where possible).
Encryption Algorithms¶
The next two sub-sections describe the encryption algorithms that must be supported. On devices with AES hardware acceleration or requiring compliance, AES GCM is the recommended algorithm. Otherwise, XChacha20Poly1305 should be used.
Content Encryption Algorithms¶
The following table defines the supported content encryption algorithms for DIDComm JWE envelopes:
Content Encryption | Encryption Algorithm identifier | Authcrypt/Anoncrypt | Reference |
---|---|---|---|
A256CBC-HS512 (512 bit) | AES_256_CBC_HMAC_SHA_512 | Authcrypt/Anoncrypt | ECDH-1PU section 2.1 and RFC 7518 section 5.2.5 |
AES-GCM (256 bit) | A256GCM | Anoncrypt | RFC7518 section 5.1 and more specifically RFC7518 section 5.3 |
XChacha20Poly1305 | XC20P | Anoncrypt | xchacha draft 03 |
Key Encryption Algorithms¶
The following table defines the supported key wrapping encryption algorithms for DIDComm JWE envelopes:
Key Encryption | Encryption algorithm identifier | Anoncrypt/Authcrypt |
---|---|---|
ECDH-ES + AES key wrap | ECDH-ES+A256KW | Anoncrypt |
ECDH-1PU + AES key wrap | ECDH-1PU+A256KW | Authcrypt |
Curves support¶
The following curves are supported:
Curve Name | Curve identifier |
---|---|
X25519 (aka Curve25519) | X25519 (default) |
NIST P256 (aka SECG secp256r1 and ANSI X9.62 prime256v1, ref here) | P-256 |
NIST P384 (aka SECG secp384r1, ref here) | P-384 |
NIST P521 (aka SECG secp521r1, ref here) | P-521 |
Other curves are optional.
Security Consideration for Curves¶
As noted in the ECDH-1PU IETF draft security considerations section, all implementations must ensure the following:
When performing an ECDH key agreement between a static private key
and any untrusted public key, care should be taken to ensure that the
public key is a valid point on the same curve as the private key.
Failure to do so may result in compromise of the static private key.
For the NIST curves P-256, P-384, and P-521, appropriate validation
routines are given in Section 5.6.2.3.3 of [NIST.800-56A]. For the
curves used by X25519 and X448, consult the security considerations
of [RFC7748].
JWE Examples¶
AES GCM encryption and key wrapping examples are found in Appendix C of the JSON Web Algorithm specs.
The Proposed JWE Formats below lists a combination of content encryption and key wrapping algorithms formats.
Drawbacks¶
- All new algorithm identifiers should be registered at IANA.
- XC20P
- ECDH-1PU+A256KW (already in IETF draft)
- ECDH-ES+XC20PKW
- ECDH-1PU+XC20PKW
- Security Considerations of ECDH-1PU (Section 4)
- X25519 is not yet part of SP 800-56A. See NIST post for more information.
Rationale and alternatives¶
Our approach for AuthCrypt compliance is to use the NIST approved One-Pass Unified Model for ECDH
scheme described in SP 800-56A Rev. 3. The JOSE version is defined as ECDH-1PU
in this IETF draft.
Aries agents currently use the envelope described in RFC0019. This envelope uses libsodium (NaCl) encryption/decryption, which is based on Salsa20Poly1305 algorithm.
Another prior effort towards enhancing JWE compliance is to use XChacha20Poly1305 encryption and ECDH-SS key wrapping mode. See Aries-RFCs issue-133 and Go JWE Authcrypt package for an implementation detail. As ECDH-SS is not specified by JOSE, a new recipient header field, spk
, was needed to contain the static encrypted public key of the sender. Additionally (X)Chacha20Poly1305 key wrapping is also not specified by JOSE. For these reasons, this option is mentioned here as reference only.
JWE formats¶
Anoncrypt using ECDH-ES key wrapping mode and XC20P content encryption¶
{
"protected": base64url({
"typ": "didcomm-envelope-enc",
"enc": "XC20P", // or "A256GCM"
}),
"recipients": [
{
"header": {
"kid": base64url(recipient KID), // e.g: base64url("urn:123") or base64url(jwk thumbprint as KID)
"alg": "ECDH-ES+A256KW",
"epk": { // defining X25519 key as an example JWK, but this can be EC key as well
"kty": "OKP",
"crv": "X25519",
"x": "-3bLMSHYDG3_LVNh-MJvoYs_a2sAEPr4jwFfFjTrmUo" // sender's ephemeral public key value raw (no padding) base64url encoded
},
"apu": base64url(epk.x value above),
"apv": base64url(recipients[*].header.kid)
},
"encrypted_key": "Sls6zrMW335GJsJe0gJU4x1HYC4TRBZS1kTS1GATEHfH_xGpNbrYLg"
}
],
"aad": "base64url(sha256(concat('.',sort([recipients[0].kid, ..., recipients[n].kid])))))",
"iv": "K0PfgxVxLiW0Dslx",
"ciphertext": "Sg",
"tag": "PP31yGbQGBz9zgq9kAxhCA"
}
typ
header field is the DIDComm Transports value as mentioned in RFC-0025. This RFC states the prefix application/
but according to IANA Media types the prefix is implied therefore not needed here.
Anoncrypt using ECDH-ES key wrapping mode and A256GCM content encryption¶
{
"protected": base64url({
"typ": "didcomm-envelope-enc",
"enc": "A256GCM", // "XC20P"
}),
"recipients": [
{
"header": {
"kid": base64url(recipient KID),
"alg": "ECDH-ES+XC20PKW", // or "ECDH-ES+A256KW" with "epk" as EC key
"epk": {
"kty": "OKP",
"crv": "X25519",
"x": "aOH-76BRwkHf0nbGokaBsO6shW9McEs6jqVXaF0GNn4" // sender's ephemeral public key value raw (no padding) base64url encoded
},
"apu": base64url(epk.x value above),
"apv": base64url(recipients[*].header.kid)
},
"encrypted_key": "wXzKi-XXb6fj_KSY5BR5hTUsZIiAQKrxblTo3d50B1KIeFwBR98fzQ"
}
],
"aad": "base64url(sha256(concat('.',sort([recipients[0].kid, ..., recipients[n].kid])))))",
"iv": "9yjR8zvgeQDZFbIS",
"ciphertext": "EvIk_Rr6Nd-0PqQ1LGimSqbKyx_qZjGnmt6nBDdCWUcd15yp9GTeYqN_q_FfG7hsO8c",
"tag": "9wP3dtNyJERoR7FGBmyF-w"
}
In the above two examples, apu
is the encoded ephemeral key used to encrypt the cek stored in encrypted_key
and apv
is the encoded key id of the static public key of the recipient. Both are raw (no padding) base64Url encoded.
kid
is the value of a key ID in a DID document that should be resolvable to fetch the raw public key used.
Authcrypt using ECDH-1PU key wrapping mode¶
{
"protected": base64url({
"typ": "didcomm-envelope-enc",
"enc":"A256CBC-HS512", // or one of: "A128CBC-HS256", "A192CBC-HS384"
"skid": base64url(sender KID),
"alg": "ECDH-1PU+A256KW", // or "ECDH-1PU+XC20P" with "epk" as X25519 key
"apu": base64url("skid" header value),
"apv": base64url(sha256(concat('.',sort([recipients[0].kid, ..., recipients[n].kid]))))),
"epk": {
"kty": "EC",
"crv": "P-256",
"x": "gfdM68LgZWhHwdVyMAPh1oWqV_NcYGR4k7Bjk8uBGx8",
"y": "Gwtgz-Bl_2BQYdh4f8rd7y85LE7fyfdnb0cWyYCrAb4"
}
}),
"recipients": [
{
"header": {
"kid": base64url(recipient KID)
},
"encrypted_key": "base64url(encrypted CEK)"
},
...
],
"aad": "base64url(sha256(concat('.',sort([recipients[0].kid, ..., recipients[n].kid])))))",
"iv": "base64url(content encryption IV)",
"ciphertext": "base64url(XC20P(DIDComm payload, base64Url(json($protected)+'.'+$aad), content encryption IV, CEK))"
"tag": "base64url(AEAD Authentication Tag)"
}
With the recipients headers representing an ephemeral key that can be used to derive the key to be used for AEAD decryption of the CEK following the ECDH-1PU encryption scheme.
The function XC20P
in the example above is defined as the XChahcha20Poly1035 cipher function. This can be replaced by the AES-CBC+HMAC_SHA family of cipher functions for authcrypt or AES-GCM cipher function for anoncrypt.
Concrete examples¶
See concrete anoncrypt and authcrypt examples
JWE detached mode nested envelopes¶
There are situations in DIDComm messaging where an envelope could be nested inside another envelope -- particularly RFC 46: Mediators and Relays. Normally nesting envelopes implies that the envelope payloads will incur additional encryption and encoding operations at each parent level in the nesting. This section describes a mechanism to extract the nested payloads outside the nesting structure to avoid these additional operations.
Detached mode¶
JWS defines detached mode where the payload can be removed. As stated in IETF RFC7515, this strategy has the following benefit:
Note that this method needs no support from JWS libraries, as applications can use this method by modifying the inputs and outputs of standard JWS libraries.
We will leverage a similar detached mode for JWE in the mechanism described below.
Mechanism¶
Sender:
- Creates the "final" JWE intended for the recipient (normal JWE operation).
- Extracts the ciphertext and replace with an empty string.
- Creates the nested envelopes around the "final" JWE (but with the empty string ciphertext).
- Sends the nested envelope (normal JWE) plus the ciphertext from the "final" JWE.
Mediator:
- Decrypt their layer (normal JWE operation). The detached ciphertext(s) are filtered out prior to invoking the JWE library (normal JWE structure).
- Remove the next detached ciphertext from the structure and insert back into the ciphertext field for the next nesting level.
Receiver:
- Decrypts the "final" JWE (normal JWE operation).
The detached ciphertext steps are repeated at each nesting level. In this case, an array of ciphertexts is sent along with the nested envelope.
This solution has the following characteristics:
- Only encrypts the payload once.
- JWE headers and metadata are included in the nested envelope's ciphertext.
- Needs no support from JWE libraries.
- Requires a serialization structure for transporting both the nesting JWE and the detached ciphertexts (only when there is a nested envelope). See below.
- Requires some minor additional logic prior to invoking the JWE library.
Serialization¶
The extracted ciphertext serialization format should have additional thought for both compact and JSON modes. As a starting point:
- Compact mode: Each extracted ciphertext is appended to the end of the serialized "final" JWE (using dot separation). These extracted cipher texts are ordered according to the nesting (from innermost to outermost).
- JSON mode: The extracted ciphertext are placed into a JSON array. These extracted cipher texts are ordered according to the nesting (from innermost to outermost). The array is appended to the "final" JWE object as the
detached_ciphertext
field.
For illustration, the following compact serialization represents nesting due to two mediators (the second mediator being closest to the Receiver).
First Mediator receives:
BASE64URL(UTF8(JWE Protected Header for First Mediator)) || '.' ||
BASE64URL(JWE Encrypted Key for First Mediator) || '.' ||
BASE64URL(JWE Initialization Vector for First Mediator) || '.' ||
BASE64URL(JWE Ciphertext for First Mediator) || '.' ||
BASE64URL(JWE Authentication Tag for First Mediator) || '.' ||
BASE64URL(JWE Ciphertext for Receiver) || '.' ||
BASE64URL(JWE Ciphertext for Second Mediator)
Second Mediator receives:
BASE64URL(UTF8(JWE Protected Header for Second Mediator)) || '.' ||
BASE64URL(JWE Encrypted Key for Second Mediator) || '.' ||
BASE64URL(JWE Initialization Vector for Second Mediator) || '.' ||
BASE64URL(JWE Ciphertext for Second Mediator) || '.' ||
BASE64URL(JWE Authentication Tag for Second Mediator) || '.' ||
BASE64URL(JWE Ciphertext for Receiver)
Finally, the Receiver has a normal JWE (as usual):
BASE64URL(UTF8(JWE Protected Header for Receiver)) || '.' ||
BASE64URL(JWE Encrypted Key for Receiver) || '.' ||
BASE64URL(JWE Initialization Vector for Receiver) || '.' ||
BASE64URL(JWE Ciphertext for Receiver) || '.' ||
BASE64URL(JWE Authentication Tag for Receiver)
This illustration extends the serialization shown in RFC 7516.
Prior art¶
- The JWE family of encryption methods.
- Aries RFC 0019-encryption-envelope suggested envelope formats will be superseded by this RFC.
- Aries RFC 0025-didcomm-transports for the content type used in the proposed envelopes.
- minimal-cipher implementation
- Aries-Framework-Go has an experimental (X)Chacha20Poly1305 Packer implementation based on Aries-RFCs issue-133
- IANA Media Types
- Public Key Authenticated Encryption for JOSE: ECDH-1PU
- NIST SP 800-56A Rev. 3 Recommendation for Pair-Wise Key-Establishment schemes Using Discrete Logarithm Cryptography
- Appendix A of IETF 4492 listing equivalent curve names.
Unresolved questions¶
- What fields should Key identifiers in ES and 1PU key wrapping modes use?
kid
vsid
(vsskid
introduced in ECDH-1PU IETF document) or any other combination of fields. There is a discussion about this here. -
Update: The answer to this question is to keep
kid
definition as per the JWE/JWS family of specification definitions and useskid
in the JWE protected header as defined in ECDH-1PU to represent a resolvable sender key id. -
What kind of keys to include in the JWE envelope?
Encryption
orsigning
keys? Currently, the existing Aries agents includesigning
(ED25519) keys for the sender and recipients and convert them to encryption (X25519) keys for encryption/decryption operations only. The drawback of this approach is the envelope transmitted by the agent contains signing public keys. There is a need to separate them fromencryption
keys. - Update:
The best way to separate the two keys is to use the DID document's KeyAgreement verification method in full description to store theencryption
key so that it can be sent in the JWE envelope independently of the signing (DID authentication) key.
Implementations¶
The following lists the implementations (if any) of this RFC. Please do a pull request to add your implementation. If the implementation is open source, include a link to the repo or to the implementation within the repo. Please be consistent in the "Name" field so that a mechanical processing of the RFCs can generate a list of all RFCs supported by an Aries implementation.
Name / Link | Implementation Notes |
---|---|
Note: Aries Framework - Go is almost done with a first draft implementation of this RFC.