Шифрование Jose возвращает двоичную строку, но расшифровка с декодированной строкой дает ошибку в Python - PullRequest
1 голос
/ 24 октября 2019

Я использую 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.

1 Ответ

3 голосов
/ 24 октября 2019

Прежде всего, проект Demonware / JOSE изначально был написан для Python 2, вы, вероятно, используете ветку Python 3 . Есть нерешенные проблемы с реализацией , что, как мне кажется, говорит об авторе пакета, который не очень хорошо понимает проблему. Токены JWT в своей компактной сериализации представляют собой просто серию безопасных для URL строк Base64, соединенных с . символами.

Когда вы шифруете или подписываете новый токен, вы должны декодировать байты в строки (просто декодируйтезначение в байтах как ASCII). При проверке или дешифровании вам необходимо снова кодировать строки в байты.

Например, для кодирования значения jwt в объекте JSON вам необходимо декодировать:

data = {'jwt': jwt.decode('ascii')}

Весь смысл веб-токена Javascript (JWT) должен передаваться другой стороне в виде текста. Библиотека соединений имеет значение, утверждая, что метод возвращает строку.

Вы можете сократить это использование кодека utf-8 по умолчанию, поскольку ASCII является подмножеством UTF-8:

data = {'jwt': jwt.decode()}

Inв обратном направлении вам придется снова кодировать компактную строку в байты:

data = json.loads(json_document)
jose.decrypt(jose.deserialize_compact(data['jwt'].encode()), priv_jwk)

Но вы в основном используете устаревшее программное обеспечение;Проект Demonware / jose не обновлялся в течение 3 лет. Он также опирается на устаревший, не поддерживаемый пакет pycrypto. Вы не хотите использовать.

Вместо этого взгляните на Authlib или JWCrypto , два модуля, которые активно поддерживаются и используйте cryptography проект для обработки сложных криптографических примитивов (есть также pyjwt и python-jose, но эти проекты (пока) не поддерживают шифрование JWE, только JWS подписанотокены).

Из них Authlib предлагает самый чистый и понятный API. Например, чтобы сгенерировать пару из открытого и закрытого ключей и создать зашифрованный токен с помощью Authlib, используя алгоритм шифрования и подписи по умолчанию, выбранный Demonware / JOSE, вы должны сделать:здесь значение bytes, поэтому вам придется декодировать и кодировать это тоже, если вы хотите дополнительно встроить это в JSON и передать данные токена из полезной нагрузки JSON обратно в метод jwt.decode().

Использование тех же сериализаций открытого и закрытого ключей с JWCrypto:

import json
from jwcrypto import jwt, jwk

# Create a JWK key object from the private key
jwk_key = jwk.JWK.from_pem(private_key_pem)

# create a JWT() instance to handle ecryption and serialization
header = {'enc': 'A128CBC-HS256', 'alg': 'RSA-OAEP'}
jwt_token = jwt.JWT(claims, header)
jwt_token.make_encrypted_token(jwk_key)
token = jwt_token.serialize()

# deserialize again, using a new JWT instance but with different arguments;
# Yes, this is a confusing API.
# it's always a good idea to limit what algorithms you'll accept
# note that this is a list of both *signing* and *encryption* algorithms, not
# the possible values of the "alg" key in a JOSE header.
jwt_token = jwt.JWT(key=jwk_key, jwt=token, algs=['A128CBC-HS256', 'RSA-OAEP'])
claims_from_token = json.loads(jwt_token.claims)

Обратите внимание, что эта библиотека возвращает строку при сериализации, но вы должны выполнить JSON-декодирование заявок вручную. API также смешивает сериализацию и десериализацию в один класс, создавая очень запутанную смесь аргументов, методов и свойств.

...