I ended up reading the code behind JSON serialization of JWE with multiple recipients here:
https://github.com/panva/jose/blob/main/docs/classes/jwe_general_encrypt.GeneralEncrypt.md I started by just recovering the same interface with hpke (including support for the aad in JWE, which I had destroyed / misused in my previous proposal). I ended with this: https://github.com/OR13/draft-jose-hpke-test-vectors/blob/main/src/json.ts You can now use JSON Serialization JWE with recipients that use RSA, ECDH-ES+A128KW (etc), and HPKE: { "protected": "eyJlbmMiOiJBMTI4R0NNIn0", "ciphertext": "bs-uID3cGBG9xdtV1ofV4W...wbfT7d7dKIs5PHFhB8MwSlje84Jw", "iv": "Pty7Rw1uMFhZIKGP", "aad": "8J-SgCBhYWQ", "recipients": [ { "encrypted_key": "zHuuu3N5b3fC1PjxXW5YKTk_Ff76CKIdX-HxL8R8UJf6jk7xwsO6Cs81kBx5-Xtp", "header": { "kid": "urn:ietf:params:oauth:jwk-thumbprint:sha-256:Lrl72_24U7qugLKAbpSYDlpxmMYa5WDOj5OXGCxszUg", "alg": "HPKE-Base-P256-SHA256-AES128GCM", "encapsulated_key": "BHLsqUMD3FdSCKKcaVvm7zjz2S9P_EN-rsf16Y4Kikt__12C9UoTeMkEtvMvSxdHiefCO9jc8KjX_Ef92e34wTo" } }, { "encrypted_key": "QI98Br0e4M-xkYp-xPOFZwaApvdby1oXrmXR96UGVBzqOtaYvJnvpw", "header": { "kid": "urn:ietf:params:oauth:jwk-thumbprint:sha-256:fEAWfRlLtq4cd6hJ3ndI7-IRCeczEN_VQRTjpN2lshQ", "alg": "ECDH-ES+A128KW", "epk": { "kty": "EC", "crv": "P-256", "x": "2ilu0GYnrMD18oUELaR1SFAPNw6TvrVZoo_4ScqsKPU", "y": "r4ex0vgKP1XLnUml3fsuw2RjApydYTt73_HqYAxlujI" } } } ] } I repeated the "alg" values in the recipient headers for readability, but they are technically not required I think. The top level header is { enc: A128GCM } and is input as the aad to the hpke seal and open operations... I also explored the hkdf binding, but for JWE like this, it does not seem to do anything useful, see: https://github.com/OR13/draft-jose-hpke-test-vectors/blob/main/src/ContentEncryption.ts#L27 I feel pretty embarrassed about the aad proposal from before, because JWE supports aad and so hpke jwe needs to preserve some aad interface in json. I think this means that the aad in seal and open are the only places you can reasonably bind the protected header to the content encryption key. So the main difference between the compact and json serializations boils down to this: // compact const hpkeSealAad = new TextEncoder().encode(protectedHeader) const ciphertext = await sender.seal(plaintext, hpkeSealAad) ... const hpkeOpenAad = new TextEncoder().encode(protectedHeader) const plaintext = await recipient.open(ciphertext, hpkeOpenAad) // json const hpkeSealAad = new TextEncoder().encode(protectedHeader) const encrypted_key = await sender.seal(contentEncryptionKey, hpkeSealAad) ... const hpkeOpenAad = new TextEncoder().encode(protectedHeader) const contentEncryptionKey = await recipient.open(encrypted_key, hpkeOpenAad) It seems likely this mixed mode experiment is breaking some rules... when decrypting ECDH-ES+A128KW, we don't have a way to know the aead. ... so I think that part is still vulnerable to the cross mode attack... to fix that, we would need to bind the shared secret based content encryption key, to a single algorithm... I think that implies a new "alg" value... something like "ECDH-ES+A128KW+A128GCM" ... you can see where that could fit into the existing concatKDF structure here: https://github.com/OR13/draft-jose-hpke-test-vectors/blob/main/src/mixed.ts#L70 Thats probably a separate issue for consideration, not something to hold up JOSE HPKE for... possibly for https://datatracker.ietf.org/doc/draft-jones-jose-fully-specified-algorithms/ to address. OS On Thu, Jan 25, 2024 at 1:00 PM Ilari Liusvaara <[email protected]> wrote: > On Thu, Jan 25, 2024 at 07:26:21AM -0600, Orie Steele wrote: > > I don't understand your comment about the space in "some string" > preventing > > cross mode attacks, and it's not clear which header you are placing the > enc > > (encryption algorithm) value in, but I assume it is the top level header. > > The standard JWE authenticated data construction can never generate > output with a space character (only alphanumerics, dash, underscore and > full stop). > > Therefore if one mode uses standard JWE authenticated data construction, > and another mode uses aad that has space in it, then it is not possible > for attacker to transplant ciphertexts between the modes. > > And yes, if "enc" is present, it goes to top-level headers, just > like in JWE currently. > > (Comparing to COSE-HPKE: Such transplanting is blocked by the > enc_structure context.) > > > > If that's true, that header is marked protected, but your proposal > doesn't > > protect it. > > JWE is designed to be able to withstand unprotected "enc". In JSON > serializations, it is even allowed to put "enc" in unprotected headers! > > The attack presented in LAMPS slides does not work against JWE > (because "enc" must be AEAD). > > However, this does not mean one does not need to be careful with > changes, lest one enables such attacks (happened with COSE! Oops.) > > > > If you just use that protected header value as the aad, then it will have > > protection. > > In Key Encryption? If so, that does not work: > > - Causes severe problems with implementations. > - Allows attacker to transplant ciphertexts between modes. > > > > It seems weird to concatenate strings when you have a json object that > can > > clearly identify them. > > I don't think that json object is intended to be used that way (JWE > section 5.1, step 4). > > > > > -Ilari > > _______________________________________________ > jose mailing list > [email protected] > https://www.ietf.org/mailman/listinfo/jose > -- ORIE STEELE Chief Technology Officer www.transmute.industries <https://transmute.industries>
_______________________________________________ jose mailing list [email protected] https://www.ietf.org/mailman/listinfo/jose
