Ошибка расшифровки - aes-256-gcm/A256GCM зашифрован с использованием узла jose и расшифрован с использованием шифрования узла

Я вижу следующую ошибку при расшифровке части cipherText JWE. CipherText (alg: aes-256-gcm) создается с использованием узла Node Jose, и я пытаюсь расшифровать с помощью шифрования Node.

Error: Unsupported state or unable to authenticate data
    at Decipheriv.final (node:internal/crypto/cipher:193:29)
    at Object.<anonymous> (/index.js:100:24)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47 

Узел jose encrypt decrypt: работает нормально

const jose = require('node-jose');


(async () => {

let keypair = {
"p": "wP8U4hF_Dyj-Z-YY_89gmT1ngnKER_0e_WTxOS5SWQp-giImmsCEVpP9mqKrwHBrkPJenFwa8kIxNgmJtGSuXkNMd8NoHdqzwtq50-mMCV1oDAIjXl0UUX8_CdVyy9TFe3-P5lJuQoOIRlCs_hvVJ_4x3fT9Xipo85OMoPTmwoM",
"kty": "RSA",
"q": "uk0U0Wx9GfpyLLJhJSJ1gyx5M31kAP9vMGQLrp0P40g-BOl7YYusv8H1EVcscZQuMrNBQvlIyJRTx229r_Wz961YqQ6fw-hJetQQ08CiLj8AuYMm6KHNbEyhzFV8lFyIZCwsDXbA-Ek6F5FLfOqfeFHjo0fOq77R7kcp8cepcP0",
"d": "bd1sMKhIu3QDbEvzrb8cj6f0egUQQU0S1M53okm9ByBWYOFCNPayoluvO9BWBBY2kMsIWQ64q7-sQgjc894yaffppF4Cz0jFCzIIIgoWmT4L4syQkdiiV7xoIrbKvZkloH7bSATf6QioxkcX-9Dz4Z5VHUg0GKzFkK74a655odc-VzlDp7cbrfeL29ETlbb9864IJIoC_hAhzfaVOHCMb8y5Rr5UTgGjf1QlYjSjMhE5L0BOty4QeyxDoy_dI7sosJPj9tVFQCa6yDJaOAFF_h3QTLyhXU1qL6GJbG_JklsTn5z93Vy8haVyf3FvHDW2PVkKy46HRTINpB72QWkV-Q",
"e": "AQAB",
"use": "enc",
"kid": "tester",
"qi": "tItxE9gwrpmifSWur8DdsaMZN7rylhhR18PIgtZaHhw58i9EBRpzW_CMZIHuzl8-ujh8ZsuUsmU2HbYX0VWZnPty3z_-hCWV1DjoElQ93WThcQa0HviIVSxbXEtYoLoNM_gzIFjihICGCtXhlF9Di3C4FKcCP0dYzYWpVFq4uac",
"dp": "M8j-IH7TWg0E3noWQSWy5MteJ9l0dyCLHTDlrRMp02yGb4KcWy_HErgY91IoxbUkl7sA-fGY5WIvdDFw-q99PhvOu9_54vDZBTLNY_gptCWVEovMU7ikCA4dqxTT_a904eNjiEib_0rt2PgywuhS9K03Ujg3d_nnOVxhAptUA-M",
"alg": "RSA-OAEP-256",
"dq": "NsOr5_gNOlK9t1fkaKcdhibPpgwpFoX_6Giwam7vGa_F02nTBBSr_l6ErMlEXkrh3bOF7qsa8yNvEUO4K_59HcSOOHv9CPjCiOHH5IdO5WtNyjq8eEv_9-L6-Pb0PSSKT3AQrxCGnzXfZsgmOZ06rYLc-MWGAkSAr5upv9Iig_0",
"n": "jHNxl1hhNxvYEn5PPObRia7LM6_koGcrcHLgWVVc-zU5loWn33xdd3R3EPs10ZwrhRBmXthN1WLFB0V4w-1QrGSM5wuBm2AqIFglDaYWW7d_aFCYMubCC6YiKYgrXezZtjngGtjBJPNwov4PC6KJgh7xwtqt5MTXX7TH8H6BhvQvNiD_IEH_vxF9hEhN-f5wKR6yNGlCT3X0NWwUiavG0vgtW0y1g6BHUskA1HogdrpURAfmcSSrDya9IoYjlAmUmql-0JGeEJIU53hoDB0ZVNREZbhJxZLN1hV8KrYeVPjfHCjXaJ6-Fw9MvnC9m-FGiX9dvE1A-Yp5sowUOqKLdw"
}
keypairob = await jose.JWK.asKey(JSON.stringify(keypair));

const contentAlg = "A256GCM";
const payload = JSON.stringify({test: 'test'});

const options = {
compact: true,
contentAlg: contentAlg,
protect: Object.keys({
alg: keypairob.alg,
kid: keypairob.kid,
enc: contentAlg
}),
fields: {
alg: keypairob.alg,
kid: keypairob.kid,
enc: contentAlg
}
};

const enc = await jose.JWE.createEncrypt(options, keypairob).update(payload, "utf8").final();
console.info("encrypted payload node jose  : "+enc);

const dec = await jose.JWE.createDecrypt(keypairob,options).decrypt(enc)
let decryptJSON = JSON.stringify(dec);
let originalInput = Buffer.from(dec.plaintext).toString("utf-8");
console.info("decrypted payload node jose :"+originalInput);
})();

