libves 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,10 @@
16
16
 
17
17
  # libVES.js
18
18
 
19
+ [![CI](https://github.com/vesvault/libVES/actions/workflows/ci.yml/badge.svg)](https://github.com/vesvault/libVES/actions/workflows/ci.yml)
20
+ [![npm](https://img.shields.io/npm/v/libves)](https://www.npmjs.com/package/libves)
21
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
22
+
19
23
  **End-to-end encryption for the browser and Node — that you can actually recover from.**
20
24
 
21
25
  The official VESvault JavaScript library. It does client-side end-to-end encryption
@@ -135,7 +139,9 @@ open source under the Apache License 2.0. See current terms and pricing at
135
139
  Bug reports and small, focused fixes are welcome via issues and pull requests. Because
136
140
  this is security-critical software backed by a hosted service, larger changes — new
137
141
  cryptography, API-surface or protocol changes — should **start with an issue** before you
138
- write code; we can't always merge changes that affect the protocol or the service.
142
+ write code; we can't always merge changes that affect the protocol or the service. See
143
+ [CONTRIBUTING.md](CONTRIBUTING.md) for build, syntax-check, and test details, and our
144
+ [Code of Conduct](CODE_OF_CONDUCT.md).
139
145
 
140
146
  Security issues are different: **please don't open a public issue or PR** — follow
141
147
  [SECURITY.md](SECURITY.md).
package/libVES.js CHANGED
@@ -32,7 +32,7 @@
32
32
  *
33
33
  * @title libVES
34
34
  * @dev A JavaScript end-to-end encryption interface to VESvault REST API
35
- * @version 3.1.0
35
+ * @version 3.2.0
36
36
  *
37
37
  * @dev Official source code: https://github.com/vesvault/libVES
38
38
  *
@@ -1782,6 +1782,7 @@ if (typeof(libVES) != 'function') function libVES(optns) {
1782
1782
  else throw new libVES.Error('InvalidValue','Required parameters: user || domain');
1783
1783
  this.unlockedKeys = {};
1784
1784
  this.pendingKeys = {};
1785
+ this.attnErrors = [];
1785
1786
  }
1786
1787
 
1787
1788
  libVES.prototype = {
@@ -1980,7 +1981,9 @@ libVES.prototype = {
1980
1981
  return cryptoKey;
1981
1982
  });
1982
1983
  }).then(function(ck) {
1983
- return self.handleAttn().catch(function() {}).then(function() {
1984
+ return self.handleAttn().catch(function(e) {
1985
+ self.logAttnError(e);
1986
+ }).then(function() {
1984
1987
  return ck;
1985
1988
  });
1986
1989
  });
@@ -2583,6 +2586,16 @@ libVES.prototype = {
2583
2586
  });
2584
2587
  });
2585
2588
  },
2589
+ attnErrors: null,
2590
+ logAttnError: function(error, vaultKey) {
2591
+ if (!this.attnErrors) this.attnErrors = [];
2592
+ var rec = {error: error, at: new Date()};
2593
+ if (vaultKey !== undefined) rec.vaultKey = vaultKey;
2594
+ this.attnErrors.push(rec);
2595
+ if (this.attnErrors.length > 64) this.attnErrors.shift();
2596
+ try { console.error('libVES attn error:', error, vaultKey); } catch (e) {}
2597
+ return rec;
2598
+ },
2586
2599
  getAttn: function() {
2587
2600
  var self = this;
2588
2601
  var rs = {};
@@ -2605,7 +2618,6 @@ libVES.prototype = {
2605
2618
  attnVaultKeys: function(vkeys) {
2606
2619
  var self = this;
2607
2620
  return Promise.all(vkeys.map(function(vkey, i) {
2608
- console.log('attnVaultKeys:', vkey);
2609
2621
  return vkey.getType().then(function(type) {
2610
2622
  switch (type) {
2611
2623
  case 'temp':
@@ -2641,6 +2653,8 @@ libVES.prototype = {
2641
2653
  return rcv.recover();
2642
2654
  });
2643
2655
  }
2656
+ }).catch(function(e) {
2657
+ return self.logAttnError(e, vkey);
2644
2658
  });
2645
2659
  }));
2646
2660
  },
@@ -5166,6 +5180,15 @@ libVES.Scramble = {
5166
5180
  }
5167
5181
  };
