gun/sea/secret.js
2020-01-07 15:32:22 +02:00

52 lines
2.0 KiB
JavaScript

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;