Вывод консоли:

узел зашифрованной полезной нагрузки jose: eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJraWQiOiJ0ZXN0ZXIiLCJlbmMiOiJBMjU2R0NNIn0.Dw_EDEJnahKdk8mwlY3juSWd4jTIM8Go8NdQLpLWeH2kCmDHNg0RZKvbINEc3jF 70bPECCzuI_fH3ovlUeQ_o7KqbF_5ZMiyOIYQvfsVlgSZpl1YSRHgoX1QaRg_FvOvUile 6xGJ_nRnLSk1VjdTWJFARu-IGEfed0aQ1mCsh5Hq9e2q55iQGlMUQVIHQ7X6ZzXNHu4QW7 jSMYLskP7Vg-EjQizrGvHC04S2SsglZ0znm5eyz0KR71zcdkR2O80_v6u2GM6APMCQrJ3 GQ7SSsguwEKMxxvCpQvZ65lCV4bujvP7tD4A8pn_SCKTjFGU8MulGzHi2z-K4EZU6yZXFQ .DOkezaeJUsRg6h8q.oXC0AtIkn53UgjF2KdxW.1NBMp9IdXW-U5emoiIrE7A

расшифрованный узел полезной нагрузки Хосе :{"test":"test"}

Крипто-расшифровка узла:

