latchset / jwcrypto

Implements JWK,JWS,JWE specifications using python-cryptography
GNU Lesser General Public License v3.0
439 stars 118 forks source link

Protected Header is still readable for JWE #317

Closed ds2286 closed 1 year ago

ds2286 commented 1 year ago

I currently am encrypting a JWS to create a JWE. I am receiving the format per the standard: { "ciphertext":"alphabet soup", "encrypted_key":"alphabet soup", "iv":"alphabet soup", "protected":"alphabet soup", "tag":"alphabet soup" }

But when I use base64.urlsafe_b64decode I am able to read the protected headers. I used this simple script:

import base64

jwe_dict = { "ciphertext":"alphabet soup", "encrypted_key":"alphabet soup", "iv":"alphabet soup", "protected":"alphabet soup", "tag":"alphabet soup" }

for key,val in jwe_dict.items(): try: print(base64.urlsafe_b64decode(val)) except Exception as e: print(e)

The output is: Incorrect padding Incorrect padding Incorrect padding b'{"alg":"the algorithm","enc":"the algorithm","kid":"test","typ":"JWE"}' Incorrect padding

The incorrect padding is expected with the encryption, but the protected headers should also be encrypted. In section 7.2.1 in rfc 7516:

7.2.1. General JWE JSON Serialization Syntax

The following members are defined for use in top-level JSON objects used for the fully general JWE JSON Serialization syntax:

protected The "protected" member MUST be present and contain the value BASE64URL(UTF8(JWE Protected Header)) when the JWE Protected Header value is non-empty; otherwise, it MUST be absent. These Header Parameter values are integrity protected.

unprotected The "unprotected" member MUST be present and contain the value JWE Shared Unprotected Header when the JWE Shared Unprotected Header value is non-empty; otherwise, it MUST be absent. This value is represented as an unencoded JSON object, rather than as a string. These Header Parameter values are not integrity protected.

To me, the protected headers should have their integrity protected and be encrypted. Then any headers that should remain publicly readable should go in the unprotected headers.

simo5 commented 1 year ago

The headers are used to provide the necessary information to the recipient to be able to decrypt the payload. If the headers where themselves encrypted you wouldn't be able to decrypt the JWE.

Integrity protection has a specific meaning in cryptography and means simply: the data cannot be altered without the recipient knowing it has been altered.

Integrity protection does not imply encryption, it may be achieved, via MAC, Signatures, or other AEAD ciphers in the case of encryption.

Keep in mind that JWCrypto has an extensive suite of tests based on the standard's test vectors, which include JWEs test vectors.

If your system can deal with JWEs in the absence of a header that tells them any information, you can simply strip the protected header or leave it empty. The headers are never part of the payload, therefore are never encrypted.

Generally in JWE the integrity protection of the protected header is achieved by using the protected header as input in calculating the Authentication Tag.

ds2286 commented 1 year ago

That makes a lot of sense. Thank you for clarifying that!