5168
5182
  libVES.Scramble.RDX.prototype = {
5183
+ explode: function(sc,ct,optns) {
5184
+ var impl = (optns && optns.v && libVES.Scramble.algo[optns.v]) || (ct <= 255 ? libVES.Scramble.SSS : libVES.Scramble.RDX12);
5185
+ return new impl(this.size).explode(sc,ct,optns);
5186
+ }
5187
+ };
5188
+ libVES.Scramble.RDX12 = function(x) {
5189
+ this.size = x;
5190
+ };
5191
+ libVES.Scramble.RDX12.prototype = {
5169
5192
  tag: 'RDX1.2',
5170
5193
  name: 'RDX 1.2 Shamir',
5171
5194
  getBases: function(n) {
@@ -5307,8 +5330,115 @@ libVES.Scramble.RDX.prototype = {
5307
5330
  return f([0]);
5308
5331
  }
5309
5332
  };
5333
+ libVES.Scramble.SSS = function(x) {
5334
+ this.size = x;
5335
+ };
5336
+ libVES.Scramble.SSS.prototype = {
5337
+ tag: 'SSS1',
5338
+ name: 'Shamir GF(256)',
5339
+ gf: function() {
5340
+ var g = libVES.Scramble.SSS._gf;
5341
+ if (g) return g;
5342
+ var exp = new Uint8Array(512);
5343
+ var log = new Uint8Array(256);
5344
+ for (var a = 1, i = 0; i < 255; i++) {
5345
+ exp[i] = a;
5346
+ log[a] = i;
5347
+ var d = a << 1;
5348
+ if (d & 0x100) d ^= 0x11b;
5349
+ a = d ^ a;
5350
+ }
5351
+ for (var j = 255; j < 512; j++) exp[j] = exp[j - 255];
5352
+ return libVES.Scramble.SSS._gf = {exp: exp, log: log};
5353
+ },
5354
+ mul: function(a,b) {
5355
+ if (!a || !b) return 0;
5356
+ var g = this.gf();
5357
+ return g.exp[g.log[a] + g.log[b]];
5358
+ },
5359
+ div: function(a,b) {
5360
+ if (!a) return 0;
5361
+ var g = this.gf();
5362
+ return g.exp[g.log[a] + 255 - g.log[b]];
5363
+ },
5364
+ weights: function(xs,x0) {
5365
+ var w = [];
5366
+ for (var i = 0; i < xs.length; i++) {
5367
+ var num = 1, den = 1;
5368
+ for (var l = 0; l < xs.length; l++) if (l != i) {
5369
+ num = this.mul(num,x0 ^ xs[l]);
5370
+ den = this.mul(den,xs[i] ^ xs[l]);
5371
+ }
5372
+ w[i] = this.div(num,den);
5373
+ }
5374
+ return w;
5375
+ },
5376
+ combine: function(w,ys,len) {
5377
+ var rs = new Uint8Array(len);
5378
+ for (var j = 0; j < len; j++) {
5379
+ var acc = 0;
5380
+ for (var i = 0; i < w.length; i++) acc ^= this.mul(w[i],ys[i][j]);
5381
+ rs[j] = acc;
5382
+ }
5383
+ return rs;
5384
+ },
5385
+ explode: function(sc,ct,optns) {
5386
+ var self = this;
5387
+ if (ct > 255) return Promise.reject(new libVES.Error('InvalidValue','GF(256) Shamir supports at most 255 shares'));
5388
+ var n = this.size;
5389
+ var L = sc.length;
5390
+ var rnd = new Uint8Array(L * (n - 1));
5391
+ if (n > 1) crypto.getRandomValues(rnd);
5392
+ var rs = [];
5393
+ for (var x = 1; x <= ct; x++) {
5394
+ var val = new Uint8Array(L);
5395
+ for (var j = 0; j < L; j++) {
5396
+ var acc = (n > 1) ? rnd[(n - 2) * L + j] : 0;
5397
+ for (var k = n - 2; k >= 1; k--) acc = self.mul(acc,x) ^ rnd[(k - 1) * L + j];
5398
+ val[j] = self.mul(acc,x) ^ sc[j];
5399
+ }
5400
+ rs.push({
5401
+ meta: (function(m) {
5402
+ if (optns) {
5403
+ if (optns.t != null) m.t = optns.t;
5404
+ if (optns.shadow) for (var key in optns.shadow) m[key] = optns.shadow[key];
5405
+ }
5406
+ return m;
5407
+ })({
5408
+ v: self.tag,
5409
+ n: n,
5410
+ b: x
5411
+ }),
5412
+ value: val
5413
+ });
5414
+ }
5415
+ return Promise.resolve(rs);
5416
+ },
5417
+ implode: function(tokens,then,okfn) {
5418
+ var self = this;
5419
+ var n = this.size;
5420
+ if (tokens.length < n) return Promise.reject(new libVES.Error('Internal','Insufficient number of tokens to unscramble'));
5421
+ var xs = [], ys = [];
5422
+ for (var i = 0; i < n; i++) {
5423
+ xs.push(Number(tokens[i].meta.b));
5424
+ ys.push(tokens[i].value);
5425
+ }
5426
+ var L = ys[0].length;
5427
+ var rs = Promise.resolve(self.combine(self.weights(xs,0),ys,L));
5428
+ if (then) rs = rs.then(then);
5429
+ if (okfn) rs = rs.then(function(sc) {
5430
+ for (var i = 0; i < tokens.length; i++) {
5431
+ var ok = i < n || !libVES.Math.cmp(tokens[i].value,self.combine(self.weights(xs,Number(tokens[i].meta.b)),ys,L));
5432
+ okfn(tokens[i],ok,i);
5433
+ }
5434
+ return sc;
5435
+ });
5436
+ return rs;
5437
+ }
5438
+ };
5310
5439
  libVES.Scramble.algo = {
5311
- 'RDX1.2': libVES.Scramble.RDX
5440
+ 'RDX1.2': libVES.Scramble.RDX12,
5441
+ 'SSS1': libVES.Scramble.SSS
5312
5442
  };
5313
5443
 
5314
5444
  libVES.Recovery = function(vaultKey, myItems) {
@@ -6532,7 +6662,10 @@ libVES.Algo.OQS.MLKEM = {
6532
6662
  export: function(data, optns) {
6533
6663
  var spec = this.findSpec(data.algo);
6534
6664
  if (!spec) return null;
6535
- if (data.priv) return libVES.Util.PKCS8.encode8(this.exportPriv(spec, data.pub, data.priv), optns);
6665
+ if (data.priv) {
6666
+ var encrypting = !(optns && optns.opentext);
6667
+ return libVES.Util.PKCS8.encode8(this.exportPriv(spec, encrypting ? null : data.pub, data.priv), optns);
6668
+ }
6536
6669
  return libVES.Util.PEM.encode(this.exportPub(spec, data.pub), 'PUBLIC KEY');
6537
6670
  },
6538
6671
  bind: function(spec) {
@@ -7771,4 +7904,4 @@ libVES.KeyStore.flags = function(input) {
7771
7904
  );
7772
7905
  return {};
7773
7906
  };
7774
- libVES.version = '3.1.0';
7907
+ libVES.version = '3.2.0';
package/libVES.node.js CHANGED
@@ -32,7 +32,7 @@
32
32
  *
33
33
  * @title libVES
34
34
  * @dev A JavaScript end-to-end encryption interface to VESvault REST API
35
- * @version 3.1.0
35
+ * @version 3.2.0
36
36
  *
37
37
  * @dev Official source code: https://github.com/vesvault/libVES
38
38
  *
@@ -6233,6 +6233,7 @@ if (typeof(libVES) != 'function') function libVES(optns) {
6233
6233
  else throw new libVES.Error('InvalidValue','Required parameters: user || domain');
6234
6234
  this.unlockedKeys = {};
6235
6235
  this.pendingKeys = {};
6236
+ this.attnErrors = [];
6236
6237
  }
6237
6238
 
6238
6239
  libVES.prototype = {
@@ -6431,7 +6432,9 @@ libVES.prototype = {
6431
6432
  return cryptoKey;
6432
6433
  });
6433
6434
  }).then(function(ck) {
6434
- return self.handleAttn().catch(function() {}).then(function() {
6435
+ return self.handleAttn().catch(function(e) {
6436
+ self.logAttnError(e);
6437
+ }).then(function() {
6435
6438
  return ck;
6436
6439
  });
6437
6440
  });
@@ -7034,6 +7037,16 @@ libVES.prototype = {
7034
7037
  });
7035
7038
  });
