From dcf8d75a8aca4f05fe04df64fdd2ba50bbc75bc9 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Wed, 15 Apr 2020 09:21:50 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20use=20native=20openssl=20AES=20Key=20Wra?= =?UTF-8?q?p=20=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/jwa/aes_kw.js | 71 ++++------------------------------------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/lib/jwa/aes_kw.js b/lib/jwa/aes_kw.js index 145f0a275e..689f5ba34e 100644 --- a/lib/jwa/aes_kw.js +++ b/lib/jwa/aes_kw.js @@ -1,7 +1,5 @@ const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') -const uint64be = require('../help/uint64be') -const timingSafeEqual = require('../help/timing_safe_equal') const { KEYOBJECT } = require('../help/consts') const { asInput } = require('../help/key_object') @@ -13,84 +11,25 @@ const checkInput = (data) => { const IV = Buffer.alloc(8, 'a6', 'hex') -const xor = (a, b) => { - const len = Math.max(a.length, b.length) - const result = Buffer.alloc(len) - for (let idx = 0; len > idx; idx++) { - result[idx] = (a[idx] || 0) ^ (b[idx] || 0) - } - - return result -} - -const split = (input, size) => { - const output = [] - for (let idx = 0; input.length > idx; idx += size) { - output.push(input.slice(idx, idx + size)) - } - return output -} - const wrapKey = (size, { [KEYOBJECT]: keyObject }, payload) => { const key = asInput(keyObject, false) - const iv = Buffer.alloc(16) - let R = split(payload, 8) - let A - let B - let count - A = IV - for (let jdx = 0; jdx < 6; jdx++) { - for (let idx = 0; R.length > idx; idx++) { - count = (R.length * jdx) + idx + 1 - const cipher = createCipheriv(`aes${size}`, key, iv) - B = Buffer.concat([A, R[idx]]) - B = cipher.update(B) + const cipher = createCipheriv(`aes${size}-wrap`, key, IV) - A = xor(B.slice(0, 8), uint64be(count)) - R[idx] = B.slice(8, 16) - } - } - R = [A].concat(R) - - return { wrapped: Buffer.concat(R) } + return { wrapped: Buffer.concat([cipher.update(payload), cipher.final()]) } } const unwrapKey = (size, { [KEYOBJECT]: keyObject }, payload) => { const key = asInput(keyObject, false) checkInput(payload) + const cipher = createDecipheriv(`aes${size}-wrap`, key, IV) - const iv = Buffer.alloc(16) - - let R = split(payload, 8) - let A - let B - let count - A = R[0] - R = R.slice(1) - for (let jdx = 5; jdx >= 0; --jdx) { - for (let idx = R.length - 1; idx >= 0; --idx) { - count = (R.length * jdx) + idx + 1 - B = xor(A, uint64be(count)) - B = Buffer.concat([B, R[idx], iv]) - const cipher = createDecipheriv(`aes${size}`, key, iv) - B = cipher.update(B) - - A = B.slice(0, 8) - R[idx] = B.slice(8, 16) - } - } - - if (!timingSafeEqual(IV, A)) { - throw new Error('unwrap failed') - } - - return Buffer.concat(R) + return Buffer.concat([cipher.update(payload), cipher.final()]) } module.exports = (JWA, JWK) => { ['A128KW', 'A192KW', 'A256KW'].forEach((jwaAlg) => { const size = parseInt(jwaAlg.substr(1, 3), 10) - if (getCiphers().includes(`aes${size}`)) { + if (getCiphers().includes(`aes${size}-wrap`)) { JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, size)) JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, size)) JWK.oct.wrapKey[jwaAlg] = JWK.oct.unwrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size