mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
feat: create pair using priv/epriv
This commit is contained in:
parent
6be276afe7
commit
7e254ae13f
79
sea.js
79
sea.js
@ -336,33 +336,64 @@
|
||||
SEA.pair = SEA.pair || (async (cb, opt) => { try {
|
||||
|
||||
var ecdhSubtle = shim.ossl || shim.subtle;
|
||||
var sa;
|
||||
var sa = {};
|
||||
var dh = {};
|
||||
|
||||
if(opt && opt.seed){
|
||||
const e = new shim.TextEncoder();
|
||||
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)
|
||||
};
|
||||
const [x,y,eh] = await Promise.all([
|
||||
shim.subtle.digest('SHA-256', e.encode(sa.priv+'-x')),
|
||||
shim.subtle.digest('SHA-256', e.encode(sa.priv+'-y')),
|
||||
shim.subtle.digest('SHA-256', e.encode(opt.seed+'-encrypt'))
|
||||
]);
|
||||
sa.pub = 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);
|
||||
const e = new shim.TextEncoder();
|
||||
|
||||
dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
|
||||
const [ex,ey] = await Promise.all([
|
||||
shim.subtle.digest('SHA-256', e.encode(dh.epriv+'-x')),
|
||||
shim.subtle.digest('SHA-256', e.encode(dh.epriv+'-y'))
|
||||
// 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'))
|
||||
]);
|
||||
dh.epub = 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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.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);
|
||||
@ -388,7 +419,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
var r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv }
|
||||
var r = { pub: sa.pub, priv: sa.priv, epub: dh.epub, epriv: dh.epriv }
|
||||
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
|
||||
return r;
|
||||
} catch(e) {
|
||||
|
77
sea/pair.js
77
sea/pair.js
@ -18,33 +18,64 @@
|
||||
SEA.pair = SEA.pair || (async (cb, opt) => { try {
|
||||
|
||||
var ecdhSubtle = shim.ossl || shim.subtle;
|
||||
var sa;
|
||||
var sa = {};
|
||||
var dh = {};
|
||||
|
||||
if(opt && opt.seed){
|
||||
const e = new shim.TextEncoder();
|
||||
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)
|
||||
};
|
||||
const [x,y,eh] = await Promise.all([
|
||||
shim.subtle.digest('SHA-256', e.encode(sa.priv+'-x')),
|
||||
shim.subtle.digest('SHA-256', e.encode(sa.priv+'-y')),
|
||||
shim.subtle.digest('SHA-256', e.encode(opt.seed+'-encrypt'))
|
||||
const e = new shim.TextEncoder();
|
||||
|
||||
// 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'))
|
||||
]);
|
||||
sa.pub = 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);
|
||||
|
||||
dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
|
||||
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);
|
||||
}
|
||||
|
||||
// Helper function to generate epub from epriv
|
||||
const epubFromEpriv = async (epriv) => {
|
||||
const [ex,ey] = await Promise.all([
|
||||
shim.subtle.digest('SHA-256', e.encode(dh.epriv+'-x')),
|
||||
shim.subtle.digest('SHA-256', e.encode(dh.epriv+'-y'))
|
||||
shim.subtle.digest('SHA-256', e.encode(epriv+'-x')),
|
||||
shim.subtle.digest('SHA-256', e.encode(epriv+'-y'))
|
||||
]);
|
||||
dh.epub = 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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.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);
|
||||
@ -70,7 +101,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
var r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv }
|
||||
var r = { pub: sa.pub, priv: sa.priv, epub: dh.epub, epriv: dh.epriv }
|
||||
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
|
||||
return r;
|
||||
} catch(e) {
|
||||
|
@ -1,3 +1,6 @@
|
||||
const exp = require('constants');
|
||||
const expect = require('../expect');
|
||||
|
||||
var root;
|
||||
var Gun;
|
||||
(function(){
|
||||
@ -74,6 +77,24 @@ describe('SEA', function(){
|
||||
expect(sameKeys).to.be(true);
|
||||
expect(differentKeys).to.be(true);
|
||||
});
|
||||
it('generate key pairs from private key', async function () {
|
||||
var gun = Gun()
|
||||
var user = gun.user()
|
||||
const test1 = await SEA.pair(null, { seed: "seed" });
|
||||
const test2 = await SEA.pair(null, { priv: test1.priv });
|
||||
expect(test2.priv).to.be(test1.priv);
|
||||
expect(test2.pub).to.be(test1.pub);
|
||||
await user.auth(test2);
|
||||
expect(user.is.pub).to.be(test2.pub);
|
||||
expect(user.is.pub).to.be(test1.pub);
|
||||
user.leave();
|
||||
const test3 = await SEA.pair(null, { epriv: test2.epriv });
|
||||
expect(test3.epriv).to.be(test2.epriv);
|
||||
await user.auth(test3);
|
||||
expect(user.is.epub).to.be(test3.epub);
|
||||
expect(user.is.epub).to.be(test2.epub);
|
||||
user.leave();
|
||||
});
|
||||
it('quickstart', function(done){
|
||||
SEA.pair(function(pair){
|
||||
SEA.encrypt('hello self', pair, function(enc){
|
||||
|
Loading…
x
Reference in New Issue
Block a user