7036
7039
  },
7040
+ attnErrors: null,
7041
+ logAttnError: function(error, vaultKey) {
7042
+ if (!this.attnErrors) this.attnErrors = [];
7043
+ var rec = {error: error, at: new Date()};
7044
+ if (vaultKey !== undefined) rec.vaultKey = vaultKey;
7045
+ this.attnErrors.push(rec);
7046
+ if (this.attnErrors.length > 64) this.attnErrors.shift();
7047
+ try { console.error('libVES attn error:', error, vaultKey); } catch (e) {}
7048
+ return rec;
7049
+ },
7037
7050
  getAttn: function() {
7038
7051
  var self = this;
7039
7052
  var rs = {};
@@ -7056,7 +7069,6 @@ libVES.prototype = {
7056
7069
  attnVaultKeys: function(vkeys) {
7057
7070
  var self = this;
7058
7071
  return Promise.all(vkeys.map(function(vkey, i) {
7059
- console.log('attnVaultKeys:', vkey);
7060
7072
  return vkey.getType().then(function(type) {
7061
7073
  switch (type) {
7062
7074
  case 'temp':
@@ -7092,6 +7104,8 @@ libVES.prototype = {
7092
7104
  return rcv.recover();
7093
7105
  });
7094
7106
  }
7107
+ }).catch(function(e) {
7108
+ return self.logAttnError(e, vkey);
7095
7109
  });
7096
7110
  }));
7097
7111
  },
@@ -9617,6 +9631,15 @@ libVES.Scramble = {
9617
9631
  }
9618
9632
  };
