var SEA = require('./root'); var shim = require('./shim'); var S = require('./settings'); // Derive shared secret from other's pub and my epub/epriv SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try { opt = opt || {}; if(!pair || !pair.epriv || !pair.epub){ pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why}); } var pub = key.epub || key; var epub = pair.epub; var epriv = pair.epriv; var ecdhSubtle = shim.ossl || shim.subtle; var pubKeyData = keysToEcdhJwk(pub); var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },{name: 'ECDH', namedCurve: 'P-256'}); // Thanks to @sirpy ! var privKeyData = keysToEcdhJwk(epub, epriv); var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveBits']).then(async (privKey) => { // privateKey scope doesn't leak out from here! var derivedBits = await ecdhSubtle.deriveBits(props, privKey, 256); var rawBits = new Uint8Array(derivedBits); var derivedKey = await ecdhSubtle.importKey('raw', rawBits,{ name: 'AES-GCM', length: 256 }, true, [ 'encrypt', 'decrypt' ]); return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k); }) var r = derived; if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; } catch(e) { console.log(e); SEA.err = e; if(SEA.throw){ throw e } if(cb){ cb() } return; }}); // can this be replaced with settings.jwk? var keysToEcdhJwk = (pub, d) => { // d === priv //var [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old var [ x, y ] = pub.split('.') // new var jwk = d ? { d: d } : {} return [ // Use with spread returned value... 'jwk', Object.assign( jwk, { x: x, y: y, kty: 'EC', crv: 'P-256', ext: true } ), // ??? refactor {name: 'ECDH', namedCurve: 'P-256'} ] } module.exports = SEA.secret;