@zip.js/zip.js 2.6.25 → 2.6.28
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 +16 -17
- package/dist/z-worker-fflate.js +1 -1
- package/dist/z-worker-pako.js +1 -1
- package/dist/z-worker.js +1 -1
- package/dist/zip-fs-full.js +5593 -5582
- package/dist/zip-fs-full.min.js +1 -1
- package/dist/zip-fs.js +536 -514
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-full.js +4110 -4099
- package/dist/zip-full.min.js +1 -1
- package/dist/zip-no-worker-deflate.min.js +1 -1
- package/dist/zip-no-worker-inflate.min.js +1 -1
- package/dist/zip-no-worker.min.js +1 -1
- package/dist/zip.js +536 -514
- package/dist/zip.min.js +1 -1
- package/index.d.ts +46 -23
- package/index.js +2 -2
- package/lib/core/codec-interface.js +17 -9
- package/lib/core/codec-pool-worker.js +2 -3
- package/lib/core/codec-pool.js +1 -1
- package/lib/core/configuration.js +29 -8
- package/lib/core/io.js +36 -46
- package/lib/core/streams/aes-crypto-stream.js +87 -62
- package/lib/core/streams/codec-stream.js +4 -3
- package/lib/core/streams/codecs/crc32.js +3 -1
- package/lib/core/streams/codecs/deflate.js +1792 -1796
- package/lib/core/streams/codecs/inflate.js +1828 -1831
- package/lib/core/streams/common-crypto.js +3 -1
- package/lib/core/streams/crc32-stream.js +7 -7
- package/lib/core/streams/zip-crypto-stream.js +13 -14
- package/lib/core/streams/zip-entry-stream.js +42 -58
- package/lib/core/util/cp437-decode.js +6 -2
- package/lib/core/util/decode-text.js +4 -2
- package/lib/core/util/encode-text.js +3 -1
- package/lib/core/util/stream-codec-shim.js +6 -2
- package/lib/core/z-worker-core.js +9 -9
- package/lib/core/zip-entry.js +6 -2
- package/lib/core/zip-reader.js +15 -6
- package/lib/core/zip-writer.js +74 -50
- package/lib/z-worker-bootstrap-fflate.js +1 -1
- package/lib/z-worker-bootstrap-pako.js +1 -1
- package/lib/z-worker-inline-template.js +9 -7
- package/lib/z-worker-inline.js +1 -1
- package/lib/z-worker.js +2 -2
- package/lib/zip-fflate-shim.js +1 -1
- package/lib/zip-fs.js +2 -2
- package/lib/zip-full-fflate.js +2 -2
- package/lib/zip-full.js +4 -4
- package/lib/zip-no-worker-deflate.js +1 -1
- package/lib/zip-no-worker-inflate.js +1 -1
- package/lib/zip-no-worker.js +2 -2
- package/lib/zip.js +2 -2
- package/package.json +5 -2
- package/rollup-fflate.config.dev.js +2 -2
- package/rollup-fflate.config.js +2 -2
- package/rollup.config.dev.js +2 -2
- package/rollup.config.js +2 -2
- package/tests/all/test-streams.js +29 -0
- package/tests/tests-data.js +1 -0
- package/lib/z-worker-inline-template-base64.js +0 -36
package/index.js
CHANGED
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
import Deflate from "./lib/core/streams/codecs/deflate.js";
|
|
32
|
-
import Inflate from "./lib/core/streams/codecs/inflate.js";
|
|
31
|
+
import { Deflate } from "./lib/core/streams/codecs/deflate.js";
|
|
32
|
+
import { Inflate } from "./lib/core/streams/codecs/inflate.js";
|
|
33
33
|
import { configure } from "./lib/core/configuration.js";
|
|
34
34
|
import { getMimeType } from "./lib/core/util/mime-type.js";
|
|
35
35
|
import { terminateWorkers } from "./lib/core/codec-pool.js";
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
ERR_INVALID_PASSWORD,
|
|
36
36
|
ERR_INVALID_SIGNATURE
|
|
37
37
|
} from "./streams/zip-entry-stream.js";
|
|
38
|
+
import { CodecStream } from "./streams/codec-stream.js";
|
|
38
39
|
|
|
39
40
|
const CODEC_DEFLATE = "deflate";
|
|
40
41
|
const CODEC_INFLATE = "inflate";
|
|
@@ -47,6 +48,7 @@ const MESSAGE_CLOSE = "close";
|
|
|
47
48
|
|
|
48
49
|
export {
|
|
49
50
|
Codec,
|
|
51
|
+
getCodecStreamClass,
|
|
50
52
|
CODEC_DEFLATE,
|
|
51
53
|
CODEC_INFLATE,
|
|
52
54
|
ERR_INVALID_SIGNATURE,
|
|
@@ -61,17 +63,16 @@ export {
|
|
|
61
63
|
|
|
62
64
|
class Codec {
|
|
63
65
|
|
|
64
|
-
constructor(
|
|
66
|
+
constructor(readable, writable, options, config) {
|
|
65
67
|
const { codecType } = options;
|
|
66
|
-
let
|
|
68
|
+
let CodecStream;
|
|
67
69
|
if (codecType.startsWith(CODEC_DEFLATE)) {
|
|
68
|
-
|
|
70
|
+
CodecStream = DeflateStream;
|
|
69
71
|
} else if (codecType.startsWith(CODEC_INFLATE)) {
|
|
70
|
-
|
|
72
|
+
CodecStream = InflateStream;
|
|
71
73
|
}
|
|
72
74
|
Object.assign(this, {
|
|
73
|
-
|
|
74
|
-
CodecConstructor,
|
|
75
|
+
CodecStream,
|
|
75
76
|
readable,
|
|
76
77
|
writable,
|
|
77
78
|
options,
|
|
@@ -81,14 +82,13 @@ class Codec {
|
|
|
81
82
|
|
|
82
83
|
async run() {
|
|
83
84
|
const {
|
|
84
|
-
|
|
85
|
-
CodecConstructor,
|
|
85
|
+
CodecStream,
|
|
86
86
|
readable,
|
|
87
87
|
writable,
|
|
88
88
|
options,
|
|
89
89
|
config
|
|
90
90
|
} = this;
|
|
91
|
-
const stream = new
|
|
91
|
+
const stream = new CodecStream(options, config);
|
|
92
92
|
let size = 0;
|
|
93
93
|
await readable
|
|
94
94
|
.pipeThrough(stream)
|
|
@@ -104,4 +104,12 @@ class Codec {
|
|
|
104
104
|
const { signature } = stream;
|
|
105
105
|
return { size, signature };
|
|
106
106
|
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getCodecStreamClass(Codec) {
|
|
110
|
+
return class extends CodecStream {
|
|
111
|
+
constructor(algorithm, options) {
|
|
112
|
+
super(Codec, options);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
107
115
|
}
|
|
@@ -50,10 +50,9 @@ class CodecWorker {
|
|
|
50
50
|
|
|
51
51
|
constructor(workerData, stream, workerOptions, onTaskFinished) {
|
|
52
52
|
const { readable, writable } = stream;
|
|
53
|
-
const { options, config, streamOptions, useWebWorkers, transferStreams, scripts
|
|
53
|
+
const { options, config, streamOptions, useWebWorkers, transferStreams, scripts } = workerOptions;
|
|
54
54
|
Object.assign(workerData, {
|
|
55
55
|
busy: true,
|
|
56
|
-
codecConstructor,
|
|
57
56
|
readable,
|
|
58
57
|
writable,
|
|
59
58
|
options: Object.assign({}, options),
|
|
@@ -106,7 +105,7 @@ async function callHandler(handler, ...parameters) {
|
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
function createWorkerInterface(workerData, config) {
|
|
109
|
-
const interfaceCodec = new Codec(workerData.
|
|
108
|
+
const interfaceCodec = new Codec(workerData.readable, workerData.writable, workerData.options, config);
|
|
110
109
|
const { onTaskFinished } = workerData;
|
|
111
110
|
const codec = {
|
|
112
111
|
async run() {
|
package/lib/core/codec-pool.js
CHANGED
|
@@ -58,7 +58,7 @@ async function runWorker(stream, workerOptions) {
|
|
|
58
58
|
const streamCopy = !compressed && !signed && !encrypted && !workerOptions.transferStreams;
|
|
59
59
|
workerOptions.useWebWorkers = !streamCopy && (useWebWorkers || (useWebWorkers === undefined && config.useWebWorkers));
|
|
60
60
|
workerOptions.scripts = workerOptions.useWebWorkers && workerScripts ? workerScripts[codecType] : [];
|
|
61
|
-
options.useCompressionStream = useCompressionStream === undefined
|
|
61
|
+
options.useCompressionStream = useCompressionStream || (useCompressionStream === undefined && config.useCompressionStream);
|
|
62
62
|
let worker;
|
|
63
63
|
if (pool.length < config.maxWorkers) {
|
|
64
64
|
const workerData = { indexWorker };
|
|
@@ -26,16 +26,29 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global navigator */
|
|
29
|
+
/* global navigator, CompressionStream, DecompressionStream */
|
|
30
|
+
|
|
31
|
+
import { getCodecStreamClass } from "./codec-interface.js";
|
|
30
32
|
|
|
31
33
|
const MINIMUM_CHUNK_SIZE = 64;
|
|
32
|
-
const
|
|
34
|
+
const UNDEFINED_VALUE = undefined;
|
|
35
|
+
let maxWorkers = 2;
|
|
36
|
+
try {
|
|
37
|
+
if (typeof navigator != "undefined" && navigator.hardwareConcurrency) {
|
|
38
|
+
maxWorkers = navigator.hardwareConcurrency;
|
|
39
|
+
}
|
|
40
|
+
} catch (_error) {
|
|
41
|
+
// ignored
|
|
42
|
+
}
|
|
33
43
|
const DEFAULT_CONFIGURATION = {
|
|
34
44
|
chunkSize: 512 * 1024,
|
|
35
|
-
maxWorkers
|
|
45
|
+
maxWorkers,
|
|
36
46
|
terminateWorkerTimeout: 5000,
|
|
37
47
|
useWebWorkers: true,
|
|
38
|
-
|
|
48
|
+
useCompressionStream: true,
|
|
49
|
+
workerScripts: undefined,
|
|
50
|
+
CompressionStreamNative: typeof CompressionStream != "undefined" && CompressionStream,
|
|
51
|
+
DecompressionStreamNative: typeof DecompressionStream != "undefined" && DecompressionStream
|
|
39
52
|
};
|
|
40
53
|
|
|
41
54
|
const config = Object.assign({}, DEFAULT_CONFIGURATION);
|
|
@@ -64,6 +77,8 @@ function configure(configuration) {
|
|
|
64
77
|
useWebWorkers,
|
|
65
78
|
Deflate,
|
|
66
79
|
Inflate,
|
|
80
|
+
CompressionStream,
|
|
81
|
+
DecompressionStream,
|
|
67
82
|
workerScripts
|
|
68
83
|
} = configuration;
|
|
69
84
|
setIfDefined("baseURL", baseURL);
|
|
@@ -72,9 +87,15 @@ function configure(configuration) {
|
|
|
72
87
|
setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
|
|
73
88
|
setIfDefined("useCompressionStream", useCompressionStream);
|
|
74
89
|
setIfDefined("useWebWorkers", useWebWorkers);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
if (Deflate) {
|
|
91
|
+
config.CompressionStream = getCodecStreamClass(Deflate);
|
|
92
|
+
}
|
|
93
|
+
if (Inflate) {
|
|
94
|
+
config.DecompressionStream = getCodecStreamClass(Inflate);
|
|
95
|
+
}
|
|
96
|
+
setIfDefined("CompressionStream", CompressionStream);
|
|
97
|
+
setIfDefined("DecompressionStream", DecompressionStream);
|
|
98
|
+
if (workerScripts !== UNDEFINED_VALUE) {
|
|
78
99
|
const { deflate, inflate } = workerScripts;
|
|
79
100
|
if (deflate || inflate) {
|
|
80
101
|
if (!config.workerScripts) {
|
|
@@ -97,7 +118,7 @@ function configure(configuration) {
|
|
|
97
118
|
}
|
|
98
119
|
|
|
99
120
|
function setIfDefined(propertyName, propertyValue) {
|
|
100
|
-
if (propertyValue !==
|
|
121
|
+
if (propertyValue !== UNDEFINED_VALUE) {
|
|
101
122
|
config[propertyName] = propertyValue;
|
|
102
123
|
}
|
|
103
124
|
}
|
package/lib/core/io.js
CHANGED
|
@@ -100,52 +100,6 @@ class Writer extends Stream {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
class TextReader extends Reader {
|
|
104
|
-
|
|
105
|
-
constructor(text) {
|
|
106
|
-
super();
|
|
107
|
-
this.blobReader = new BlobReader(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN }));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
init() {
|
|
111
|
-
const reader = this;
|
|
112
|
-
super.init();
|
|
113
|
-
reader.blobReader.init();
|
|
114
|
-
reader.size = reader.blobReader.size;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
readUint8Array(offset, length) {
|
|
118
|
-
return this.blobReader.readUint8Array(offset, length);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
class TextWriter extends Writer {
|
|
123
|
-
|
|
124
|
-
constructor(encoding) {
|
|
125
|
-
super();
|
|
126
|
-
this.encoding = encoding;
|
|
127
|
-
this.blob = new Blob([], { type: CONTENT_TYPE_TEXT_PLAIN });
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
writeUint8Array(array) {
|
|
131
|
-
this.blob = new Blob([this.blob, array.buffer], { type: CONTENT_TYPE_TEXT_PLAIN });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
getData() {
|
|
135
|
-
const writer = this;
|
|
136
|
-
if (writer.blob.text && (writer.encoding === undefined || (writer.encoding && writer.encoding.toLowerCase() == "utf-8"))) {
|
|
137
|
-
return writer.blob.text();
|
|
138
|
-
} else {
|
|
139
|
-
const reader = new FileReader();
|
|
140
|
-
return new Promise((resolve, reject) => {
|
|
141
|
-
reader.onload = event => resolve(event.target.result);
|
|
142
|
-
reader.onerror = () => reject(reader.error);
|
|
143
|
-
reader.readAsText(writer.blob, writer.encoding);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
103
|
class Data64URIReader extends Reader {
|
|
150
104
|
|
|
151
105
|
constructor(dataURI) {
|
|
@@ -242,6 +196,42 @@ class BlobWriter extends Stream {
|
|
|
242
196
|
}
|
|
243
197
|
}
|
|
244
198
|
|
|
199
|
+
class TextReader extends BlobReader {
|
|
200
|
+
|
|
201
|
+
constructor(text) {
|
|
202
|
+
super(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN }));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
class TextWriter extends BlobWriter {
|
|
207
|
+
|
|
208
|
+
constructor(encoding) {
|
|
209
|
+
super(encoding);
|
|
210
|
+
Object.assign(this, {
|
|
211
|
+
encoding,
|
|
212
|
+
utf8: !encoding || encoding.toLowerCase() == "utf-8"
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async getData() {
|
|
217
|
+
const {
|
|
218
|
+
encoding,
|
|
219
|
+
utf8
|
|
220
|
+
} = this;
|
|
221
|
+
const blob = await super.getData();
|
|
222
|
+
if (blob.text && utf8) {
|
|
223
|
+
return blob.text();
|
|
224
|
+
} else {
|
|
225
|
+
const reader = new FileReader();
|
|
226
|
+
return new Promise((resolve, reject) => {
|
|
227
|
+
reader.onload = ({ target }) => resolve(target.result);
|
|
228
|
+
reader.onerror = () => reject(reader.error);
|
|
229
|
+
reader.readAsText(blob, encoding);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
245
235
|
class FetchReader extends Reader {
|
|
246
236
|
|
|
247
237
|
constructor(url, options) {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
/* global crypto, TransformStream */
|
|
30
30
|
// deno-lint-ignore-file no-this-alias
|
|
31
31
|
|
|
32
|
-
import encodeText from "./../util/encode-text.js";
|
|
32
|
+
import { encodeText } from "./../util/encode-text.js";
|
|
33
33
|
import {
|
|
34
34
|
cipher,
|
|
35
35
|
codec,
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
} from "./codecs/sjcl.js";
|
|
39
39
|
import {
|
|
40
40
|
ERR_INVALID_PASSWORD,
|
|
41
|
+
ERR_INVALID_SIGNATURE,
|
|
41
42
|
getRandomValues
|
|
42
43
|
} from "./common-crypto.js";
|
|
43
44
|
|
|
@@ -56,9 +57,10 @@ const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0];
|
|
|
56
57
|
const UNDEFINED_TYPE = "undefined";
|
|
57
58
|
const FUNCTION_TYPE = "function";
|
|
58
59
|
const CRYPTO_API_SUPPORTED = typeof crypto != UNDEFINED_TYPE;
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
60
|
+
const subtle = CRYPTO_API_SUPPORTED && crypto.subtle;
|
|
61
|
+
const SUBTLE_API_SUPPORTED = CRYPTO_API_SUPPORTED && typeof subtle != UNDEFINED_TYPE;
|
|
62
|
+
const IMPORT_KEY_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.importKey == FUNCTION_TYPE;
|
|
63
|
+
const DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.deriveBits == FUNCTION_TYPE;
|
|
62
64
|
const codecBytes = codec.bytes;
|
|
63
65
|
const Aes = cipher.aes;
|
|
64
66
|
const CtrGladman = mode.ctrGladman;
|
|
@@ -67,7 +69,6 @@ const HmacSha1 = misc.hmacSha1;
|
|
|
67
69
|
class AESDecryptionStream extends TransformStream {
|
|
68
70
|
|
|
69
71
|
constructor(password, signed, strength) {
|
|
70
|
-
let stream;
|
|
71
72
|
super({
|
|
72
73
|
start() {
|
|
73
74
|
Object.assign(this, {
|
|
@@ -80,47 +81,51 @@ class AESDecryptionStream extends TransformStream {
|
|
|
80
81
|
},
|
|
81
82
|
async transform(chunk, controller) {
|
|
82
83
|
const aesCrypto = this;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
const {
|
|
85
|
+
password,
|
|
86
|
+
strength,
|
|
87
|
+
resolveReady,
|
|
88
|
+
ready
|
|
89
|
+
} = aesCrypto;
|
|
90
|
+
if (password) {
|
|
91
|
+
await createDecryptionKeys(aesCrypto, strength, password, subarray(chunk, 0, SALT_LENGTH[strength] + 2));
|
|
92
|
+
chunk = subarray(chunk, SALT_LENGTH[strength] + 2);
|
|
93
|
+
resolveReady();
|
|
92
94
|
} else {
|
|
93
|
-
await
|
|
95
|
+
await ready;
|
|
94
96
|
}
|
|
95
97
|
const output = new Uint8Array(chunk.length - SIGNATURE_LENGTH - ((chunk.length - SIGNATURE_LENGTH) % BLOCK_LENGTH));
|
|
96
98
|
controller.enqueue(append(aesCrypto, chunk, output, 0, SIGNATURE_LENGTH, true));
|
|
97
99
|
},
|
|
98
100
|
async flush(controller) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
const {
|
|
102
|
+
signed,
|
|
103
|
+
ctr,
|
|
104
|
+
hmac,
|
|
105
|
+
pending,
|
|
106
|
+
ready
|
|
107
|
+
} = this;
|
|
108
|
+
await ready;
|
|
102
109
|
const chunkToDecrypt = subarray(pending, 0, pending.length - SIGNATURE_LENGTH);
|
|
103
110
|
const originalSignature = subarray(pending, pending.length - SIGNATURE_LENGTH);
|
|
104
111
|
let decryptedChunkArray = new Uint8Array();
|
|
105
112
|
if (chunkToDecrypt.length) {
|
|
106
113
|
const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
|
|
107
|
-
|
|
108
|
-
const decryptedChunk =
|
|
114
|
+
hmac.update(encryptedChunk);
|
|
115
|
+
const decryptedChunk = ctr.update(encryptedChunk);
|
|
109
116
|
decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
|
|
110
117
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const signature = subarray(fromBits(codecBytes, aesCrypto.hmac.digest()), 0, SIGNATURE_LENGTH);
|
|
118
|
+
if (signed) {
|
|
119
|
+
const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
|
|
114
120
|
for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
|
|
115
121
|
if (signature[indexSignature] != originalSignature[indexSignature]) {
|
|
116
|
-
|
|
122
|
+
throw new Error(ERR_INVALID_SIGNATURE);
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
125
|
}
|
|
120
126
|
controller.enqueue(decryptedChunkArray);
|
|
121
127
|
}
|
|
122
128
|
});
|
|
123
|
-
stream = this;
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
131
|
|
|
@@ -139,31 +144,38 @@ class AESEncryptionStream extends TransformStream {
|
|
|
139
144
|
},
|
|
140
145
|
async transform(chunk, controller) {
|
|
141
146
|
const aesCrypto = this;
|
|
147
|
+
const {
|
|
148
|
+
password,
|
|
149
|
+
strength,
|
|
150
|
+
resolveReady,
|
|
151
|
+
ready
|
|
152
|
+
} = aesCrypto;
|
|
142
153
|
let preamble = new Uint8Array();
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
preamble = await createEncryptionKeys(aesCrypto, password);
|
|
147
|
-
aesCrypto.ctr = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE));
|
|
148
|
-
aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication);
|
|
149
|
-
aesCrypto.resolveReady();
|
|
154
|
+
if (password) {
|
|
155
|
+
preamble = await createEncryptionKeys(aesCrypto, strength, password);
|
|
156
|
+
resolveReady();
|
|
150
157
|
} else {
|
|
151
|
-
await
|
|
158
|
+
await ready;
|
|
152
159
|
}
|
|
153
160
|
const output = new Uint8Array(preamble.length + chunk.length - (chunk.length % BLOCK_LENGTH));
|
|
154
161
|
output.set(preamble, 0);
|
|
155
162
|
controller.enqueue(append(aesCrypto, chunk, output, preamble.length, 0));
|
|
156
163
|
},
|
|
157
164
|
async flush(controller) {
|
|
158
|
-
const
|
|
159
|
-
|
|
165
|
+
const {
|
|
166
|
+
ctr,
|
|
167
|
+
hmac,
|
|
168
|
+
pending,
|
|
169
|
+
ready
|
|
170
|
+
} = this;
|
|
171
|
+
await ready;
|
|
160
172
|
let encryptedChunkArray = new Uint8Array();
|
|
161
|
-
if (
|
|
162
|
-
const encryptedChunk =
|
|
163
|
-
|
|
173
|
+
if (pending.length) {
|
|
174
|
+
const encryptedChunk = ctr.update(toBits(codecBytes, pending));
|
|
175
|
+
hmac.update(encryptedChunk);
|
|
164
176
|
encryptedChunkArray = fromBits(codecBytes, encryptedChunk);
|
|
165
177
|
}
|
|
166
|
-
stream.signature = fromBits(codecBytes,
|
|
178
|
+
stream.signature = fromBits(codecBytes, hmac.digest()).slice(0, SIGNATURE_LENGTH);
|
|
167
179
|
controller.enqueue(concat(encryptedChunkArray, stream.signature));
|
|
168
180
|
}
|
|
169
181
|
});
|
|
@@ -178,20 +190,25 @@ export {
|
|
|
178
190
|
};
|
|
179
191
|
|
|
180
192
|
function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) {
|
|
193
|
+
const {
|
|
194
|
+
ctr,
|
|
195
|
+
hmac,
|
|
196
|
+
pending
|
|
197
|
+
} = aesCrypto;
|
|
181
198
|
const inputLength = input.length - paddingEnd;
|
|
182
|
-
if (
|
|
183
|
-
input = concat(
|
|
199
|
+
if (pending.length) {
|
|
200
|
+
input = concat(pending, input);
|
|
184
201
|
output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
|
|
185
202
|
}
|
|
186
203
|
let offset;
|
|
187
204
|
for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
|
|
188
205
|
const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
|
|
189
206
|
if (verifySignature) {
|
|
190
|
-
|
|
207
|
+
hmac.update(inputChunk);
|
|
191
208
|
}
|
|
192
|
-
const outputChunk =
|
|
209
|
+
const outputChunk = ctr.update(inputChunk);
|
|
193
210
|
if (!verifySignature) {
|
|
194
|
-
|
|
211
|
+
hmac.update(outputChunk);
|
|
195
212
|
}
|
|
196
213
|
output.set(fromBits(codecBytes, outputChunk), offset + paddingStart);
|
|
197
214
|
}
|
|
@@ -199,36 +216,44 @@ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignat
|
|
|
199
216
|
return output;
|
|
200
217
|
}
|
|
201
218
|
|
|
202
|
-
async function createDecryptionKeys(decrypt,
|
|
203
|
-
await createKeys(decrypt, password, subarray(
|
|
204
|
-
const passwordVerification = subarray(
|
|
205
|
-
const passwordVerificationKey = decrypt.keys.passwordVerification;
|
|
219
|
+
async function createDecryptionKeys(decrypt, strength, password, preamble) {
|
|
220
|
+
const passwordVerificationKey = await createKeys(decrypt, strength, password, subarray(preamble, 0, SALT_LENGTH[strength]));
|
|
221
|
+
const passwordVerification = subarray(preamble, SALT_LENGTH[strength]);
|
|
206
222
|
if (passwordVerificationKey[0] != passwordVerification[0] || passwordVerificationKey[1] != passwordVerification[1]) {
|
|
207
223
|
throw new Error(ERR_INVALID_PASSWORD);
|
|
208
224
|
}
|
|
209
225
|
}
|
|
210
226
|
|
|
211
|
-
async function createEncryptionKeys(encrypt, password) {
|
|
212
|
-
const salt = getRandomValues(new Uint8Array(SALT_LENGTH[
|
|
213
|
-
await createKeys(encrypt, password, salt);
|
|
214
|
-
return concat(salt,
|
|
227
|
+
async function createEncryptionKeys(encrypt, strength, password) {
|
|
228
|
+
const salt = getRandomValues(new Uint8Array(SALT_LENGTH[strength]));
|
|
229
|
+
const passwordVerification = await createKeys(encrypt, strength, password, salt);
|
|
230
|
+
return concat(salt, passwordVerification);
|
|
215
231
|
}
|
|
216
232
|
|
|
217
|
-
async function createKeys(
|
|
233
|
+
async function createKeys(aesCrypto, strength, password, salt) {
|
|
234
|
+
aesCrypto.password = null;
|
|
218
235
|
const encodedPassword = encodeText(password);
|
|
219
|
-
const
|
|
220
|
-
const derivedBits = await deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM),
|
|
236
|
+
const baseKey = await importKey(RAW_FORMAT, encodedPassword, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE);
|
|
237
|
+
const derivedBits = await deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), baseKey, 8 * ((KEY_LENGTH[strength] * 2) + 2));
|
|
221
238
|
const compositeKey = new Uint8Array(derivedBits);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
239
|
+
const key = toBits(codecBytes, subarray(compositeKey, 0, KEY_LENGTH[strength]));
|
|
240
|
+
const authentication = toBits(codecBytes, subarray(compositeKey, KEY_LENGTH[strength], KEY_LENGTH[strength] * 2));
|
|
241
|
+
const passwordVerification = subarray(compositeKey, KEY_LENGTH[strength] * 2);
|
|
242
|
+
Object.assign(aesCrypto, {
|
|
243
|
+
keys: {
|
|
244
|
+
key,
|
|
245
|
+
authentication,
|
|
246
|
+
passwordVerification
|
|
247
|
+
},
|
|
248
|
+
ctr: new CtrGladman(new Aes(key), Array.from(COUNTER_DEFAULT_VALUE)),
|
|
249
|
+
hmac: new HmacSha1(authentication)
|
|
250
|
+
});
|
|
251
|
+
return passwordVerification;
|
|
227
252
|
}
|
|
228
253
|
|
|
229
254
|
function importKey(format, password, algorithm, extractable, keyUsages) {
|
|
230
255
|
if (IMPORT_KEY_SUPPORTED) {
|
|
231
|
-
return
|
|
256
|
+
return subtle.importKey(format, password, algorithm, extractable, keyUsages);
|
|
232
257
|
} else {
|
|
233
258
|
return misc.importKey(password);
|
|
234
259
|
}
|
|
@@ -236,7 +261,7 @@ function importKey(format, password, algorithm, extractable, keyUsages) {
|
|
|
236
261
|
|
|
237
262
|
async function deriveBits(algorithm, baseKey, length) {
|
|
238
263
|
if (DERIVE_BITS_SUPPORTED) {
|
|
239
|
-
return await
|
|
264
|
+
return await subtle.deriveBits(algorithm, baseKey, length);
|
|
240
265
|
} else {
|
|
241
266
|
return misc.pbkdf2(baseKey, algorithm.salt, DERIVED_BITS_ALGORITHM.iterations, length);
|
|
242
267
|
}
|
|
@@ -44,8 +44,7 @@ class CodecStream extends TransformStream {
|
|
|
44
44
|
codec = new Codec(options);
|
|
45
45
|
},
|
|
46
46
|
transform(chunk, controller) {
|
|
47
|
-
|
|
48
|
-
controller.enqueue(chunk);
|
|
47
|
+
controller.enqueue(codec.append(chunk));
|
|
49
48
|
},
|
|
50
49
|
flush(controller) {
|
|
51
50
|
const chunk = codec.flush();
|
|
@@ -57,4 +56,6 @@ class CodecStream extends TransformStream {
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
export
|
|
59
|
+
export {
|
|
60
|
+
CodecStream
|
|
61
|
+
};
|