9619
9633
  libVES.Scramble.RDX.prototype = {
9634
+ explode: function(sc,ct,optns) {
9635
+ var impl = (optns && optns.v && libVES.Scramble.algo[optns.v]) || (ct <= 255 ? libVES.Scramble.SSS : libVES.Scramble.RDX12);
9636
+ return new impl(this.size).explode(sc,ct,optns);
9637
+ }
9638
+ };
9639
+ libVES.Scramble.RDX12 = function(x) {
9640
+ this.size = x;
9641
+ };
9642
+ libVES.Scramble.RDX12.prototype = {
9620
9643
  tag: 'RDX1.2',
9621
9644
  name: 'RDX 1.2 Shamir',
9622
9645
  getBases: function(n) {
@@ -9758,8 +9781,115 @@ libVES.Scramble.RDX.prototype = {
9758
9781
  return f([0]);
9759
9782
  }
9760
9783
  };
9784
+ libVES.Scramble.SSS = function(x) {
9785
+ this.size = x;
9786
+ };
9787
+ libVES.Scramble.SSS.prototype = {
9788
+ tag: 'SSS1',
9789
+ name: 'Shamir GF(256)',
9790
+ gf: function() {
9791
+ var g = libVES.Scramble.SSS._gf;
9792
+ if (g) return g;
9793
+ var exp = new Uint8Array(512);
9794
+ var log = new Uint8Array(256);
9795
+ for (var a = 1, i = 0; i < 255; i++) {
9796
+ exp[i] = a;
9797
+ log[a] = i;
9798
+ var d = a << 1;
9799
+ if (d & 0x100) d ^= 0x11b;
9800
+ a = d ^ a;
9801
+ }
9802
+ for (var j = 255; j < 512; j++) exp[j] = exp[j - 255];
9803
+ return libVES.Scramble.SSS._gf = {exp: exp, log: log};
9804
+ },
9805
+ mul: function(a,b) {
9806
+ if (!a || !b) return 0;
9807
+ var g = this.gf();
9808
+ return g.exp[g.log[a] + g.log[b]];
9809
+ },
9810
+ div: function(a,b) {
9811
+ if (!a) return 0;
9812
+ var g = this.gf();
9813
+ return g.exp[g.log[a] + 255 - g.log[b]];
9814
+ },
9815
+ weights: function(xs,x0) {
9816
+ var w = [];
9817
+ for (var i = 0; i < xs.length; i++) {
9818
+ var num = 1, den = 1;
9819
+ for (var l = 0; l < xs.length; l++) if (l != i) {
9820
+ num = this.mul(num,x0 ^ xs[l]);
9821
+ den = this.mul(den,xs[i] ^ xs[l]);
9822
+ }
9823
+ w[i] = this.div(num,den);
9824
+ }
9825
+ return w;
9826
+ },
9827
+ combine: function(w,ys,len) {
9828
+ var rs = new Uint8Array(len);
9829
+ for (var j = 0; j < len; j++) {
9830
+ var acc = 0;
9831
+ for (var i = 0; i < w.length; i++) acc ^= this.mul(w[i],ys[i][j]);
9832
+ rs[j] = acc;
9833
+ }
9834
+ return rs;
9835
+ },
9836
+ explode: function(sc,ct,optns) {
9837
+ var self = this;
9838
+ if (ct > 255) return Promise.reject(new libVES.Error('InvalidValue','GF(256) Shamir supports at most 255 shares'));
9839
+ var n = this.size;
9840
+ var L = sc.length;
9841
+ var rnd = new Uint8Array(L * (n - 1));
9842
+ if (n > 1) crypto.getRandomValues(rnd);
9843
+ var rs = [];
9844
+ for (var x = 1; x <= ct; x++) {
9845
+ var val = new Uint8Array(L);
9846
+ for (var j = 0; j < L; j++) {
9847
+ var acc = (n > 1) ? rnd[(n - 2) * L + j] : 0;
9848
+ for (var k = n - 2; k >= 1; k--) acc = self.mul(acc,x) ^ rnd[(k - 1) * L + j];
9849
+ val[j] = self.mul(acc,x) ^ sc[j];
9850
+ }
9851
+ rs.push({
9852
+ meta: (function(m) {
9853
+ if (optns) {
9854
+ if (optns.t != null) m.t = optns.t;
9855
+ if (optns.shadow) for (var key in optns.shadow) m[key] = optns.shadow[key];
9856
+ }
9857
+ return m;
9858
+ })({
9859
+ v: self.tag,
9860
+ n: n,
9861
+ b: x
9862
+ }),
9863
+ value: val
9864
+ });
9865
+ }
9866
+ return Promise.resolve(rs);
9867
+ },
9868
+ implode: function(tokens,then,okfn) {
9869
+ var self = this;
9870
+ var n = this.size;
9871
+ if (tokens.length < n) return Promise.reject(new libVES.Error('Internal','Insufficient number of tokens to unscramble'));
9872
+ var xs = [], ys = [];
9873
+ for (var i = 0; i < n; i++) {
9874
+ xs.push(Number(tokens[i].meta.b));
9875
+ ys.push(tokens[i].value);
9876
+ }
9877
+ var L = ys[0].length;
9878
+ var rs = Promise.resolve(self.combine(self.weights(xs,0),ys,L));
9879
+ if (then) rs = rs.then(then);
9880
+ if (okfn) rs = rs.then(function(sc) {
9881
+ for (var i = 0; i < tokens.length; i++) {
9882
+ var ok = i < n || !libVES.Math.cmp(tokens[i].value,self.combine(self.weights(xs,Number(tokens[i].meta.b)),ys,L));
9883
+ okfn(tokens[i],ok,i);
9884
+ }
9885
+ return sc;
9886
+ });
9887
+ return rs;
9888
+ }
9889
+ };
9761
9890
  libVES.Scramble.algo = {
9762
- 'RDX1.2': libVES.Scramble.RDX
9891
+ 'RDX1.2': libVES.Scramble.RDX12,
9892
+ 'SSS1': libVES.Scramble.SSS
9763
9893
  };
9764
9894
 
9765
9895
  libVES.Recovery = function(vaultKey, myItems) {
@@ -10983,7 +11113,10 @@ libVES.Algo.OQS.MLKEM = {
10983
11113
  export: function(data, optns) {
10984
11114
  var spec = this.findSpec(data.algo);
10985
11115
  if (!spec) return null;
10986
- if (data.priv) return libVES.Util.PKCS8.encode8(this.exportPriv(spec, data.pub, data.priv), optns);
11116
+ if (data.priv) {
11117
+ var encrypting = !(optns && optns.opentext);
11118
+ return libVES.Util.PKCS8.encode8(this.exportPriv(spec, encrypting ? null : data.pub, data.priv), optns);
11119
+ }
10987
11120
  return libVES.Util.PEM.encode(this.exportPub(spec, data.pub), 'PUBLIC KEY');
10988
11121
  },
10989
11122
  bind: function(spec) {
@@ -12222,6 +12355,6 @@ libVES.KeyStore.flags = function(input) {
12222
12355
  );
12223
12356
  return {};
12224
12357
  };
12225
- libVES.version = '3.1.0';
12358
+ libVES.version = '3.2.0';
12226
12359
 
12227
12360
  module.exports = libVES;
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "libves",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Recoverable end-to-end encryption for browser and Node — key management, sharing, and key recovery without exposing keys or plaintext",
5
5
  "main": "libVES.node.js",
6
6
  "browser": "libVES.js",
7
7
  "scripts": {
8
- "test": "echo \"No test defined\" && exit 1"
8
+ "build": "node build.js",
9
+ "build:min": "node build.js --minify",
10
+ "prepare": "node build.js",
11
+ "test": "echo \"tests/ require two live VES accounts - see tests/ and tests/vestest.conf.example.js\" && exit 0"
9
12
  },
10
13
  "files": [
11
14
  "libVES.js",