secret.js 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. var SEA = require('./root');
  2. var shim = require('./shim');
  3. var S = require('./settings');
  4. // Derive shared secret from other's pub and my epub/epriv
  5. SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try {
  6. opt = opt || {};
  7. if(!pair || !pair.epriv || !pair.epub){
  8. pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why});
  9. }
  10. const pub = key.epub || key
  11. const epub = pair.epub
  12. const epriv = pair.epriv
  13. const ecdhSubtle = shim.ossl || shim.subtle
  14. const pubKeyData = keysToEcdhJwk(pub)
  15. const props = Object.assign(
  16. S.ecdh,
  17. { public: await ecdhSubtle.importKey(...pubKeyData, true, []) }
  18. )
  19. const privKeyData = keysToEcdhJwk(epub, epriv)
  20. const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey'])
  21. .then(async (privKey) => {
  22. // privateKey scope doesn't leak out from here!
  23. const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-GCM', length: 256 }, true, [ 'encrypt', 'decrypt' ])
  24. return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k)
  25. })
  26. const r = derived;
  27. if(cb){ try{ cb(r) }catch(e){console.log(e)} }
  28. return r;
  29. } catch(e) {
  30. SEA.err = e;
  31. if(SEA.throw){ throw e }
  32. if(cb){ cb() }
  33. return;
  34. }});
  35. const keysToEcdhJwk = (pub, d) => { // d === priv
  36. //const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old
  37. const [ x, y ] = pub.split('.') // new
  38. const jwk = d ? { d: d } : {}
  39. return [ // Use with spread returned value...
  40. 'jwk',
  41. Object.assign(
  42. jwk,
  43. { x: x, y: y, kty: 'EC', crv: 'P-256', ext: true }
  44. ), // ??? refactor
  45. S.ecdh
  46. ]
  47. }
  48. module.exports = SEA.secret;