fix: use native openssl AES Key Wrap 🤦

This commit is contained in:
Filip Skokan 2020-04-15 09:21:50 +02:00
parent 447f2bee01
commit dcf8d75a8a

View file

@ -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