Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions jose/jwe.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import binascii
import hmac
import json
import zlib
from collections.abc import Mapping
Expand Down Expand Up @@ -237,17 +238,16 @@ def _decrypt_and_auth(cek_bytes, enc, cipher_text, iv, aad, auth_tag):
if enc in ALGORITHMS.HMAC_AUTH_TAG:
encryption_key, mac_key, key_len = _get_encryption_key_mac_key_and_key_length_from_cek(cek_bytes, enc)
auth_tag_check = _auth_tag(cipher_text, iv, aad, mac_key, key_len)
# Validate the tag before decrypting so that a forged ciphertext is
# rejected without ever being decrypted or unpadded.
if not hmac.compare_digest(auth_tag, auth_tag_check):
raise JWEError("Invalid JWE Auth Tag")
elif enc in ALGORITHMS.GCM:
encryption_key = jwk.construct(cek_bytes, enc)
auth_tag_check = auth_tag # GCM check auth on decrypt
encryption_key = jwk.construct(cek_bytes, enc) # GCM check auth on decrypt
else:
raise NotImplementedError(f"enc {enc} is not implemented!")

plaintext = encryption_key.decrypt(cipher_text, iv, aad, auth_tag)
if auth_tag != auth_tag_check:
raise JWEError("Invalid JWE Auth Tag")

return plaintext
return encryption_key.decrypt(cipher_text, iv, aad, auth_tag)


def _get_encryption_key_mac_key_and_key_length_from_cek(cek_bytes, enc):
Expand Down
21 changes: 20 additions & 1 deletion tests/test_jwe.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from jose.constants import ALGORITHMS, ZIPS
from jose.exceptions import JWEError, JWEParseError
from jose.jwk import AESKey, RSAKey
from jose.utils import base64url_decode
from jose.utils import base64url_decode, base64url_encode

backends = []
try:
Expand Down Expand Up @@ -336,6 +336,25 @@ def test_decrypt_oct_256_key_wrap(self, jwe_package):
actual = jwe.decrypt(jwe_package, key)
assert actual == b"Live long and prosper."

@pytest.mark.parametrize(
"enc, key",
(
(ALGORITHMS.A128CBC_HS256, OCT_256_BIT_KEY),
(ALGORITHMS.A192CBC_HS384, OCT_384_BIT_KEY),
(ALGORITHMS.A256CBC_HS512, OCT_512_BIT_KEY),
),
)
def test_tampered_cipher_text_is_auth_tag_error(self, enc, key):
encrypted = jwe.encrypt(b"Live long and prosper.", key, enc, ALGORITHMS.DIR)
header, encrypted_key, iv, cipher_text, auth_tag = encrypted.split(b".")
tampered = bytearray(base64url_decode(cipher_text))
tampered[-1] ^= 0x01
cipher_text = base64url_encode(bytes(tampered))
encrypted = b".".join((header, encrypted_key, iv, cipher_text, auth_tag))
with pytest.raises(JWEError) as excinfo:
jwe.decrypt(encrypted, key)
assert str(excinfo.value) == "Invalid JWE Auth Tag"

def test_invalid_jwe_is_parse_error(self):
with pytest.raises(JWEParseError):
jwe.decrypt("invalid", "key")
Expand Down