Skip to content

Commit

Permalink
refactor: allow ECDH-ES to be pluggable with extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Dec 4, 2019
1 parent b103874 commit af635be
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 42 deletions.
33 changes: 33 additions & 0 deletions lib/jwa/ecdh/compute_secret.js
Original file line number Diff line number Diff line change
@@ -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))
}
47 changes: 5 additions & 42 deletions lib/jwa/ecdh/derive.js
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -58,20 +27,14 @@ 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),
lengthAndInput(apv),
uint32be(keyLen)
])

return concatDerive(privKey, pubKey, keyLen / 8, value)
const sharedSecret = computeSecret(privKey, pubKey)
return concat(sharedSecret, keyLen / 8, value)
}

module.exports = derive
4 changes: 4 additions & 0 deletions lib/jwa/ecdh/kw.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down Expand Up @@ -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)))
Expand All @@ -42,3 +44,5 @@ module.exports = (JWA, JWK) => {
}
})
}
module.exports.wrapKey = wrapKey
module.exports.unwrapKey = unwrapKey
1 change: 1 addition & 0 deletions lib/registry/ecdh_derive_lengths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = new Map()
2 changes: 2 additions & 0 deletions lib/registry/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit af635be

Please sign in to comment.