Я не могу расшифровать токен JWE, сгенерированный jwcrypt (библиотека Python для шифрования и дешифрования JWE) в jose (библиотека Javascript для шифрования и дешифрования JWE)
Я также явно определил A256KW и A256CBC-HS512 как для jwcrypt, так и для jose. Мне также необходимо предоставить «секретный ключ» для параметра JWK «k», который будет использоваться для симметричного шифрования и дешифрования.
Ниже приведен Javascript-код для jose
import {
CompactEncrypt,
compactDecrypt,
CompactDecryptResult,
KeyLike,
importJWK,
} from 'jose';
class JweService {
async createSecretKey(jwtKey: string): Promise<KeyLike | Uint8Array> {
const base64Key = Buffer.from(jwtKey).toString('base64');
return importJWK(
{
kty: 'oct',
use: 'enc',
k: base64Key
},
'A256KW',
);
}
async createAccessToken(
payload,
secretKey: KeyLike | Uint8Array,
): Promise<string> {
const encoder = new TextEncoder();
return new CompactEncrypt(encoder.encode(payload))
.setProtectedHeader({
alg: 'A256KW',
enc: 'A256CBC-HS512',
})
.encrypt(secretKey);
}
async decryptAccessToken(
token: string,
secretKey: KeyLike | Uint8Array,
): Promise<string> {
const decoder = new TextDecoder();
const { plaintext }: CompactDecryptResult = await compactDecrypt(
token,
secretKey,
);
return decoder.decode(plaintext);
}
}Вот как я использую JweService
async createAccessTokenForDemo(reqBody): Promise<string> {
const secretKey = await this.jweService.createSecretKey(
'QEO89KnZ8GJNAZEhBGRlQaBVtuA9asd2',
);
return this.jweService.createAccessToken(
JSON.stringify(reqBody),
secretKey,
);
}
async decryptAccessTokenForDemo(reqBody): Promise<any> {
const secretKey = await this.jweService.createSecretKey(
'QEO89KnZ8GJNAZEhBGRlQaBVtuA9asd2',
);
const decrypted = await this.jweService.decryptAccessToken(
reqBody.Token,
secretKey,
);
return JSON.parse(decrypted);
}Теперь о Python, который использует jwcrypto:
from jwcrypto import jwk, jwe
from jwcrypto.common import json_encode
import base64
def create_secret_key(jwt_key, alg='A256KW'):
jwt_key_bytes = jwt_key.encode('utf-8') # Convert string to bytes
jwt_key_base64 = base64.b64encode(jwt_key_bytes) # Base64 encode the bytes
return jwk.JWK.generate(
kty = "oct",
use = "enc",
k = jwt_key_base64,
alg = alg
)
def create_access_token(payload, secret_key, alg='A256KW', enc='A256CBC-HS512'):
jwetoken = jwe.JWE(payload.encode('utf-8'), json_encode({"alg": alg, "enc": enc}))
jwetoken.add_recipient(secret_key)
return jwetoken.serialize(compact=True)
def decrypt_access_token(token, secret_key):
jwetoken = jwe.JWE()
jwetoken.deserialize(token)
jwetoken.decrypt(secret_key)
return jwetoken.payload.decode('utf-8')
# Secret key and payload
jwt_key = 'QEO89KnZ8GJNAZEhBGRlQaBVtuA9asd2'
payload = '{"name": "John"}'
# Create secret key
secret_key = create_secret_key(jwt_key)
# Create JWE access token
access_token = create_access_token(payload, secret_key)
print("Encrypted Payload:", access_token)
# Decrypt JWE access token
decrypted_payload = decrypt_access_token(access_token, secret_key)
print("Decrypted Payload:", decrypted_payload)Это пример токена JWE из скрипта Python: (При расшифровке с помощью NodeJS jose библиотека jose возвращает ошибку «Ошибка: операция дешифрования не удалась»)
Encrypted JWE token: b'eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.4xd2sw9FFFBZjzOo7ofz-Y7M_rUK_2-DACZPZyvVEHtFVa29eOu43s5rCtlh3xP8_9oMBOuoWXnzJWLEOyxyzl3axDYo-a8Y.QH-iHG2dqduw6r8agd5ZIg.W7MmKBaBEe5EwaGTHfXAUI2MhPFOHMGA5ZkHBNHWqUY.xRUr1jaYxwN5JDkazJ6mQYeSafiXCeidgPurl9qMJLs'
Decrypted JWE token: b'{"name": "John Doe"}'
Есть ли какая-то конфигурация, которой мне не хватает? или есть ли какая-то кодировка, которая отличается между NodeJS и Python за кулисами, что может быть причиной?
Привет @Topaco. Я сгенерировал новые токены JWE, по какой-то причине я больше не могу их расшифровать в NodeJS. Зашифрованная полезная нагрузка: eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.c8uqoqjjX8NMditN5FxoR370s2SStS3l2MyAICjMOpPPgoGMKvJXe4Uc1oPuEDCN4ErnR HTQCV0rv1ufuBGVHPrVquEA6FUg.lHpvKOITrWmPy_KjD1VAJA.2-Jqr7ilFdyou0Fd7OiYR_xEGpcmIDQ8XBsq-vyG68M.buxzj5_Nr-xjoBiU8oLcQYbW 7vAAlBEbX7H3rxZj3Jw Расшифрованная полезная нагрузка: {"name": "John"}
Токен, опубликованный в вашем последнем комментарии, невозможно расшифровать с помощью опубликованного ключа даже с помощью кода Python! Причина - несогласованный ключ, подробности смотрите в моем ответе.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


