Search code examples
encryptionjwtaeshmacjwk

Why does encrypting a JWT with AES_128_CBC_HMAC_SHA_256 also change its "alg" header parameter?


I am creating symmetrically signed Tokens with HMAC + SHA-256. As expected the header looks like this:

{
  "alg": "HS256",
  "typ": "JWT"
}

But when I encrypt the token with the AES_128_CBC_HMAC_SHA_256, the header changed to this:

{
  "alg": "A128KW",
  "enc": "A128CBC-HS256",
  "typ": "JWT"
}

The "enc" parameter looks like expected, but why does the "alg" parameter change when encrypted?

From what I understand about encrypting JWTs:

  • The payload is signed (or symmetrically encrypted) and appended to the token;
  • payload + signature are encrypted with the algorithm specified in "enc" if applicable.

This does not appear to apply though. How would a potential recipient know that the decrypted token was signed with HMAC + SHA-256 now? Isn't signing and encrypting done in this manner? I also noted that the distinct "." separating the signature and the payload is still present in the encrypted token, which seems odd considering the whole content should be encrypted as one (excluding the header).

I am using Microsoft.IdentityModel to generate the tokens if that matters.


Solution

  • The "enc" parameter looks like expected, but why does the "alg" parameter change when encrypted?
    

    The header claim alg has different meanings when used in a JWS (signed token) and JWE (encrypted token).

    With JWS (extract from the RFC7515 section 4.1.1)

    The "alg" (algorithm) Header Parameter identifies the cryptographic algorithm used to secure the JWS.

    With JWE (extract from the RFC7516 section 4.1.1)

    This parameter has the same meaning, syntax, and processing rules as the "alg" Header Parameter defined in Section 4.1.1 of [JWS], except that the Header Parameter identifies the cryptographic algorithm used to encrypt or determine the value of the CEK.

    About you assumption

    From what I understand about encrypting JWTs:
    * The payload is signed (or symmetrically encrypted) and appended to the token;
    * payload + signature are encrypted with the algorithm specified in "enc" if applicable.
    

    This is not correct. With JWE, the payload is not digitally signed by the issuer. If you need both encryption and signature, you will have to issue a JWS (e.g. with {"alg":"HS256","typ":"JWT"}). This JWS will be encrypted (e.g. with {"alg": "A128KW","enc": "A128CBC-HS256","typ": "JWT"}

    I also noted that the distinct "." separating the signature and the payload is still present in the encrypted token
    

    THe difference between JWS and JWE is that the number of . is not the same:

    • 2 . for JWS
    • 4 . for JWE

    Disctinction between the 2 token types is detailed in the RFC7516 section 9