13

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.

Community
  • 1
  • 1
Johnny
  • 133
  • 1
  • 2
  • 13

3 Answers3

15

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
Yifan Wu
  • 420
  • 5
  • 10
  • 1
    Can you/someone please add a thorough example where an existing RSA Key is imported to jwcrypto? I have been trying but keep getting errors. – kilokahn Sep 25 '17 at 21:24
  • 5
    The jose library does not support python 3. see https://github.com/Demonware/jose/pull/15 . Confusingly, another library called python-jose does not support JWE. – jnnnnn Dec 10 '19 at 05:22
  • 2
    @kilokahn three years later, but since I had the same question; you can use `key = jwcrypto.jwk.JWK.from_pem(pemfile.read())`, as documented here: https://jwcrypto.readthedocs.io/en/stable/jwk.html#examples – Jacob Davis-Hansson Mar 23 '20 at 19:09
0

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
Guillaume
  • 5,497
  • 3
  • 24
  • 42
-1

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))

  • 1
    You got your modules confused here; this is a demo of JWK key creation, and saving / loading. JWK is *not necessary to created and decrypt JWT encrypted tokens with JWE*. – Martijn Pieters Oct 25 '19 at 16:12