В коде Python новый случайный ключ длиной 32 байта генерируется в create_secret_key() с помощью jwk.JWK.generate() при каждом вызове. Переданный jwt_key игнорируется (т. е. k вообще не является кодировкой Base64url QEO8...). В этом можно легко убедиться, экспортировав сгенерированный ключ с помощью secret_key.export() и сравнив параметр k.
Как следствие, расшифровка токена с помощью кода NodeJS не удается при применении ключа QEO8....
Чтобы импортировать ключ (вместо создания нового), можно использовать следующую реализацию: s. здесь:
def create_secret_key(jwt_key, alg='A256KW'):
jwt_key_bytes = jwt_key.encode('utf-8')
jwt_key_base64url = base64.urlsafe_b64encode(jwt_key_bytes).replace(b" = ", b"").decode('utf-8')
key = {
'kty': 'oct',
'use': 'enc',
'k': jwt_key_base64url,
"alg": alg
}
return jwk.JWK(**key)
Также обратите внимание, что реализация применяет Base64url, а не Base64, как определено для JWK.
Со следующим кодом:
jwt_key = 'QEO89KnZ8GJNAZEhBGRlQaBVtuA9asd2'
secret_key = create_secret_key(jwt_key)
print('Key:' + secret_key.export())
импорт можно проверить: k — это UUVPODlLblo4R0pOQVpFaEJHUmxRYUJWdHVBOWFzZDI, что соответствует кодировке QEO89KnZ8GJNAZEhBGRlQaBVtuA9asd2 Base64url.
Также в соответствующем методе в коде NodeJS вместо Base64 необходимо использовать Base64url:
async createSecretKey(jwtKey) {
const base64urlKey = Buffer.from(jwtKey).toString('base64url');
return importJWK(
{
kty: 'oct',
use: 'enc',
k: base64urlKey
},
'A256KW',
);
}
Теперь, если зашифрованный токен генерируется с фиксированным кодом Python, например.
eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.BAhqPzCOT6u0xEGd40z6sYBU7XWJqwLMWxY1L6B2YYK0YdLvVe6WA8ypHJ6Q0cm4TWFw2xL4n6DeqqyoC9zkEd4fLqU04U4D.pK_f_0tBwXIj7hy79IjC2g.9vtRX6kKCBFoPD2UcfuUyIMevY3d7Pj7ydOM9XBWiJU.cYVtCc9O_8xuBxXg21316rmeNA2NHYPLF3NOjk7RSrw
это можно расшифровать с помощью ключа QEO8... и адаптированного кода NodeJS.
Это невозможно воспроизвести: опубликованный токен можно расшифровать с помощью опубликованного ключа и кода NodeJS, см. онлайн: jdoodle.com/ia/13Af