我正在使用jose
进行python jwe加密。
这是示例中的代码
import jose
from time import time
from Crypto.PublicKey import RSA
key = RSA.generate(2048)
claims = {'name': 'Jack'}
pub_jwk = {'k': key.publickey().exportKey('PEM')}
jwe = jose.encrypt(claims, pub_jwk)
jwt = jose.serialize_compact(jwe)
此处jwt的值为binary string
b'eyJlbmMiOiAiQTEyOENCQy1IUzI1NiIsICJhbGciOiAiUlNBLU9BRVAiLCAiX192IjogMn0.N1RFIEaRIGxCgSkT8HhQI4bO66XOL2RVfn4tMu8BBfGBO79AFKzHUYIRuVqpBX9YcUrsn66n3ccH5O2HO-CuCEPZ6EBM47IBUW1NAdFnm4uc3_X3EAngGTe2hnkLp0RzByYUcaLp2bMn7TWptRmvDGrADaI3uliZCV_ahLeWWFySFjIm_LaLBUzH1okZ-uPqvKQRXDEsdmBSTH5KlsQZHOdRa6uZz_iILmZY6Pp-9XtOSldTLiGasIA_9DNfljP5UtImOhAax_piA7hHeacGAtBNZJVZCWZZajLI6HKz5hVs4aZy7I2EIK6ogL0ubBNMeCQ0dZ70SWjvBTcTbtV2jw.65XaQ1rCSIn25Gc73CJe0g.oo81kAasMwPTISH5XEnnY5Mym3PPXMVs-FtYwgboHUE.5TR5Au7A7JYU7x0iYoPhGQ'
当我使用相同的jwt
值解密时,会得到准确的结果。
enc = jose.decrypt(jose.deserialize_compact(jwt), priv_jwk)
在这里,当我尝试使json
的加密值
data = {'jwt': jwt}
json.dumps(data)
它给我错误Object of type 'bytes' is not JSON serializable
我可以像这样对加密进行解码:
jwt = jose.serialize_compact(jwe)
,但是使用此加密值解密将引发错误。我不想在解密过程中对jwt
进行编码。
无论如何,在加密时我可以得到string
而不是byte
,以便将其转储到JSON。
答案 0 :(得分:3)
首先,Demonware / JOSE项目最初是为Python 2编写的,您大概使用的是Python 3 branch。有unresolved issues with the implementation,对我来说,软件包作者实际上并不十分了解这个问题。 JWT令牌在其紧凑的序列化中只是一系列由.
字符组成的URL安全的Base64字符串。
无论何时加密或签名新令牌,都必须将字节解码为字符串(只需将字节值解码为ASCII)。验证或解密时,您需要再次将字符串编码为字节。
例如要将jwt
值编码为JSON对象,您需要解码:
data = {'jwt': jwt.decode('ascii')}
JavaScript Web令牌(JWT)的全部要与另一方交换为文本。通过声明该方法返回字符串,库化合物变得重要起来。
您可以使用默认的utf-8
编解码器来缩短此时间,因为ASCII是UTF-8的子集:
data = {'jwt': jwt.decode()}
相反,您将不得不再次将紧凑型字符串编码为字节:
data = json.loads(json_document)
jose.decrypt(jose.deserialize_compact(data['jwt'].encode()), priv_jwk)
但是您基本上使用的是过时的软件。 Demonware/jose project已有3年没有更新了。它还依赖于过时的,未维护的pycrypto软件包。您不想使用。
相反,请看一下Authlib或JWCrypto,这两个被主动维护的模块,并使用cryptography
project处理棘手的加密原语(还有pyjwt
和python-jose
,但这些项目(目前)还不支持JWE加密,仅支持JWS签名令牌。
其中,Authlib提供了迄今为止最干净,最清晰的API。例如。使用Demonware / JOSE选择的默认加密和签名算法,既可以生成公钥/私钥对,又可以使用Authlib创建加密令牌,您可以这样做:
from authlib.jose import jwt
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
# generate a private key with corresponding public key, then
# export the keys as a PEM serializations.
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
private_key_pem = private_key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption()
)
public_key = private_key.public_key()
public_key_pem = public_key.public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo
)
# create an encrypted token (JWT using JWE)
claims = {'name': 'Jack'}
header = {'enc': 'A128CBC-HS256', 'alg': 'RSA-OAEP'}
token = jwt.encode(header, claims, public_key_pem).decode()
# decrypt the token again
claims_from_token = jwt.decode(token.encode(), private_key_pem)
请注意,Authlib也会在此处返回bytes
值,因此,如果您想进一步将其嵌入JSON并将令牌数据从JSON有效负载传递回{,则也必须对此进行解码和编码。 {1}}方法。
通过JWCrypto使用相同的公钥和私钥序列化:
jwt.decode()
请注意,该库在序列化时不会返回字符串,但是您必须手动对声明进行JSON解码。该API还将序列化和反序列化混合到一个类中,从而创建了一个非常混乱的参数,方法和属性组合。