const crypto = require('crypto');
const testJwk = {
"p": "wP8U4hF_Dyj-Z-YY_89gmT1ngnKER_0e_WTxOS5SWQp-giImmsCEVpP9mqKrwHBrkPJenFwa8kIxNgmJtGSuXkNMd8NoHdqzwtq50-mMCV1oDAIjXl0UUX8_CdVyy9TFe3-P5lJuQoOIRlCs_hvVJ_4x3fT9Xipo85OMoPTmwoM",
"kty": "RSA",
"q": "uk0U0Wx9GfpyLLJhJSJ1gyx5M31kAP9vMGQLrp0P40g-BOl7YYusv8H1EVcscZQuMrNBQvlIyJRTx229r_Wz961YqQ6fw-hJetQQ08CiLj8AuYMm6KHNbEyhzFV8lFyIZCwsDXbA-Ek6F5FLfOqfeFHjo0fOq77R7kcp8cepcP0",
"d": "bd1sMKhIu3QDbEvzrb8cj6f0egUQQU0S1M53okm9ByBWYOFCNPayoluvO9BWBBY2kMsIWQ64q7-sQgjc894yaffppF4Cz0jFCzIIIgoWmT4L4syQkdiiV7xoIrbKvZkloH7bSATf6QioxkcX-9Dz4Z5VHUg0GKzFkK74a655odc-VzlDp7cbrfeL29ETlbb9864IJIoC_hAhzfaVOHCMb8y5Rr5UTgGjf1QlYjSjMhE5L0BOty4QeyxDoy_dI7sosJPj9tVFQCa6yDJaOAFF_h3QTLyhXU1qL6GJbG_JklsTn5z93Vy8haVyf3FvHDW2PVkKy46HRTINpB72QWkV-Q",
"e": "AQAB",
"use": "enc",
"kid": "tester",
"qi": "tItxE9gwrpmifSWur8DdsaMZN7rylhhR18PIgtZaHhw58i9EBRpzW_CMZIHuzl8-ujh8ZsuUsmU2HbYX0VWZnPty3z_-hCWV1DjoElQ93WThcQa0HviIVSxbXEtYoLoNM_gzIFjihICGCtXhlF9Di3C4FKcCP0dYzYWpVFq4uac",
"dp": "M8j-IH7TWg0E3noWQSWy5MteJ9l0dyCLHTDlrRMp02yGb4KcWy_HErgY91IoxbUkl7sA-fGY5WIvdDFw-q99PhvOu9_54vDZBTLNY_gptCWVEovMU7ikCA4dqxTT_a904eNjiEib_0rt2PgywuhS9K03Ujg3d_nnOVxhAptUA-M",
"alg": "RSA-OAEP-256",
"dq": "NsOr5_gNOlK9t1fkaKcdhibPpgwpFoX_6Giwam7vGa_F02nTBBSr_l6ErMlEXkrh3bOF7qsa8yNvEUO4K_59HcSOOHv9CPjCiOHH5IdO5WtNyjq8eEv_9-L6-Pb0PSSKT3AQrxCGnzXfZsgmOZ06rYLc-MWGAkSAr5upv9Iig_0",
"n": "jHNxl1hhNxvYEn5PPObRia7LM6_koGcrcHLgWVVc-zU5loWn33xdd3R3EPs10ZwrhRBmXthN1WLFB0V4w-1QrGSM5wuBm2AqIFglDaYWW7d_aFCYMubCC6YiKYgrXezZtjngGtjBJPNwov4PC6KJgh7xwtqt5MTXX7TH8H6BhvQvNiD_IEH_vxF9hEhN-f5wKR6yNGlCT3X0NWwUiavG0vgtW0y1g6BHUskA1HogdrpURAfmcSSrDya9IoYjlAmUmql-0JGeEJIU53hoDB0ZVNREZbhJxZLN1hV8KrYeVPjfHCjXaJ6-Fw9MvnC9m-FGiX9dvE1A-Yp5sowUOqKLdw"
}
// node crypto generated JWE ciphertext part  - decrypt with node crypto code : success 
const nodeCryptoEncPayload = "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoidGVzdGVyIn0.FHEgUliMX84RcU_Vh50VsyvpradjaUclFyXpyTikqx6bhsBJ3KCUiE34plNNtI_e-CdU-NQEH-Aa7lhkpW4WsVoBi_2WO7IeIZ_Q2RkASlyB4Br0U98ExA6_vXzmZ1RtWaXsvcsRSpcwQTc5fmAah2eOG0A0glxYqf-dwM7PjOoIdP0ryc-6jrp5w1d2dE3ImoC-pMyOLTagsDj5iVUtIq8Y4xCFdXh4J1WYSZ6UAnyxYY0ctPVTv3NXJvlcbccy_4GsqgpSIk0Whcun0Jyjr0jPXw5Jaxl50VVW2Me8srgTSbFWugqEAfxkgVQHu2GDwd60oYyznMrfmYI8t4Q8lQ.8yeQaqpcresDf6Gy.7Bz_yj77Vfa1QTlfKZD1.ODRr0itIlYurZ3bbNH47jQ"    

