Closed AndreiCravtov closed 1 month ago
Stepping through the code, the culprit of the unexpected behavior seems to be _AesGcm.decrypt
in jwa.py
:
def decrypt(self, k, aad, iv, e, t):
""" Decrypt according to the selected encryption and hashing
functions.
:param k: Encryption key
:param aad: Additional Authenticated Data
:param iv: Initialization Vector
:param e: Ciphertext
:param t: Authentication Tag
Returns plaintext or raises an error
"""
cipher = Cipher(algorithms.AES(k), modes.GCM(iv, t),
backend=self.backend)
decryptor = cipher.decryptor()
decryptor.authenticate_additional_data(aad)
return decryptor.update(e) + decryptor.finalize()
When it returns, the calling block (which is JWE._unwrap_decrypt
in jwe.py
) receives the problematic "payload"
def _unwrap_decrypt(self, alg, enc, key, enckey, header,
aad, iv, ciphertext, tag):
cek = alg.unwrap(key, enc.wrap_key_size, enckey, header)
data = enc.decrypt(cek, aad, iv, ciphertext, tag)
self.decryptlog.append('Success')
self.cek = cek
return data
Here, data
is precisely the contents of jwe_compressed_str
except its a b"string"; if it doesn't actually decrypt anything it should surely at least raise an error?
So what you are saying is that decryption is returning the actual ciphertext instead of the expected plaintext ? It is not entirely clear to me what problem you are identifying, can you write a simple reproducer? (Create a JWE with a random key, then decrypt it) Can you post the unprotected header of your JWE? (Just base64 decode the token string until the first dot). I'd like to see what algorithms the JWE is specifying.
Sorry for wasting your time, there was no issue. I just saw:
eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIn0....
<- ciphertext
and
eyJhbGciOiJFUzI1NiJ9....
<- plaintext
and the eyJhbGciOiJ...
prefix in both short-circuited my brain
I'm trying to decrypt a JWE with a symmetric key, with
enc=A256GCM
andalg=A256KW
, following the documentation I get something like this:When I check
decryptlog
I see['Success']
so its failing silently for some reason, so I have no idea whats going on. The specific payload and keys are for server-side validation of Google Play Integrity verdict tokens, and I'm porting the decryption logic from Rust code (which works), so the cryptographic tokens themselves aren't incorrect. Somewhere along the way either I made a mistake with using this API or there is a bug.