JWT encrypting payload in python? (JWE)

Question:

According to RFC 7516 it should be possible to encrypt the payload/claim, called JWE.

Are there any python libraries out there that support that?

I’ve checked PyJWT, python-jose and jwcrypto but they all just have examples for signing with HS256 (JWS).

Sorry if this is totally obvious, but when it comes to things involving crypto I’m extra cautious.

Asked By: Johnny

||

Answers:

Both Jose and jwcrypto libraries can do JWE.

For jose:

claims = {
'iss': 'http://www.example.com',
'sub': 42,
}
pubKey = {'k':
           '-----BEGIN PUBLIC KEY-----n
-----END PUBLIC KEY-----'
    }
# decrypt on the other end using the private key
privKey = {'k': 
    '-----BEGIN RSA PRIVATE KEY-----n'+
'-----END RSA PRIVATE KEY-----'
}

encJwt = jose.encrypt(claims, pubKey)
serJwt = jose.serialize_compact(encJwt)
decJwt = jose.decrypt(jose.deserialize_compact(serJwt), privKey)

For jwcrypto:

# algorithm to use
eprot = {'alg': "RSA-OAEP", 'enc': "A128CBC-HS256"}
stringPayload = u'attack at dawn'
E = jwe.JWE(stringPayload, json_encode(eprot))
E.add_recipient(pubKey)
encrypted_token = E.serialize(compact=True)
E = jwe.JWE()
E.deserialize(encrypted_token, key=privKey)
decrypted_payload = E.payload
Answered By: Yifan Wu

https://jwcrypto.readthedocs.io/en/latest/jwk.html#examples

from jwcrypto import jwk
_k = jwk.JWK.generate(kty='RSA', size=2048)
_text = _k.export()

import json
# loading the key back
_import_key_dict = json.loads(_text)
key = jwk.JWK(**json.loads(_import_key_dict))

Answered By: Meng Wee Tan

I can add a new library to the above suggested libraries, named jwskate, as initials of "JSON Web Signing, Keys, Algorithms, Tokens, and Encryption". Disclaimer: I am the author of that lib. I wrote it because I was not satisfied with the APIs from the previous libs which are not Pythonic enough for my tastes.

Here is an usage example to encode/decode a JWE, in this particular case using ECDH-ES+A256KW and A128CBC-HS256, but obviously you can use any supported key management and encryption algorithm:

from jwskate import JweCompact, Jwk

plaintext = b"this is an example plaintext"

# I'll use this specific Elliptic Curve private key:
key = Jwk(
    {'kid': '8-nLgBsa-vXI_geoGt061_ZiVZ8BB-hYBDSoOQj9QgI',
     'alg': 'ECDH-ES+A256KW',
     'crv': 'P-256',
     'd': '39QMopTVL1u267FOx4ayvsueDU317vHaq_z-PU_NioA',
     'kty': 'EC',
     'x': 'f_VRZlIk1Qd2eNGFVas9sNXx9wd43L8VymknAyP5Ntk',
     'y': 'NmsfCs5VVOk6FEE31aaN9jB8rlfz1MWolBC3af_8DGs'}
)


# alternatively, you can generate one like this:
random_key = Jwk.generate_for_alg("ECDH-ES+A256KW").with_kid_thumbprint()

# sign your JWE
jwe = JweCompact.encrypt(plaintext, jwk=key.public_jwk(), enc="A128CBC-HS256")
print(jwe)
# it will look like: 
# eyJlcGsiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiItVnNfYkdSNTdUUVY4MHNnUENwcWZhVjNmWXR4dWdTWmJRM1FLeTJEVDdNIiwieSI6IjBtc0pZSUFfMC1OY2lfM0plOWZLSml3RU1ZdGRBaE9kZDZhdkp5THd0dzQifSwiYWxnIjoiRUNESC1FUytBMjU2S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiOC1uTGdCc2EtdlhJX2dlb0d0MDYxX1ppVlo4QkItaFlCRFNvT1FqOVFnSSJ9.nnOEhmdonA19LRvyKSrL7f8aEb2vVwE7EU-zO91fyTUls4otMVppYg.h8h7Mxz4irvckPnknsnM0g.sRQJJq-RmiF7GeqvL8EpWTstS-daLbfgGnOPybWeOj8.z3heCfTiI0cjw8GaV0qcHw


# as recipient, you can decrypt your JWE like this:
jwe = JweCompact("""eyJlcGsiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJkSllwMHNTZUVhMnhiMkc4M2Jnam
1VNnp4OEFxTkZRVmlJclJXUnlJYURzIiwieSI6InJXcEZ0OENESGNkQXFoMVR2eG9BZTFCT3FfZ2I3RzJya0hVd0hhNldfV0kif
SwiYWxnIjoiRUNESC1FUytBMjU2S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiOC1uTGdCc2EtdlhJX2dlb0d0MDYx
X1ppVlo4QkItaFlCRFNvT1FqOVFnSSJ9.Nt89wpmYDZmbmjQCEZnZOygTOP5x2s7trvzLFehw1I_lMzTU-qlrcg.SQgJPG_WNUn
F13XnCJMAtw.wWwu_VUG7LPbsnWFTv-rAyiG84RW4tszR2fQ-AQaLBI.Onf3K4MSKhXaUrS8NpMDIA""")
assert jwe.decrypt(key) == plaintext
Answered By: Guillaume
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.