@fairblock/stabletrust 2.0.6 → 2.0.10

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.
@@ -0,0 +1,127 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { Buffer } from "buffer";
38
+ import { hkdf } from "@noble/hashes/hkdf";
39
+ import { sha256 } from "@noble/hashes/sha256";
40
+ import { STREAM } from "./stream-cipher.js";
41
+ import { NoOpEncDec } from "./no-op-encdec.js";
42
+ import { readAge, writeAge } from "./age-reader-writer.js";
43
+ import { sliceUntil, unpaddedBase64Buffer } from "./utils.js";
44
+ import { createMacKey, random } from "./utils-crypto.js";
45
+ var ageVersion = "age-encryption.org/v1";
46
+ var headerMacMessage = "header"; // some plaintext used to generate the mac
47
+ var hkdfBodyMessage = "payload"; // some plaintext used for generating the key for encrypting the body
48
+ var fileKeyLengthBytes = 32;
49
+ var bodyHkdfNonceLengthBytes = 16;
50
+ var hkdfKeyLengthBytes = 32;
51
+ // encrypts a plaintext payload using AGE by generating a fileKey
52
+ // and passing the fileKey to another `EncryptionWrapper` for handling
53
+ export function encryptAge(plaintext, wrapFileKey) {
54
+ if (wrapFileKey === void 0) { wrapFileKey = NoOpEncDec.wrap; }
55
+ return __awaiter(this, void 0, void 0, function () {
56
+ var fileKey, recipients, body;
57
+ return __generator(this, function (_a) {
58
+ switch (_a.label) {
59
+ case 0: return [4 /*yield*/, random(fileKeyLengthBytes)];
60
+ case 1:
61
+ fileKey = _a.sent();
62
+ return [4 /*yield*/, wrapFileKey(fileKey)];
63
+ case 2:
64
+ recipients = _a.sent();
65
+ return [4 /*yield*/, encryptedPayload(fileKey, plaintext)];
66
+ case 3:
67
+ body = _a.sent();
68
+ return [2 /*return*/, writeAge({
69
+ fileKey: fileKey,
70
+ version: ageVersion,
71
+ recipients: recipients,
72
+ headerMacMessage: headerMacMessage,
73
+ body: body,
74
+ })];
75
+ }
76
+ });
77
+ });
78
+ }
79
+ function encryptedPayload(fileKey, payload) {
80
+ return __awaiter(this, void 0, void 0, function () {
81
+ var nonce, hkdfKey, ciphertext;
82
+ return __generator(this, function (_a) {
83
+ switch (_a.label) {
84
+ case 0: return [4 /*yield*/, random(bodyHkdfNonceLengthBytes)];
85
+ case 1:
86
+ nonce = _a.sent();
87
+ hkdfKey = hkdf(sha256, fileKey, nonce, Buffer.from(hkdfBodyMessage, "utf8"), hkdfKeyLengthBytes);
88
+ ciphertext = STREAM.seal(payload, hkdfKey);
89
+ return [2 /*return*/, Buffer.concat([nonce, ciphertext])];
90
+ }
91
+ });
92
+ });
93
+ }
94
+ // decrypts a payload that has been encrypted using AGE can unwrap
95
+ // any internal encryption by passing a `DecryptionWrapper` that can
96
+ // provide the `fileKey` created during encryption
97
+ export function decryptAge(payload, unwrapFileKey) {
98
+ if (unwrapFileKey === void 0) { unwrapFileKey = NoOpEncDec.unwrap; }
99
+ return __awaiter(this, void 0, void 0, function () {
100
+ var encryptedPayload, version, fileKey, header, expectedMac, actualMac, nonce, cipherText, hkdfKey, plaintext;
101
+ return __generator(this, function (_a) {
102
+ switch (_a.label) {
103
+ case 0:
104
+ encryptedPayload = readAge(payload);
105
+ version = encryptedPayload.header.version;
106
+ if (version !== ageVersion) {
107
+ throw Error("The payload version ".concat(version, " is not supported, only ").concat(ageVersion));
108
+ }
109
+ return [4 /*yield*/, unwrapFileKey(encryptedPayload.header.recipients)];
110
+ case 1:
111
+ fileKey = _a.sent();
112
+ header = sliceUntil(payload, "---");
113
+ expectedMac = unpaddedBase64Buffer(createMacKey(fileKey, headerMacMessage, header));
114
+ actualMac = encryptedPayload.header.mac;
115
+ if (Buffer.compare(actualMac, expectedMac) !== 0) {
116
+ throw Error("The MAC did not validate for the fileKey and payload!");
117
+ }
118
+ nonce = Buffer.from(encryptedPayload.body.slice(0, bodyHkdfNonceLengthBytes));
119
+ cipherText = encryptedPayload.body.slice(bodyHkdfNonceLengthBytes);
120
+ hkdfKey = hkdf(sha256, fileKey, nonce, Buffer.from(hkdfBodyMessage, "utf8"), hkdfKeyLengthBytes);
121
+ plaintext = STREAM.open(cipherText, hkdfKey);
122
+ return [2 /*return*/, Buffer.from(plaintext)];
123
+ }
124
+ });
125
+ });
126
+ }
127
+ //# sourceMappingURL=age-encrypt-decrypt.js.map
@@ -0,0 +1,94 @@
1
+ import { Buffer } from "buffer";
2
+ import { chunked, unpaddedBase64 } from "./utils.js";
3
+ import { createMacKey } from "./utils-crypto.js";
4
+ // takes the model to be encrypted and encodes everything to a string
5
+ // inserting newlines, other tags and the hmac as per the spec
6
+ export function writeAge(input) {
7
+ var headerStr = header(input);
8
+ var macKey = mac(createMacKey(input.fileKey, input.headerMacMessage, headerStr));
9
+ var payload = Buffer.from(input.body).toString("binary");
10
+ return "".concat(headerStr, " ").concat(macKey, "\n").concat(payload);
11
+ }
12
+ // ends with a `---`, as this is included in the header when
13
+ // calculating the MAC
14
+ export function header(input) {
15
+ return "".concat(input.version, "\n").concat(recipients(input.recipients), "---");
16
+ }
17
+ var recipients = function (stanzas) {
18
+ return stanzas.map(function (it) { return recipient(it) + "\n"; });
19
+ };
20
+ var recipient = function (stanza) {
21
+ var type = stanza.type;
22
+ var encodedBody = unpaddedBase64(stanza.body);
23
+ var chunkedEncodedBody = chunked(encodedBody, 64).join("\n");
24
+ return "-> ".concat(type, "\n") + chunkedEncodedBody;
25
+ };
26
+ // The `---` preceding the MAC is technically part of the MAC-able text
27
+ // so it's included in the header instead
28
+ var mac = function (macStr) { return unpaddedBase64(macStr); };
29
+ // parses an AGE encrypted string into a model object with all the
30
+ // relevant parts encoded correctly
31
+ // throws an error if things are missing, in the wrong place or cannot
32
+ // be parsed
33
+ export function readAge(input) {
34
+ var _a;
35
+ var _b = input.split("\n"), version = _b[0], lines = _b.slice(1);
36
+ var recipients = parseRecipients(lines);
37
+ var macStartingTag = "--- ";
38
+ var macLine = lines.shift();
39
+ if (!macLine || !macLine.startsWith(macStartingTag)) {
40
+ throw Error("Expected mac, but there were no more lines left!");
41
+ }
42
+ var mac = Buffer.from(macLine.slice(macStartingTag.length, macLine.length), "base64");
43
+ // any remaining newlines are actually part of the payload
44
+ var ciphertext = Buffer.from((_a = lines.join("\n")) !== null && _a !== void 0 ? _a : "", "binary");
45
+ return {
46
+ header: { version: version, recipients: recipients, mac: mac },
47
+ body: ciphertext,
48
+ };
49
+ }
50
+ // validates the code points of the characters of the args in line with the go implementation
51
+ // see: https://github.com/FiloSottile/age/blob/8e3f74c283b2e9b3cd0ec661fa4008504e536d20/internal/format/format.go#L301
52
+ function validateArguments(args) {
53
+ args.forEach(function (arg) {
54
+ for (var i = 0; i < arg.length; i++) {
55
+ var charCode = arg.charCodeAt(i);
56
+ if (charCode < 33 || charCode > 126) {
57
+ throw Error("Invalid character ".concat(arg[i], " in argument ").concat(arg));
58
+ }
59
+ }
60
+ });
61
+ }
62
+ // parses all the recipient stanzas from `lines`
63
+ // modifies `lines`!!
64
+ function parseRecipients(lines) {
65
+ var recipients = [];
66
+ for (var current = peek(lines); current != null && current.startsWith("->"); current = peek(lines)) {
67
+ var _a = current.slice(3, current.length).split(" "), type = _a[0], args = _a.slice(1);
68
+ lines.shift();
69
+ validateArguments(args);
70
+ var body = parseRecipientBody(lines);
71
+ if (!body) {
72
+ throw Error("expected stanza '".concat(type, " to have a body, but it didn't"));
73
+ }
74
+ recipients.push({ type: type, args: args, body: Buffer.from(body, "base64") });
75
+ }
76
+ if (recipients.length === 0) {
77
+ throw Error("Expected at least one stanza! (beginning with -->)");
78
+ }
79
+ return recipients;
80
+ }
81
+ function parseRecipientBody(lines) {
82
+ var body = "";
83
+ for (var next = peek(lines); next != null; next = peek(lines)) {
84
+ body += lines.shift();
85
+ if (next.length < 64) {
86
+ break;
87
+ }
88
+ }
89
+ return body;
90
+ }
91
+ function peek(arr) {
92
+ return arr[0];
93
+ }
94
+ //# sourceMappingURL=age-reader-writer.js.map
@@ -0,0 +1,52 @@
1
+ import { Buffer } from "buffer";
2
+ import { chunked } from "./utils.js";
3
+ var header = "-----BEGIN AGE ENCRYPTED FILE-----";
4
+ var footer = "-----END AGE ENCRYPTED FILE-----";
5
+ // takes some payload and encodes it as armor with the AGE armor headers in lines of size `chunkSize`
6
+ export function encodeArmor(input, chunkSize) {
7
+ if (chunkSize === void 0) { chunkSize = 64; }
8
+ var base64Input = Buffer.from(input, "binary").toString("base64");
9
+ var columnisedInput = chunked(base64Input, chunkSize).join("\n");
10
+ // if the last line is exactly 64 columns, add an extra newline
11
+ var paddedFooter = footer;
12
+ if (columnisedInput.length > 0 &&
13
+ columnisedInput[columnisedInput.length - 1].length === 64) {
14
+ paddedFooter = "\n" + footer;
15
+ }
16
+ return "".concat(header, "\n").concat(columnisedInput, "\n").concat(paddedFooter, "\n");
17
+ }
18
+ // takes an armored payload and decodes it if it is an AGE armor payload
19
+ // and it satisfies some security properties
20
+ export function decodeArmor(armor, chunkSize) {
21
+ if (chunkSize === void 0) { chunkSize = 64; }
22
+ // could start/end with space or newlines, let's strip them
23
+ armor = armor.trimStart();
24
+ var lengthBeforeEndTrim = armor.length;
25
+ armor = armor.trimEnd();
26
+ var lengthAfterTrim = armor.length;
27
+ // for compliance with the go age implementation, we deny more than 1024 whitespace chars:
28
+ // see: https://github.com/FiloSottile/age/blob/8e3f74c283b2e9b3cd0ec661fa4008504e536d20/armor/armor.go#L104
29
+ var trimmedWhitespace = lengthBeforeEndTrim - lengthAfterTrim;
30
+ if (trimmedWhitespace > 1024) {
31
+ throw Error("too much whitespace at the end of the armor payload");
32
+ }
33
+ if (!armor.startsWith(header)) {
34
+ throw Error("Armor cannot be decoded if it does not start with a header! i.e. ".concat(header));
35
+ }
36
+ if (!armor.endsWith(footer)) {
37
+ throw Error("Armor cannot be decoded if it does not end with a footer! i.e. ".concat(footer));
38
+ }
39
+ var base64Payload = armor.slice(header.length, armor.length - footer.length);
40
+ var lines = base64Payload.split("\n");
41
+ if (lines.some(function (line) { return line.length > chunkSize; })) {
42
+ throw Error("Armor to decode cannot have lines longer than ".concat(chunkSize, " (configurable) in order to stop padding attacks"));
43
+ }
44
+ if (lines[lines.length - 1].length >= chunkSize) {
45
+ throw Error("The last line of an armored payload must be less than ".concat(chunkSize, " (configurable) to stop padding attacks"));
46
+ }
47
+ return Buffer.from(base64Payload, "base64").toString("binary");
48
+ }
49
+ export function isProbablyArmored(input) {
50
+ return input.startsWith(header);
51
+ }
52
+ //# sourceMappingURL=armor.js.map
@@ -0,0 +1,72 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ var noOpType = "no-op";
38
+ // if you wish to encrypt with AGE but simply pass the filekey in the recipient stanza, then use this
39
+ // protip: you probably don't!
40
+ var NoOpEncDec = /** @class */ (function () {
41
+ function NoOpEncDec() {
42
+ }
43
+ NoOpEncDec.wrap = function (filekey) {
44
+ return __awaiter(this, void 0, void 0, function () {
45
+ return __generator(this, function (_a) {
46
+ return [2 /*return*/, [
47
+ {
48
+ type: noOpType,
49
+ args: [],
50
+ body: filekey,
51
+ },
52
+ ]];
53
+ });
54
+ });
55
+ };
56
+ NoOpEncDec.unwrap = function (recipients) {
57
+ return __awaiter(this, void 0, void 0, function () {
58
+ return __generator(this, function (_a) {
59
+ if (recipients.length !== 1) {
60
+ throw Error("NoOpEncDec only expects a single stanza!");
61
+ }
62
+ if (recipients[0].type !== noOpType) {
63
+ throw Error("NoOpEncDec expects the type of the stanza to be ".concat(noOpType));
64
+ }
65
+ return [2 /*return*/, recipients[0].body];
66
+ });
67
+ });
68
+ };
69
+ return NoOpEncDec;
70
+ }());
71
+ export { NoOpEncDec };
72
+ //# sourceMappingURL=no-op-encdec.js.map
@@ -0,0 +1,99 @@
1
+ // largely taken from https://github.com/paulmillr/jage,
2
+ // but hooking in a browser compatible ChaCha20 implementation
3
+ // STREAM cipher
4
+ // https://eprint.iacr.org/2015/189.pdf
5
+ // age spec:
6
+ // After the header the binary payload is nonce || STREAM[HKDF[nonce, "payload"](file key)](plaintext) where nonce is random(16) and STREAM is from Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance with ChaCha20-Poly1305 in 64KiB chunks and a nonce structure of 11 bytes of big endian counter, and 1 byte of last block flag (0x00 / 0x01). (The STREAM scheme is similar to the one Tink and Miscreant use, but without nonce prefix as we use HKDF, and with ChaCha20-Poly1305 instead of AES-GCM because the latter is unreasonably hard to do well or fast without hardware support.)
7
+ import { ChaCha20Poly1305 } from "@stablelib/chacha20poly1305";
8
+ var CHUNK_SIZE = 64 * 1024; // 64 KiB
9
+ var TAG_SIZE = 16; // Poly1305 MAC size
10
+ var ENCRYPTED_CHUNK_SIZE = CHUNK_SIZE + TAG_SIZE;
11
+ var NONCE_SIZE = 12; // STREAM nonce size
12
+ // due to using a 32bit uint for the counter, this is the max
13
+ // value the counter can be without risking a nonce reuse
14
+ var COUNTER_MAX = Math.pow(2, 32) - 1;
15
+ var STREAM = /** @class */ (function () {
16
+ function STREAM(key) {
17
+ this.key = key.slice();
18
+ this.nonce = new Uint8Array(NONCE_SIZE);
19
+ this.nonceView = new DataView(this.nonce.buffer);
20
+ this.counter = 0;
21
+ }
22
+ STREAM.seal = function (plaintext, privateKey) {
23
+ var stream = new STREAM(privateKey);
24
+ var chunks = Math.ceil(plaintext.length / CHUNK_SIZE);
25
+ var ciphertext = new Uint8Array(plaintext.length + chunks * TAG_SIZE);
26
+ for (var chunk64kb = 1; chunk64kb <= chunks; chunk64kb++) {
27
+ var start = chunk64kb - 1;
28
+ var end = chunk64kb;
29
+ var isLast = chunk64kb === chunks;
30
+ var input = plaintext.slice(start * CHUNK_SIZE, end * CHUNK_SIZE);
31
+ var output = ciphertext.subarray(start * ENCRYPTED_CHUNK_SIZE, end * ENCRYPTED_CHUNK_SIZE);
32
+ stream.encryptChunk(input, isLast, output);
33
+ }
34
+ stream.clear();
35
+ return ciphertext;
36
+ };
37
+ STREAM.open = function (ciphertext, privateKey) {
38
+ var stream = new STREAM(privateKey);
39
+ var chunks = Math.ceil(ciphertext.length / ENCRYPTED_CHUNK_SIZE);
40
+ var plaintext = new Uint8Array(ciphertext.length - chunks * TAG_SIZE);
41
+ for (var chunk64kb = 1; chunk64kb <= chunks; chunk64kb++) {
42
+ var start = chunk64kb - 1;
43
+ var end = chunk64kb;
44
+ var isLast = chunk64kb === chunks;
45
+ var input = ciphertext.slice(start * ENCRYPTED_CHUNK_SIZE, end * ENCRYPTED_CHUNK_SIZE);
46
+ var output = plaintext.subarray(start * CHUNK_SIZE, end * CHUNK_SIZE);
47
+ stream.decryptChunk(input, isLast, output);
48
+ }
49
+ stream.clear();
50
+ return plaintext;
51
+ };
52
+ STREAM.prototype.encryptChunk = function (chunk, isLast, output) {
53
+ if (chunk.length > CHUNK_SIZE)
54
+ throw new Error("Chunk is too big");
55
+ if (this.nonce[11] === 1)
56
+ throw new Error("Last chunk has been processed");
57
+ if (isLast)
58
+ this.nonce[11] = 1;
59
+ var ciphertext = new ChaCha20Poly1305(this.key).seal(this.nonce, chunk);
60
+ output.set(ciphertext);
61
+ this.incrementCounter();
62
+ };
63
+ STREAM.prototype.decryptChunk = function (chunk, isLast, output) {
64
+ if (chunk.length > ENCRYPTED_CHUNK_SIZE)
65
+ throw new Error("Chunk is too big");
66
+ if (this.nonce[11] === 1)
67
+ throw new Error("Last chunk has been processed");
68
+ if (isLast)
69
+ this.nonce[11] = 1;
70
+ var plaintext = new ChaCha20Poly1305(this.key).open(this.nonce, chunk);
71
+ if (plaintext == null) {
72
+ throw Error("Error during decryption!");
73
+ }
74
+ output.set(plaintext);
75
+ this.incrementCounter();
76
+ };
77
+ // Increments Big Endian Uint8Array-based counter.
78
+ // [0, 0, 0] => [0, 0, 1] ... => [0, 0, 255] => [0, 1, 0]
79
+ STREAM.prototype.incrementCounter = function () {
80
+ if (this.counter == COUNTER_MAX) {
81
+ throw new Error("Stream cipher counter has already hit max value! Aborting to avoid nonce reuse - tlock only supports payloads up to 256TB");
82
+ }
83
+ this.counter += 1;
84
+ this.nonceView.setUint32(7, this.counter, false);
85
+ };
86
+ STREAM.prototype.clear = function () {
87
+ function clear(arr) {
88
+ for (var i = 0; i < arr.length; i++) {
89
+ arr[i] = 0;
90
+ }
91
+ }
92
+ clear(this.key);
93
+ clear(this.nonce);
94
+ this.counter = 0;
95
+ };
96
+ return STREAM;
97
+ }());
98
+ export { STREAM };
99
+ //# sourceMappingURL=stream-cipher.js.map
@@ -0,0 +1,60 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { Buffer } from "buffer";
38
+ import { hkdf } from "@noble/hashes/hkdf";
39
+ import { sha256 } from "@noble/hashes/sha256";
40
+ import { hmac } from "@noble/hashes/hmac";
41
+ import { randomBytes } from "crypto";
42
+ export function createMacKey(fileKey, macMessage, headerText) {
43
+ // empty string salt as per the spec!
44
+ var hmacKey = hkdf(sha256, fileKey, "", Buffer.from(macMessage, "utf8"), 32);
45
+ return Buffer.from(hmac(sha256, hmacKey, Buffer.from(headerText, "utf8")));
46
+ }
47
+ // returns a string of n bytes read from a CSPRNG like /dev/urandom.
48
+ export function random(n) {
49
+ return __awaiter(this, void 0, void 0, function () {
50
+ var bytes;
51
+ return __generator(this, function (_a) {
52
+ if (typeof window === "object" && "crypto" in window) {
53
+ return [2 /*return*/, window.crypto.getRandomValues(new Uint8Array(n))];
54
+ }
55
+ bytes = randomBytes(n);
56
+ return [2 /*return*/, new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength)];
57
+ });
58
+ });
59
+ }
60
+ //# sourceMappingURL=utils-crypto.js.map
@@ -0,0 +1,59 @@
1
+ import { Buffer } from "buffer";
2
+ // as per the spec:
3
+ // RFC 4648, Section 4
4
+ // without = padding characters (sometimes referred to as "raw" or "unpadded" base64)
5
+ export function unpaddedBase64(buf) {
6
+ var encodedBuf = Buffer.from(buf).toString("base64");
7
+ var lastIndex = encodedBuf.length - 1;
8
+ while (encodedBuf[lastIndex] === "=") {
9
+ lastIndex--;
10
+ }
11
+ return encodedBuf.slice(0, lastIndex + 1);
12
+ }
13
+ export function unpaddedBase64Buffer(buf) {
14
+ return Buffer.from(unpaddedBase64(buf), "base64");
15
+ }
16
+ /*
17
+ e.g. chunked("hello world", 2, ".") returns
18
+ ["he.", "ll.", "o .", "wo.", "rl.", "d."]
19
+ */
20
+ export function chunked(input, chunkSize, suffix) {
21
+ if (suffix === void 0) { suffix = ""; }
22
+ var output = [];
23
+ var currentChunk = "";
24
+ for (var i = 0, chunks = 0; i < input.length; i++) {
25
+ currentChunk += input[i];
26
+ var posInChunk = i - chunks * chunkSize;
27
+ if (posInChunk === chunkSize - 1) {
28
+ output.push(currentChunk + suffix);
29
+ currentChunk = "";
30
+ chunks++;
31
+ }
32
+ else if (i === input.length - 1) {
33
+ output.push(currentChunk + suffix);
34
+ }
35
+ }
36
+ return output;
37
+ }
38
+ // slices the input string up to and including the first
39
+ // occurrence of the string provided in `searchTerm`
40
+ // returns the whole string if it's not found
41
+ // e.g. sliceUntil("hello world", "ll") will return "hell"
42
+ export function sliceUntil(input, searchTerm) {
43
+ var lettersMatched = 0;
44
+ var inputPointer = 0;
45
+ while (inputPointer < input.length && lettersMatched < searchTerm.length) {
46
+ if (input[inputPointer] === searchTerm[lettersMatched]) {
47
+ ++lettersMatched;
48
+ }
49
+ else if (input[inputPointer] === searchTerm[0]) {
50
+ lettersMatched = 1;
51
+ }
52
+ else {
53
+ lettersMatched = 0;
54
+ }
55
+ ++inputPointer;
56
+ }
57
+ return input.slice(0, inputPointer);
58
+ }
59
+ //# sourceMappingURL=utils.js.map