jose/lib/jwa/pbes2.js
Filip Skokan 23b874cc20 feat: add JWK key_ops support, fix .algorithms() op returns
BREAKING CHANGE: key.algorithms(op) un+wrapKey was split into correct
wrapKey/unwrapKey/deriveKey returns

BREAKING CHANGE: keystore.all and keystore.get `operation` option was
removed, `key_ops: string[]` supersedes it
2019-04-23 14:30:51 +02:00

55 lines
2.1 KiB
JavaScript

const { strict: assert } = require('assert')
const { pbkdf2Sync: pbkdf2, randomBytes } = require('crypto')
const { KEYOBJECT } = require('../help/consts')
const base64url = require('../help/base64url')
const SALT_LENGTH = 16
const NULL_BUFFER = Buffer.alloc(1, 0)
const concatSalt = (alg, p2s) => {
return Buffer.concat([
Buffer.from(alg, 'utf8'),
NULL_BUFFER,
p2s
])
}
const wrapKey = (keylen, sha, concat, wrap, { [KEYOBJECT]: keyObject }, payload) => {
// Note that if password-based encryption is used for multiple
// recipients, it is expected that each recipient use different values
// for the PBES2 parameters "p2s" and "p2c".
// here we generate p2c between 2048 and 4096 and random p2s
const p2c = Math.floor((Math.random() * 2049) + 2048)
const p2s = randomBytes(SALT_LENGTH)
const salt = concat(p2s)
const derivedKey = pbkdf2(keyObject.export(), salt, p2c, keylen, sha)
const result = wrap({ [KEYOBJECT]: derivedKey }, payload)
result.header = { p2c, p2s: base64url.encodeBuffer(p2s) }
return result
}
const unwrapKey = (keylen, sha, concat, unwrap, { [KEYOBJECT]: keyObject }, payload, { p2c, p2s }) => {
const salt = concat(p2s)
const derivedKey = pbkdf2(keyObject.export(), salt, p2c, keylen, sha)
return unwrap({ [KEYOBJECT]: derivedKey }, payload)
}
module.exports = (JWA) => {
['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW'].forEach((jwaAlg) => {
assert(!JWA.keyManagementEncrypt.has(jwaAlg), `keyManagementEncrypt alg ${jwaAlg} already registered`)
assert(!JWA.keyManagementDecrypt.has(jwaAlg), `keyManagementDecrypt alg ${jwaAlg} already registered`)
const kw = jwaAlg.substr(-6)
const kwWrap = JWA.keyManagementEncrypt.get(kw)
const kwUnwrap = JWA.keyManagementDecrypt.get(kw)
const keylen = parseInt(jwaAlg.substr(13, 3), 10) / 8
const sha = `sha${jwaAlg.substr(8, 3)}`
JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwWrap))
JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwUnwrap))
})
}