// node jose generated JWE ciphertext part  - decrypt with node crypto code : error  
const nodejoseEncPayload = "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJraWQiOiJ0ZXN0ZXIiLCJlbmMiOiJBMjU2R0NNIn0.Dw_EDEJnahKdk8mwlY3juSWd4jTIM8Go8NdQLpLWeH2kCmDHNg0RZKvbINEc3jF70bPECCzuIi_fH3ovlUeQ_o7KqbF_5ZMiyOIYQvfsVlgSZpl1YSRHgoX1QaRg_FvOvUilE6xGJ_nRnLSk1VjdTWJFARu-IGEfed0aQ1mCsh5Hq9e2q55iQGlMUQVIHQ7X6ZzXNHu4QW7jSMYLskP7Vg-EjQizrGvHC04S2SsglZ0znm5eyz0KR71zcdkR2O80_v6u2GM6APMCQrJ3GQ7SSsguwEKMxxvCpQvZ65lCV4bujvP7tD4A8pn_SCKTjFGU8MulGzHi2z-K4EZU6yZXFQ.DOkezaeJUsRg6h8q.oXC0AtIkn53UgjF2KdxW.1NBMp9IdXW-U5emoiIrE7A"


// Step 1 : Split JWE string 
// const jweParts = nodejoseEncPayload.split(".");
const jweParts = nodeCryptoEncPayload.split(".");
const jweProtectedHeaderPart = jweParts[0];
const jweEncryptedKeyPart = jweParts[1];
const jweIvPart = jweParts[2];
const jweCipherTextPart = jweParts[3];  
const jweAuthTagPart = jweParts[4];

//step 2 : Decrypt CEK 

const sk = crypto.createPrivateKey({ key: testJwk, format: 'jwk',encoding: "utf-8" });

const decryptedCek = crypto.privateDecrypt({key:sk,oaepHash: 'sha256',padding: crypto.constants.RSA_PKCS1_OAEP_PADDING},
Buffer.from(jweEncryptedKeyPart,"base64")
);


//step 3 : Decrypt Content  

const dataToDecryptPart = jweCipherTextPart.slice(0, jweCipherTextPart.length - jweCipherTextPart.length);

const deCipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(decryptedCek, 'base64'), Buffer.from(jweIvPart, 'base64'));

deCipher.setAuthTag(Buffer.from(jweAuthTagPart, 'base64'))
deCipher.setAAD(Buffer.from(jweProtectedHeaderPart, 'base64'));
let decrypted = deCipher.update(Buffer.from(jweCipherTextPart, 'base64'), null, 'utf8');
deCipher.setAutoPadding(false);
decrypted += deCipher.final('utf8');

console.info("Decrypted text : "+decrypted)    

**Console output**

Decrypted text : {"test":"test"}

блок кода шифрования узла работает с узлом, сгенерированным с помощью шифрования JWE nodeCryptoEncPayload, но возникают ошибки для узла, сгенерированного jose, используется JWE nodejoseEncPayload

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Заголовок должен передаваться в формате AAD «как есть», т. е. в кодировке Base64. Ошибка в текущем коде — декодирование Base64. Исправить:

...
deCipher.setAAD(Buffer.from(jweProtectedHeaderPart, 'utf8'));
...

Благодаря этому исправлению расшифровка токена JOSE работает.


Несколько несоответствий, но без последствий: компоненты токена на самом деле закодированы Base64url. Поэтому было бы чище применить Base64url, то есть идентификатор base64url вместо base64. Хотя криптомодуль исправляет это изнутри, с правильным идентификатором было бы яснее.
Кроме того, decryptedCek уже является буфером и не требует декодирования Base64 (что, впрочем, также неявно фиксируется криптомодулем).
Кроме того, насколько я знаю, заполнение автоматически отключается для GCM, поэтому явное отключение с помощью setAutoPadding() не требуется.

Спасибо. это устранило проблему. Есть ли у вас какие-либо предложения по обратной совместимости с шифрованием узла, поскольку теперь по той же причине он нарушает криптокод узла?

vion 29.08.2024 20:11

@vion — Похоже, ваш код шифрования NodeJS не соответствует RFC 7516, поскольку он генерирует JWE, не соответствующий RFC 7516 (nodeCryptoEncPayload), в отличие от кода шифрования node-jose. Без кода я могу только предполагать: возможно, здесь также необходимо использовать заголовок в кодировке Base64 в качестве AAD. Если это не решит проблему, вам следует задать новый вопрос, используя код шифрования NodeJS.

Topaco 29.08.2024 21:36

Другие вопросы по теме