diff --git a/sea.js b/sea.js index 3c85cbbd..de4d795c 100644 --- a/sea.js +++ b/sea.js @@ -332,86 +332,30 @@ return; }}); - //SEA.pair = async (data, proof, cb) => { try { SEA.pair = SEA.pair || (async (cb, opt) => { try { - - var ecdhSubtle = shim.ossl || shim.subtle; - var sa = {}; - var dh = {}; - const e = new shim.TextEncoder(); + const h = async d => shim.Buffer.from(await shim.subtle.digest('SHA-256', e.encode(d))).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); + const g = async k => (await Promise.all([h(k+'-x'), h(k+'-y')])).join('.'); + let r = {}; - // Helper function to generate pub from priv - const pubFromPriv = async (priv) => { - const [x,y] = await Promise.all([ - shim.subtle.digest('SHA-256', e.encode(priv+'-x')), - shim.subtle.digest('SHA-256', e.encode(priv+'-y')) - ]); - return shim.Buffer.from(x).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) + - '.' + - shim.Buffer.from(y).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); + if(opt && opt.seed){ + r = { priv: await h(opt.seed+'-sign'), epriv: await h(opt.seed+'-encrypt') }; } - - // Helper function to generate epub from epriv - const epubFromEpriv = async (epriv) => { - const [ex,ey] = await Promise.all([ - shim.subtle.digest('SHA-256', e.encode(epriv+'-x')), - shim.subtle.digest('SHA-256', e.encode(epriv+'-y')) - ]); - return shim.Buffer.from(ex).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) + - '.' + - shim.Buffer.from(ey).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); + else if(opt && opt.priv){ + r = { priv: opt.priv, epriv: opt.epriv || await h(opt.priv+'-encrypt') }; } - - if(opt && opt.seed){ // Case 0: Generate from seed - const h = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-sign')); - sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - sa.pub = await pubFromPriv(sa.priv); - const eh = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-encrypt')); - dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - dh.epub = await epubFromEpriv(dh.epriv); + else if(opt && opt.epriv){ + r = { epriv: opt.epriv, priv: await h(opt.epriv+'-sign') }; } - else if(opt && opt.priv){ // Case 1 & 3: Given priv - sa.priv = opt.priv; - sa.pub = await pubFromPriv(sa.priv); - if(!opt.epriv){ // Case 1: Generate epriv - // Generate a virtual seed from priv to maintain compatibility - const virtualSeed = sa.priv; - const eh = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-encrypt')); - dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - } else { // Case 3: Use provided epriv - dh.epriv = opt.epriv; - } - dh.epub = await epubFromEpriv(dh.epriv); - } - else if(opt && opt.epriv){ // Case 2: Given epriv - dh.epriv = opt.epriv; - dh.epub = await epubFromEpriv(dh.epriv); - // Generate a virtual seed from epriv to maintain compatibility - const virtualSeed = dh.epriv; - const h = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-sign')); - sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - sa.pub = await pubFromPriv(sa.priv); - } - else { // Case 4: Generate new keypair - // First: ECDSA keys for signing/verifying... - const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, [ 'sign', 'verify' ]); - const priv = await shim.subtle.exportKey('jwk', keys.privateKey); - const pub = await shim.subtle.exportKey('jwk', keys.publicKey); - sa = { - priv: priv.d, - pub: pub.x + '.' + pub.y - }; - - // Next: ECDH keys for encryption/decryption... + else { + const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify']); + const [priv, pub] = await Promise.all([shim.subtle.exportKey('jwk', keys.privateKey), shim.subtle.exportKey('jwk', keys.publicKey)]); + r = { priv: priv.d, pub: pub.x+'.'+pub.y }; try { - const dhKeys = await ecdhSubtle.generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']); - const dhPriv = await ecdhSubtle.exportKey('jwk', dhKeys.privateKey); - const dhPub = await ecdhSubtle.exportKey('jwk', dhKeys.publicKey); - dh = { - epriv: dhPriv.d, - epub: dhPub.x + '.' + dhPub.y - }; + const dhKeys = await (shim.ossl || shim.subtle).generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']); + const [dhPriv, dhPub] = await Promise.all([shim.subtle.exportKey('jwk', dhKeys.privateKey), shim.subtle.exportKey('jwk', dhKeys.publicKey)]); + r.epriv = dhPriv.d; + r.epub = dhPub.x+'.'+dhPub.y; } catch(e) { if(SEA.window){ throw e } if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...') } @@ -419,7 +363,8 @@ } } - var r = { pub: sa.pub, priv: sa.priv, epub: dh.epub, epriv: dh.epriv } + r.pub = r.pub || await g(r.priv); + r.epub = r.epub || await g(r.epriv); if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; } catch(e) { diff --git a/sea/pair.js b/sea/pair.js index 3410b93e..65d92c52 100644 --- a/sea/pair.js +++ b/sea/pair.js @@ -1,5 +1,4 @@ ;(function(){ - var SEA = require('./root'); var shim = require('./shim'); @@ -14,86 +13,30 @@ return; }}); - //SEA.pair = async (data, proof, cb) => { try { SEA.pair = SEA.pair || (async (cb, opt) => { try { - - var ecdhSubtle = shim.ossl || shim.subtle; - var sa = {}; - var dh = {}; - const e = new shim.TextEncoder(); + const h = async d => shim.Buffer.from(await shim.subtle.digest('SHA-256', e.encode(d))).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); + const g = async k => (await Promise.all([h(k+'-x'), h(k+'-y')])).join('.'); + let r = {}; - // Helper function to generate pub from priv - const pubFromPriv = async (priv) => { - const [x,y] = await Promise.all([ - shim.subtle.digest('SHA-256', e.encode(priv+'-x')), - shim.subtle.digest('SHA-256', e.encode(priv+'-y')) - ]); - return shim.Buffer.from(x).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) + - '.' + - shim.Buffer.from(y).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); + if(opt && opt.seed){ + r = { priv: await h(opt.seed+'-sign'), epriv: await h(opt.seed+'-encrypt') }; } - - // Helper function to generate epub from epriv - const epubFromEpriv = async (epriv) => { - const [ex,ey] = await Promise.all([ - shim.subtle.digest('SHA-256', e.encode(epriv+'-x')), - shim.subtle.digest('SHA-256', e.encode(epriv+'-y')) - ]); - return shim.Buffer.from(ex).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) + - '.' + - shim.Buffer.from(ey).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); + else if(opt && opt.priv){ + r = { priv: opt.priv, epriv: opt.epriv || await h(opt.priv+'-encrypt') }; } - - if(opt && opt.seed){ // Case 0: Generate from seed - const h = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-sign')); - sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - sa.pub = await pubFromPriv(sa.priv); - const eh = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-encrypt')); - dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - dh.epub = await epubFromEpriv(dh.epriv); + else if(opt && opt.epriv){ + r = { epriv: opt.epriv, priv: await h(opt.epriv+'-sign') }; } - else if(opt && opt.priv){ // Case 1 & 3: Given priv - sa.priv = opt.priv; - sa.pub = await pubFromPriv(sa.priv); - if(!opt.epriv){ // Case 1: Generate epriv - // Generate a virtual seed from priv to maintain compatibility - const virtualSeed = sa.priv; - const eh = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-encrypt')); - dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - } else { // Case 3: Use provided epriv - dh.epriv = opt.epriv; - } - dh.epub = await epubFromEpriv(dh.epriv); - } - else if(opt && opt.epriv){ // Case 2: Given epriv - dh.epriv = opt.epriv; - dh.epub = await epubFromEpriv(dh.epriv); - // Generate a virtual seed from epriv to maintain compatibility - const virtualSeed = dh.epriv; - const h = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-sign')); - sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43); - sa.pub = await pubFromPriv(sa.priv); - } - else { // Case 4: Generate new keypair - // First: ECDSA keys for signing/verifying... - const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, [ 'sign', 'verify' ]); - const priv = await shim.subtle.exportKey('jwk', keys.privateKey); - const pub = await shim.subtle.exportKey('jwk', keys.publicKey); - sa = { - priv: priv.d, - pub: pub.x + '.' + pub.y - }; - - // Next: ECDH keys for encryption/decryption... + else { + const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify']); + const [priv, pub] = await Promise.all([shim.subtle.exportKey('jwk', keys.privateKey), shim.subtle.exportKey('jwk', keys.publicKey)]); + r = { priv: priv.d, pub: pub.x+'.'+pub.y }; try { - const dhKeys = await ecdhSubtle.generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']); - const dhPriv = await ecdhSubtle.exportKey('jwk', dhKeys.privateKey); - const dhPub = await ecdhSubtle.exportKey('jwk', dhKeys.publicKey); - dh = { - epriv: dhPriv.d, - epub: dhPub.x + '.' + dhPub.y - }; + const dhKeys = await (shim.ossl || shim.subtle).generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']); + const [dhPriv, dhPub] = await Promise.all([shim.subtle.exportKey('jwk', dhKeys.privateKey), shim.subtle.exportKey('jwk', dhKeys.publicKey)]); + r.epriv = dhPriv.d; + r.epub = dhPub.x+'.'+dhPub.y; } catch(e) { if(SEA.window){ throw e } if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...') } @@ -101,7 +44,8 @@ } } - var r = { pub: sa.pub, priv: sa.priv, epub: dh.epub, epriv: dh.epriv } + r.pub = r.pub || await g(r.priv); + r.epub = r.epub || await g(r.epriv); if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; } catch(e) { @@ -113,5 +57,4 @@ }}); module.exports = SEA.pair; - }());