hypercore 11.0.47 → 11.1.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 +0 -4
- package/index.js +59 -20
- package/lib/caps.js +2 -2
- package/lib/core.js +0 -3
- package/lib/messages.js +34 -12
- package/lib/replicator.js +1 -0
- package/lib/session-state.js +8 -1
- package/lib/verifier.js +23 -4
- package/package.json +2 -1
- package/lib/block-encryption.js +0 -80
package/README.md
CHANGED
|
@@ -425,10 +425,6 @@ In contrast to `core.key` this key does not allow you to verify the data but can
|
|
|
425
425
|
|
|
426
426
|
Populated after `ready` has been emitted. Will be `null` before the event.
|
|
427
427
|
|
|
428
|
-
#### `core.encryptionKey`
|
|
429
|
-
|
|
430
|
-
Buffer containing the optional block encryption key of this core. Will be `null` unless block encryption is enabled.
|
|
431
|
-
|
|
432
428
|
#### `core.length`
|
|
433
429
|
|
|
434
430
|
How many blocks of data are available on this core.
|
package/index.js
CHANGED
|
@@ -3,15 +3,16 @@ const isOptions = require('is-options')
|
|
|
3
3
|
const crypto = require('hypercore-crypto')
|
|
4
4
|
const CoreStorage = require('hypercore-storage')
|
|
5
5
|
const c = require('compact-encoding')
|
|
6
|
+
const sodium = require('sodium-universal')
|
|
6
7
|
const b4a = require('b4a')
|
|
7
8
|
const NoiseSecretStream = require('@hyperswarm/secret-stream')
|
|
9
|
+
const HypercoreEncryption = require('hypercore-encryption')
|
|
8
10
|
const Protomux = require('protomux')
|
|
9
11
|
const id = require('hypercore-id-encoding')
|
|
10
12
|
const safetyCatch = require('safety-catch')
|
|
11
13
|
const unslab = require('unslab')
|
|
12
14
|
|
|
13
15
|
const Core = require('./lib/core')
|
|
14
|
-
const BlockEncryption = require('./lib/block-encryption')
|
|
15
16
|
const Info = require('./lib/info')
|
|
16
17
|
const Download = require('./lib/download')
|
|
17
18
|
const caps = require('./lib/caps')
|
|
@@ -149,7 +150,7 @@ class Hypercore extends EventEmitter {
|
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
static blockEncryptionKey (key, encryptionKey) {
|
|
152
|
-
return
|
|
153
|
+
return HypercoreEncryption.blockEncryptionKey(key, encryptionKey)
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
static getProtocolMuxer (stream) {
|
|
@@ -233,10 +234,24 @@ class Hypercore extends EventEmitter {
|
|
|
233
234
|
return s
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
setEncryptionKey (encryptionKey, opts) {
|
|
238
|
+
const encryption = this._getLegacyEncryption(encryptionKey, !!(opts && opts.block))
|
|
239
|
+
return this.setEncryption(encryption, opts)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async setEncryption (encryption, opts) {
|
|
237
243
|
if (!this.opened) await this.opening
|
|
238
|
-
|
|
239
|
-
|
|
244
|
+
|
|
245
|
+
if (encryption === null) {
|
|
246
|
+
this.encryption = encryption
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!HypercoreEncryption.isHypercoreEncryption(encryption)) {
|
|
251
|
+
throw new Error('Expected hypercore encryption provider')
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
this.encryption = encryption
|
|
240
255
|
if (!this.core.encryption) this.core.encryption = this.encryption
|
|
241
256
|
}
|
|
242
257
|
|
|
@@ -290,7 +305,7 @@ class Hypercore extends EventEmitter {
|
|
|
290
305
|
if (this.state !== null) this.state.removeSession(this)
|
|
291
306
|
|
|
292
307
|
this.closed = true
|
|
293
|
-
this.emit('close'
|
|
308
|
+
this.emit('close')
|
|
294
309
|
throw err
|
|
295
310
|
}
|
|
296
311
|
|
|
@@ -313,9 +328,14 @@ class Hypercore extends EventEmitter {
|
|
|
313
328
|
|
|
314
329
|
if (this.keyPair === null) this.keyPair = opts.keyPair || this.core.header.keyPair
|
|
315
330
|
|
|
316
|
-
if (!this.core.encryption
|
|
331
|
+
if (!this.core.encryption) {
|
|
317
332
|
const e = getEncryptionOption(opts)
|
|
318
|
-
|
|
333
|
+
|
|
334
|
+
if (HypercoreEncryption.isHypercoreEncryption(e)) {
|
|
335
|
+
this.core.encryption = e
|
|
336
|
+
} else if (e) {
|
|
337
|
+
this.core.encryption = this._getLegacyEncryption(e.key, e.block)
|
|
338
|
+
}
|
|
319
339
|
}
|
|
320
340
|
|
|
321
341
|
const parent = opts.parent || null
|
|
@@ -476,14 +496,14 @@ class Hypercore extends EventEmitter {
|
|
|
476
496
|
if (this.core.hasSession()) {
|
|
477
497
|
// emit "fake" close as this is a session
|
|
478
498
|
this.closed = true
|
|
479
|
-
this.emit('close'
|
|
499
|
+
this.emit('close')
|
|
480
500
|
return
|
|
481
501
|
}
|
|
482
502
|
|
|
483
503
|
if (this.core.autoClose) await this.core.close()
|
|
484
504
|
|
|
485
505
|
this.closed = true
|
|
486
|
-
this.emit('close'
|
|
506
|
+
this.emit('close')
|
|
487
507
|
}
|
|
488
508
|
|
|
489
509
|
async commit (session, opts) {
|
|
@@ -576,10 +596,6 @@ class Hypercore extends EventEmitter {
|
|
|
576
596
|
return this.opened === false ? [] : this.core.replicator.peers
|
|
577
597
|
}
|
|
578
598
|
|
|
579
|
-
get encryptionKey () {
|
|
580
|
-
return this.encryption && this.encryption.key
|
|
581
|
-
}
|
|
582
|
-
|
|
583
599
|
get padding () {
|
|
584
600
|
return this.encryption === null ? 0 : this.encryption.padding
|
|
585
601
|
}
|
|
@@ -757,8 +773,8 @@ class Hypercore extends EventEmitter {
|
|
|
757
773
|
block = b4a.from(block)
|
|
758
774
|
|
|
759
775
|
if (this.encryption.compat !== this.core.compat) this._updateEncryption()
|
|
760
|
-
|
|
761
|
-
|
|
776
|
+
|
|
777
|
+
await this.encryption.decrypt(index, block)
|
|
762
778
|
}
|
|
763
779
|
|
|
764
780
|
return this._decode(encoding, block)
|
|
@@ -906,7 +922,8 @@ class Hypercore extends EventEmitter {
|
|
|
906
922
|
|
|
907
923
|
blocks = Array.isArray(blocks) ? blocks : [blocks]
|
|
908
924
|
|
|
909
|
-
const preappend = this.
|
|
925
|
+
const preappend = this.encryption && this._preappend
|
|
926
|
+
if (preappend) await this.encryption.ready()
|
|
910
927
|
|
|
911
928
|
const buffers = this.encodeBatch !== null ? this.encodeBatch(blocks) : new Array(blocks.length)
|
|
912
929
|
|
|
@@ -1037,9 +1054,22 @@ class Hypercore extends EventEmitter {
|
|
|
1037
1054
|
|
|
1038
1055
|
_updateEncryption () {
|
|
1039
1056
|
const e = this.encryption
|
|
1040
|
-
|
|
1057
|
+
if (HypercoreEncryption.isHypercoreEncryption(e)) return
|
|
1058
|
+
|
|
1059
|
+
this.encryption = this._getLegacyEncryption(e.key, e.block)
|
|
1060
|
+
|
|
1041
1061
|
if (e === this.core.encryption) this.core.encryption = this.encryption
|
|
1042
1062
|
}
|
|
1063
|
+
|
|
1064
|
+
_getLegacyEncryption (encryptionKey, block) {
|
|
1065
|
+
if (!encryptionKey) return null
|
|
1066
|
+
|
|
1067
|
+
const blockKey = block
|
|
1068
|
+
? encryptionKey
|
|
1069
|
+
: getLegacyBlockKey(this.key, encryptionKey, this.core.compat)
|
|
1070
|
+
|
|
1071
|
+
return HypercoreEncryption.createLegacyProvider(blockKey)
|
|
1072
|
+
}
|
|
1043
1073
|
}
|
|
1044
1074
|
|
|
1045
1075
|
module.exports = Hypercore
|
|
@@ -1052,14 +1082,14 @@ function toHex (buf) {
|
|
|
1052
1082
|
return buf && b4a.toString(buf, 'hex')
|
|
1053
1083
|
}
|
|
1054
1084
|
|
|
1055
|
-
function preappend (blocks) {
|
|
1085
|
+
async function preappend (blocks) {
|
|
1056
1086
|
const offset = this.state.length
|
|
1057
1087
|
const fork = this.state.encryptionFork
|
|
1058
1088
|
|
|
1059
1089
|
if (this.encryption.compat !== this.core.compat) this._updateEncryption()
|
|
1060
1090
|
|
|
1061
1091
|
for (let i = 0; i < blocks.length; i++) {
|
|
1062
|
-
this.encryption.encrypt(offset + i, blocks[i], fork)
|
|
1092
|
+
await this.encryption.encrypt(offset + i, blocks[i], fork)
|
|
1063
1093
|
}
|
|
1064
1094
|
}
|
|
1065
1095
|
|
|
@@ -1126,3 +1156,12 @@ function getEncryptionOption (opts) {
|
|
|
1126
1156
|
if (!opts.encryption) return null
|
|
1127
1157
|
return b4a.isBuffer(opts.encryption) ? { key: opts.encryption } : opts.encryption
|
|
1128
1158
|
}
|
|
1159
|
+
|
|
1160
|
+
function getLegacyBlockKey (hypercoreKey, encryptionKey, compat) {
|
|
1161
|
+
const key = b4a.alloc(HypercoreEncryption.KEYBYTES)
|
|
1162
|
+
|
|
1163
|
+
if (compat) sodium.crypto_generichash_batch(key, [encryptionKey], hypercoreKey)
|
|
1164
|
+
else sodium.crypto_generichash_batch(key, [caps.LEGACY_BLOCK_ENCRYPTION, hypercoreKey, encryptionKey])
|
|
1165
|
+
|
|
1166
|
+
return key
|
|
1167
|
+
}
|
package/lib/caps.js
CHANGED
|
@@ -12,12 +12,12 @@ const [
|
|
|
12
12
|
REPLICATE_RESPONDER,
|
|
13
13
|
MANIFEST,
|
|
14
14
|
DEFAULT_NAMESPACE,
|
|
15
|
-
|
|
15
|
+
LEGACY_BLOCK_ENCRYPTION
|
|
16
16
|
] = crypto.namespace('hypercore', 6)
|
|
17
17
|
|
|
18
18
|
exports.MANIFEST = MANIFEST
|
|
19
19
|
exports.DEFAULT_NAMESPACE = DEFAULT_NAMESPACE
|
|
20
|
-
exports.
|
|
20
|
+
exports.LEGACY_BLOCK_ENCRYPTION = LEGACY_BLOCK_ENCRYPTION
|
|
21
21
|
|
|
22
22
|
exports.replicate = function (isInitiator, key, handshakeHash) {
|
|
23
23
|
const out = b4a.allocUnsafe(32)
|
package/lib/core.js
CHANGED
|
@@ -39,7 +39,6 @@ module.exports = class Core {
|
|
|
39
39
|
this.verifier = null
|
|
40
40
|
this.truncating = 0
|
|
41
41
|
this.updating = false
|
|
42
|
-
this.unencrypted = false
|
|
43
42
|
this.skipBitfield = null
|
|
44
43
|
this.globalCache = opts.globalCache || null
|
|
45
44
|
this.autoClose = opts.autoClose !== false
|
|
@@ -271,7 +270,6 @@ module.exports = class Core {
|
|
|
271
270
|
// to unslab
|
|
272
271
|
if (header.manifest) {
|
|
273
272
|
header.manifest = Verifier.createManifest(header.manifest)
|
|
274
|
-
this.unencrypted = header.manifest.unencrypted
|
|
275
273
|
}
|
|
276
274
|
|
|
277
275
|
const verifier = header.manifest ? new Verifier(header.key, header.manifest, { crypto, legacy }) : null
|
|
@@ -326,7 +324,6 @@ module.exports = class Core {
|
|
|
326
324
|
if (verifier.prologue) this.state.prologue = Object.assign({}, verifier.prologue)
|
|
327
325
|
|
|
328
326
|
this.manifest = this.header.manifest = manifest
|
|
329
|
-
this.unencrypted = this.manifest.unencrypted
|
|
330
327
|
|
|
331
328
|
tx.setAuth({
|
|
332
329
|
key: this.header.key,
|
package/lib/messages.js
CHANGED
|
@@ -6,6 +6,10 @@ const unslab = require('unslab')
|
|
|
6
6
|
|
|
7
7
|
const EMPTY = b4a.alloc(0)
|
|
8
8
|
|
|
9
|
+
const MANIFEST_PATCH = 0b00000001
|
|
10
|
+
const MANIFEST_PROLOGUE = 0b00000010
|
|
11
|
+
const MANIFEST_LINKED = 0b00000100
|
|
12
|
+
|
|
9
13
|
const hashes = {
|
|
10
14
|
preencode (state, m) {
|
|
11
15
|
state.end++ // small uint
|
|
@@ -137,7 +141,7 @@ const manifestv0 = {
|
|
|
137
141
|
hash: c.fixed32.decode(state),
|
|
138
142
|
length: 0
|
|
139
143
|
},
|
|
140
|
-
|
|
144
|
+
linked: []
|
|
141
145
|
}
|
|
142
146
|
}
|
|
143
147
|
|
|
@@ -149,7 +153,7 @@ const manifestv0 = {
|
|
|
149
153
|
quorum: 1,
|
|
150
154
|
signers: [signer.decode(state)],
|
|
151
155
|
prologue: null,
|
|
152
|
-
|
|
156
|
+
linked: []
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
159
|
|
|
@@ -162,11 +166,13 @@ const manifestv0 = {
|
|
|
162
166
|
quorum: c.uint.decode(state),
|
|
163
167
|
signers: signerArray.decode(state),
|
|
164
168
|
prologue: null,
|
|
165
|
-
|
|
169
|
+
linked: []
|
|
166
170
|
}
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
173
|
|
|
174
|
+
const fixed32Array = c.array(c.fixed32)
|
|
175
|
+
|
|
170
176
|
const manifest = exports.manifest = {
|
|
171
177
|
preencode (state, m) {
|
|
172
178
|
state.end++ // version
|
|
@@ -178,37 +184,53 @@ const manifest = exports.manifest = {
|
|
|
178
184
|
c.uint.preencode(state, m.quorum)
|
|
179
185
|
signerArray.preencode(state, m.signers)
|
|
180
186
|
if (m.prologue) prologue.preencode(state, m.prologue)
|
|
187
|
+
|
|
188
|
+
if (m.linked) {
|
|
189
|
+
fixed32Array.preencode(state, m.linked)
|
|
190
|
+
}
|
|
181
191
|
},
|
|
182
192
|
encode (state, m) {
|
|
183
193
|
c.uint.encode(state, m.version)
|
|
184
194
|
if (m.version === 0) return manifestv0.encode(state, m)
|
|
185
195
|
|
|
186
|
-
|
|
196
|
+
let flags = 0
|
|
197
|
+
if (m.allowPatch) flags |= MANIFEST_PATCH
|
|
198
|
+
if (m.prologue) flags |= MANIFEST_PROLOGUE
|
|
199
|
+
if (m.linked) flags |= MANIFEST_LINKED
|
|
200
|
+
|
|
201
|
+
c.uint.encode(state, flags)
|
|
187
202
|
hashes.encode(state, m.hash)
|
|
188
203
|
|
|
189
204
|
c.uint.encode(state, m.quorum)
|
|
190
205
|
signerArray.encode(state, m.signers)
|
|
191
206
|
if (m.prologue) prologue.encode(state, m.prologue)
|
|
207
|
+
|
|
208
|
+
if (m.linked) {
|
|
209
|
+
fixed32Array.encode(state, m.linked)
|
|
210
|
+
}
|
|
192
211
|
},
|
|
193
212
|
decode (state) {
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
196
|
-
if (
|
|
213
|
+
const version = c.uint.decode(state)
|
|
214
|
+
if (version === 0) return manifestv0.decode(state)
|
|
215
|
+
if (version > 2) throw new Error('Unknown version: ' + version)
|
|
197
216
|
|
|
198
217
|
const flags = c.uint.decode(state)
|
|
199
218
|
const hash = hashes.decode(state)
|
|
200
219
|
const quorum = c.uint.decode(state)
|
|
201
220
|
const signers = signerArray.decode(state)
|
|
202
|
-
|
|
221
|
+
|
|
222
|
+
const hasPatch = (flags & MANIFEST_PATCH) !== 0
|
|
223
|
+
const hasPrologue = (flags & MANIFEST_PROLOGUE) !== 0
|
|
224
|
+
const hasLinked = (flags & MANIFEST_LINKED) !== 0
|
|
203
225
|
|
|
204
226
|
return {
|
|
205
|
-
version
|
|
227
|
+
version,
|
|
206
228
|
hash,
|
|
207
|
-
allowPatch:
|
|
229
|
+
allowPatch: hasPatch,
|
|
208
230
|
quorum,
|
|
209
231
|
signers,
|
|
210
|
-
prologue:
|
|
211
|
-
|
|
232
|
+
prologue: hasPrologue ? prologue.decode(state) : null,
|
|
233
|
+
linked: hasLinked ? fixed32Array.decode(state) : null
|
|
212
234
|
}
|
|
213
235
|
}
|
|
214
236
|
}
|
package/lib/replicator.js
CHANGED
|
@@ -1520,6 +1520,7 @@ module.exports = class Replicator {
|
|
|
1520
1520
|
}
|
|
1521
1521
|
|
|
1522
1522
|
this._downloadingTimer = setTimeout(setDownloadingLater, this._notDownloadingLinger, this, downloading)
|
|
1523
|
+
if (this._downloadingTimer.unref) this._downloadingTimer.unref()
|
|
1523
1524
|
}
|
|
1524
1525
|
|
|
1525
1526
|
setDownloadingNow (downloading) {
|
package/lib/session-state.js
CHANGED
|
@@ -36,6 +36,7 @@ module.exports = class SessionState {
|
|
|
36
36
|
this.signature = treeInfo.signature || null
|
|
37
37
|
|
|
38
38
|
this.snapshotCompatLength = this.isSnapshot() ? Math.min(this.length, this.core.state.length) : -1
|
|
39
|
+
this.lastTruncation = null
|
|
39
40
|
|
|
40
41
|
this.active = 0
|
|
41
42
|
|
|
@@ -230,10 +231,13 @@ module.exports = class SessionState {
|
|
|
230
231
|
this._activeTx = null
|
|
231
232
|
|
|
232
233
|
try {
|
|
233
|
-
|
|
234
|
+
if (!(await tx.flush())) return false
|
|
234
235
|
} finally {
|
|
235
236
|
this._clearActiveBatch()
|
|
236
237
|
}
|
|
238
|
+
|
|
239
|
+
this.lastTruncation = null
|
|
240
|
+
return true
|
|
237
241
|
}
|
|
238
242
|
|
|
239
243
|
_precommit () {
|
|
@@ -246,6 +250,7 @@ module.exports = class SessionState {
|
|
|
246
250
|
try {
|
|
247
251
|
const bitfield = this._pendingBitfield
|
|
248
252
|
this._pendingBitfield = null
|
|
253
|
+
this.lastTruncation = null
|
|
249
254
|
await this.parent._oncommit(this, bitfield)
|
|
250
255
|
} finally {
|
|
251
256
|
this.commiting = false
|
|
@@ -576,6 +581,8 @@ module.exports = class SessionState {
|
|
|
576
581
|
ontruncate (tree, to, from, flushed) {
|
|
577
582
|
const bitfield = { start: to, length: from - to, drop: true }
|
|
578
583
|
|
|
584
|
+
this.lastTruncation = { from, to }
|
|
585
|
+
|
|
579
586
|
if (!flushed) this._updateBitfield(bitfield)
|
|
580
587
|
else if (this.isDefault()) this.core.ontruncate(tree, bitfield)
|
|
581
588
|
|
package/lib/verifier.js
CHANGED
|
@@ -129,7 +129,7 @@ module.exports = class Verifier {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
verify (batch, signature) {
|
|
132
|
-
if (this.version
|
|
132
|
+
if (this.version === 0) {
|
|
133
133
|
return this._verifyCompat(batch, signature)
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -182,7 +182,8 @@ module.exports = class Verifier {
|
|
|
182
182
|
namespace: caps.DEFAULT_NAMESPACE,
|
|
183
183
|
publicKey
|
|
184
184
|
}],
|
|
185
|
-
prologue: null
|
|
185
|
+
prologue: null,
|
|
186
|
+
linked: null
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
|
|
@@ -195,13 +196,13 @@ module.exports = class Verifier {
|
|
|
195
196
|
if (!inp) return null
|
|
196
197
|
|
|
197
198
|
const manifest = {
|
|
198
|
-
version:
|
|
199
|
+
version: getManifestVersion(inp), // only v2 if linked are present
|
|
199
200
|
hash: 'blake2b',
|
|
200
201
|
allowPatch: !!inp.allowPatch,
|
|
201
202
|
quorum: defaultQuorum(inp),
|
|
202
203
|
signers: inp.signers ? inp.signers.map(parseSigner) : [],
|
|
203
204
|
prologue: null,
|
|
204
|
-
|
|
205
|
+
linked: null
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
if (inp.hash && inp.hash !== 'blake2b') throw BAD_ARGUMENT('Only Blake2b hashes are supported')
|
|
@@ -215,6 +216,18 @@ module.exports = class Verifier {
|
|
|
215
216
|
manifest.prologue.hash = unslab(manifest.prologue.hash)
|
|
216
217
|
}
|
|
217
218
|
|
|
219
|
+
if (inp.linked && inp.linked.length) {
|
|
220
|
+
if (manifest.version < 2) throw BAD_ARGUMENT('Invalid field')
|
|
221
|
+
|
|
222
|
+
for (const key of inp.linked) {
|
|
223
|
+
if (!(b4a.isBuffer(key) && key.byteLength === 32)) {
|
|
224
|
+
throw BAD_ARGUMENT('Invalid key')
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
manifest.linked = inp.linked
|
|
229
|
+
}
|
|
230
|
+
|
|
218
231
|
return manifest
|
|
219
232
|
}
|
|
220
233
|
|
|
@@ -311,3 +324,9 @@ function proofToVersion1 (proof) {
|
|
|
311
324
|
patch: proof.patch ? proof.patch.length : 0
|
|
312
325
|
}
|
|
313
326
|
}
|
|
327
|
+
|
|
328
|
+
function getManifestVersion (inp) {
|
|
329
|
+
if (typeof inp.version === 'number') return inp.version
|
|
330
|
+
if (inp.linked && inp.linked.length) return 2
|
|
331
|
+
return 1
|
|
332
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "11.0
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"fast-fifo": "^1.3.0",
|
|
50
50
|
"flat-tree": "^1.9.0",
|
|
51
51
|
"hypercore-crypto": "^3.2.1",
|
|
52
|
+
"hypercore-encryption": "^1.0.0",
|
|
52
53
|
"hypercore-errors": "^1.2.0",
|
|
53
54
|
"hypercore-id-encoding": "^1.2.0",
|
|
54
55
|
"hypercore-storage": "^1.0.0",
|
package/lib/block-encryption.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
const sodium = require('sodium-universal')
|
|
2
|
-
const c = require('compact-encoding')
|
|
3
|
-
const b4a = require('b4a')
|
|
4
|
-
const { BLOCK_ENCRYPTION } = require('./caps')
|
|
5
|
-
|
|
6
|
-
const nonce = b4a.alloc(sodium.crypto_stream_NONCEBYTES)
|
|
7
|
-
|
|
8
|
-
module.exports = class BlockEncryption {
|
|
9
|
-
constructor (encryptionKey, hypercoreKey, { block = false, compat = true } = {}) {
|
|
10
|
-
const subKeys = b4a.alloc(2 * sodium.crypto_stream_KEYBYTES)
|
|
11
|
-
|
|
12
|
-
this.key = encryptionKey
|
|
13
|
-
this.blockKey = block ? encryptionKey : subKeys.subarray(0, sodium.crypto_stream_KEYBYTES)
|
|
14
|
-
this.blindingKey = subKeys.subarray(sodium.crypto_stream_KEYBYTES)
|
|
15
|
-
this.padding = 8
|
|
16
|
-
this.compat = compat
|
|
17
|
-
|
|
18
|
-
if (!block) {
|
|
19
|
-
if (compat) sodium.crypto_generichash_batch(this.blockKey, [encryptionKey], hypercoreKey)
|
|
20
|
-
else sodium.crypto_generichash_batch(this.blockKey, [BLOCK_ENCRYPTION, hypercoreKey, encryptionKey])
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
sodium.crypto_generichash(this.blindingKey, this.blockKey)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
static blockEncryptionKey (hypercoreKey, encryptionKey) {
|
|
27
|
-
const blockKey = b4a.alloc(sodium.crypto_stream_KEYBYTES)
|
|
28
|
-
sodium.crypto_generichash_batch(blockKey, [BLOCK_ENCRYPTION, hypercoreKey, encryptionKey])
|
|
29
|
-
return blockKey
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
encrypt (index, block, fork) {
|
|
33
|
-
const padding = block.subarray(0, this.padding)
|
|
34
|
-
block = block.subarray(this.padding)
|
|
35
|
-
|
|
36
|
-
c.uint64.encode({ start: 0, end: 8, buffer: padding }, fork)
|
|
37
|
-
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
38
|
-
|
|
39
|
-
// Zero out any previous padding.
|
|
40
|
-
nonce.fill(0, 8, 8 + padding.byteLength)
|
|
41
|
-
|
|
42
|
-
// Blind the fork ID, possibly risking reusing the nonce on a reorg of the
|
|
43
|
-
// Hypercore. This is fine as the blinding is best-effort and the latest
|
|
44
|
-
// fork ID shared on replication anyway.
|
|
45
|
-
sodium.crypto_stream_xor(
|
|
46
|
-
padding,
|
|
47
|
-
padding,
|
|
48
|
-
nonce,
|
|
49
|
-
this.blindingKey
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
nonce.set(padding, 8)
|
|
53
|
-
|
|
54
|
-
// The combination of a (blinded) fork ID and a block index is unique for a
|
|
55
|
-
// given Hypercore and is therefore a valid nonce for encrypting the block.
|
|
56
|
-
sodium.crypto_stream_xor(
|
|
57
|
-
block,
|
|
58
|
-
block,
|
|
59
|
-
nonce,
|
|
60
|
-
this.blockKey
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
decrypt (index, block) {
|
|
65
|
-
const padding = block.subarray(0, this.padding)
|
|
66
|
-
block = block.subarray(this.padding)
|
|
67
|
-
|
|
68
|
-
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
69
|
-
|
|
70
|
-
nonce.set(padding, 8)
|
|
71
|
-
|
|
72
|
-
// Decrypt the block using the blinded fork ID.
|
|
73
|
-
sodium.crypto_stream_xor(
|
|
74
|
-
block,
|
|
75
|
-
block,
|
|
76
|
-
nonce,
|
|
77
|
-
this.blockKey
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
}
|