diff --git a/lib/jwa/ecdh/compute_secret.js b/lib/jwa/ecdh/compute_secret.js new file mode 100644 index 0000000000..8499004fe1 --- /dev/null +++ b/lib/jwa/ecdh/compute_secret.js @@ -0,0 +1,33 @@ +const { createECDH, 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)]) + +module.exports = ({ crv, d }, { x, y = '' }) => { + const curve = crvToCurve(crv) + const exchange = createECDH(curve) + + exchange.setPrivateKey(base64url.decodeToBuffer(d)) + + return exchange.computeSecret(pubToBuffer(x, y)) +} diff --git a/lib/jwa/ecdh/derive.js b/lib/jwa/ecdh/derive.js index 755a946578..2dbbd789b8 100644 --- a/lib/jwa/ecdh/derive.js +++ b/lib/jwa/ecdh/derive.js @@ -1,36 +1,5 @@ -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 { createHash } = require('crypto') +const ecdhComputeSecret = require('./compute_secret') const concat = (key, length, value) => { const iterations = Math.ceil(length / 256) @@ -58,12 +27,7 @@ const uint32be = (value, buf = Buffer.allocUnsafe(4)) => { 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) } = {}) => { +module.exports = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buffer.alloc(0) } = {}, computeSecret = ecdhComputeSecret) => { const value = Buffer.concat([ lengthAndInput(Buffer.from(alg)), lengthAndInput(apu), @@ -71,7 +35,6 @@ const derive = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buf uint32be(keyLen) ]) - return concatDerive(privKey, pubKey, keyLen / 8, value) + const sharedSecret = computeSecret(privKey, pubKey) + return concat(sharedSecret, keyLen / 8, value) } - -module.exports = derive diff --git a/lib/jwa/ecdh/kw.js b/lib/jwa/ecdh/kw.js index f4a525f1d8..4dfcbd172d 100644 --- a/lib/jwa/ecdh/kw.js +++ b/lib/jwa/ecdh/kw.js @@ -3,6 +3,7 @@ const { strict: assert } = require('assert') const { KEYOBJECT } = require('../../help/consts') const { generateSync } = require('../../jwk/generate') const { name: secp256k1 } = require('../../jwk/key/secp256k1_crv') +const { ECDH_DERIVE_LENGTHS } = require('../../registry') const derive = require('./derive') @@ -34,6 +35,7 @@ module.exports = (JWA, JWK) => { const kwWrap = JWA.keyManagementEncrypt.get(kw) const kwUnwrap = JWA.keyManagementDecrypt.get(kw) const keylen = parseInt(jwaAlg.substr(9, 3), 10) + ECDH_DERIVE_LENGTHS.set(jwaAlg, keylen) if (kwWrap && kwUnwrap) { JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, kwWrap, derive.bind(undefined, jwaAlg, keylen))) @@ -42,3 +44,5 @@ module.exports = (JWA, JWK) => { } }) } +module.exports.wrapKey = wrapKey +module.exports.unwrapKey = unwrapKey diff --git a/lib/registry/ecdh_derive_lengths.js b/lib/registry/ecdh_derive_lengths.js new file mode 100644 index 0000000000..c08549c45f --- /dev/null +++ b/lib/registry/ecdh_derive_lengths.js @@ -0,0 +1 @@ +module.exports = new Map() diff --git a/lib/registry/index.js b/lib/registry/index.js index ecf04d396b..70558d2bc2 100644 --- a/lib/registry/index.js +++ b/lib/registry/index.js @@ -4,9 +4,11 @@ const JWA = require('./jwa') const JWK = require('./jwk') const KEYLENGTHS = require('./key_lengths') const OKP_CURVES = require('./okp_curves') +const ECDH_DERIVE_LENGTHS = require('./ecdh_derive_lengths') module.exports = { EC_CURVES, + ECDH_DERIVE_LENGTHS, IVLENGTHS, JWA, JWK,