@jc-lab/jose
Version:
JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWT, JWKS for Node.js with minimal dependencies
78 lines (62 loc) • 2.19 kB
JavaScript
const { createECDH, createHash, constants: { POINT_CONVERSION_UNCOMPRESSED } } = require('crypto')
const base64url = require('../../help/base64url')
const { name: secp256k1 } = require('../../jwk/key/secp256k1_crv')
const crvToCurve = (crv) => {
switch (crv) {
case 'P-256':
return 'prime256v1'
case 'P-384':
return 'secp384r1'
case 'P-521':
return 'secp521r1'
case 'secp256k1':
case 'X448':
case 'X25519':
return crv
case secp256k1:
return 'secp256k1'
}
}
const UNCOMPRESSED = Buffer.alloc(1, POINT_CONVERSION_UNCOMPRESSED)
const pubToBuffer = (x, y) => Buffer.concat([UNCOMPRESSED, base64url.decodeToBuffer(x), base64url.decodeToBuffer(y)])
const computeSecret = ({ crv, d }, { x, y = '' }) => {
const curve = crvToCurve(crv)
const exchange = createECDH(curve)
exchange.setPrivateKey(base64url.decodeToBuffer(d))
return exchange.computeSecret(pubToBuffer(x, y))
}
const concat = (key, length, value) => {
const iterations = Math.ceil(length / 256)
let res
for (let iter = 1; iter <= iterations; iter++) {
const buf = Buffer.allocUnsafe(4 + key.length + value.length)
buf.writeUInt32BE(iter, 0)
key.copy(buf, 4)
value.copy(buf, 4 + key.length)
if (!res) {
res = createHash('sha256').update(buf).digest()
} else {
res = Buffer.concat([res, createHash('sha256').update(buf).digest()])
}
}
return res.slice(0, length)
}
const uint32be = (value, buf = Buffer.allocUnsafe(4)) => {
buf.writeUInt32BE(value)
return buf
}
const lengthAndInput = input => Buffer.concat([uint32be(input.length), input])
const concatDerive = (key, pubKey, length, value) => {
const shared = computeSecret(key, pubKey)
return concat(shared, length, value)
}
const derive = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buffer.alloc(0) } = {}) => {
const value = Buffer.concat([
lengthAndInput(Buffer.from(alg)),
lengthAndInput(apu),
lengthAndInput(apv),
uint32be(keyLen)
])
return concatDerive(privKey, pubKey, keyLen / 8, value)
}
module.exports = derive