UNPKG

@hazae41/kdbx

Version:

Rust-like KeePass (KDBX 4) file format for TypeScript

356 lines (353 loc) 12.8 kB
import { __addDisposableResource, __disposeResources } from '../../../node_modules/tslib/tslib.es6.mjs'; export { Dictionary, Entries, Entry, Key, Value } from './dictionary/index.mjs'; import { HeadersAndContentWithBytes } from './headers/inner/index.mjs'; import * as index from './headers/inner/index.mjs'; export { index as Inner }; import { MagicAndVersionAndHeadersWithBytesWithHashAndHmacWithKeys, MagicAndVersionAndHeadersWithBytesWithHashAndHmac } from './headers/outer/index.mjs'; import * as index$1 from './headers/outer/index.mjs'; export { index$1 as Outer }; import { Base64 } from '@hazae41/base64'; import { Writable, Opaque, Readable } from '@hazae41/binary'; import { Cursor } from '@hazae41/cursor'; import { gzip, gunzip } from '../../libs/gzip/index.mjs'; import { PreHmacKey } from './hmac/index.mjs'; import { Compression } from './headers/outer/compression/index.mjs'; var _a, _b, _c, _d, _e, _f, _g, _h; class PasswordKey { value; #class = _a; constructor(value) { this.value = value; } static async digestOrThrow(password) { const array = await crypto.subtle.digest("SHA-256", password); const bytes = new Uint8Array(array); return new _a(new Opaque(bytes)); } } _a = PasswordKey; class CompositeKey { value; #class = _b; constructor(value) { this.value = value; } static async digestOrThrow(password) { const array = await crypto.subtle.digest("SHA-256", password.value.bytes); const bytes = new Uint8Array(array); return new _b(new Opaque(bytes)); } } _b = CompositeKey; class DerivedKey { value; #class = _c; constructor(value) { this.value = value; } } _c = DerivedKey; class PreMasterKey { seed; hash; #class = _d; constructor(seed, hash) { this.seed = seed; this.hash = hash; } sizeOrThrow() { return 32 + 32; } writeOrThrow(cursor) { cursor.writeOrThrow(this.seed.bytes); cursor.writeOrThrow(this.hash.value.bytes); } async digestOrThrow() { const input = Writable.writeToBytesOrThrow(this); const digest = await crypto.subtle.digest("SHA-256", input); const output = new Uint8Array(digest); return new MasterKey(new Opaque(output)); } } _d = PreMasterKey; class MasterKey { value; #class = _e; constructor(value) { this.value = value; } } _e = MasterKey; class PreHmacMasterKey { seed; hash; #class = _f; constructor(seed, hash) { this.seed = seed; this.hash = hash; } sizeOrThrow() { return 32 + 32 + 1; } writeOrThrow(cursor) { cursor.writeOrThrow(this.seed.bytes); cursor.writeOrThrow(this.hash.value.bytes); cursor.writeUint8OrThrow(1); } async digestOrThrow() { const input = Writable.writeToBytesOrThrow(this); const digest = await crypto.subtle.digest("SHA-512", input); const output = new Uint8Array(digest); return new HmacMasterKey(new Opaque(output)); } } _f = PreHmacMasterKey; class HmacMasterKey { bytes; #class = _g; constructor(bytes) { this.bytes = bytes; } } _g = HmacMasterKey; class MasterKeys { encrypter; authifier; #class = _h; constructor(encrypter, authifier) { this.encrypter = encrypter; this.authifier = authifier; } } _h = MasterKeys; var Database; (function (Database) { class Decrypted { outer; inner; constructor(outer, inner) { this.outer = outer; this.inner = inner; } async rotateOrThrow(composite) { return new Decrypted(await this.outer.rotateOrThrow(composite), await this.inner.rotateOrThrow()); } async encryptOrThrow() { const cipher = await this.inner.headers.getCipherOrThrow(); const $$values = this.inner.content.value.document.querySelectorAll("Value[Protected='True']"); for (let i = 0; i < $$values.length; i++) { const env_1 = { stack: [], error: void 0, hasError: false }; try { const $value = $$values[i]; const decrypted = new TextEncoder().encode($value.innerHTML); const encrypted = __addDisposableResource(env_1, cipher.applyOrThrow(decrypted), false); $value.innerHTML = Base64.encodePaddedOrThrow(encrypted.bytes); } catch (e_1) { env_1.error = e_1; env_1.hasError = true; } finally { __disposeResources(env_1); } } { const { cipher, iv, compression } = this.outer.data.data.value.headers; const degzipped = Writable.writeToBytesOrThrow(this.inner.recomputeOrThrow()); const engzipped = compression === Compression.Gzip ? new Uint8Array(await gzip(degzipped)) : degzipped; const encrypted = await cipher.encryptOrThrow(this.outer.keys.encrypter.value.bytes, iv.bytes, engzipped); const blocks = new Array(); const cursor = new Cursor(encrypted); const splits = cursor.splitOrThrow(1048576); let index = 0n; for (let x = splits.next(); true; index++, x = splits.next()) { if (x.done) break; blocks.push(await BlockWithIndex.fromOrThrow(this.outer.keys, index, x.value)); continue; } blocks.push(await BlockWithIndex.fromOrThrow(this.outer.keys, index, new Uint8Array(0))); return new Encrypted(this.outer.data, new Blocks(blocks)); } } } Database.Decrypted = Decrypted; class Encrypted { outer; inner; constructor(outer, inner) { this.outer = outer; this.inner = inner; } sizeOrThrow() { return this.outer.sizeOrThrow() + this.inner.sizeOrThrow(); } writeOrThrow(cursor) { this.outer.writeOrThrow(cursor); this.inner.writeOrThrow(cursor); } cloneOrThrow() { return new Encrypted(this.outer.cloneOrThrow(), this.inner.cloneOrThrow()); } async decryptOrThrow(composite) { const { cipher, iv, compression } = this.outer.data.value.headers; const keys = await this.outer.deriveOrThrow(composite); await this.outer.verifyOrThrow(keys); const length = this.inner.blocks.reduce((a, b) => a + b.block.data.bytes.length, 0); const cursor = new Cursor(new Uint8Array(length)); for (const block of this.inner.blocks) { await block.verifyOrThrow(keys); cursor.writeOrThrow(block.block.data.bytes); continue; } const decrypted = await cipher.decryptOrThrow(keys.encrypter.value.bytes, iv.bytes, cursor.bytes); const degzipped = compression === Compression.Gzip ? await gunzip(decrypted) : decrypted; const inner = Readable.readFromBytesOrThrow(HeadersAndContentWithBytes, degzipped); { const cipher = await inner.headers.getCipherOrThrow(); const $$values = inner.content.value.document.querySelectorAll("Value[Protected='True']"); for (let i = 0; i < $$values.length; i++) { const env_2 = { stack: [], error: void 0, hasError: false }; try { const $value = $$values[i]; const encrypted = Base64.decodePaddedOrThrow($value.innerHTML); const decrypted = __addDisposableResource(env_2, cipher.applyOrThrow(encrypted), false); $value.innerHTML = new TextDecoder().decode(decrypted.bytes); } catch (e_2) { env_2.error = e_2; env_2.hasError = true; } finally { __disposeResources(env_2); } } const outer = new MagicAndVersionAndHeadersWithBytesWithHashAndHmacWithKeys(this.outer, keys); return new Decrypted(outer, inner); } } } Database.Encrypted = Encrypted; (function (Encrypted) { function readOrThrow(cursor) { const head = MagicAndVersionAndHeadersWithBytesWithHashAndHmac.readOrThrow(cursor); const body = Blocks.readOrThrow(cursor); return new Encrypted(head, body); } Encrypted.readOrThrow = readOrThrow; })(Encrypted = Database.Encrypted || (Database.Encrypted = {})); })(Database || (Database = {})); class Blocks { blocks; constructor(blocks) { this.blocks = blocks; } sizeOrThrow() { return this.blocks.reduce((a, b) => a + b.sizeOrThrow(), 0); } writeOrThrow(cursor) { for (const block of this.blocks) block.writeOrThrow(cursor); return; } cloneOrThrow() { return new Blocks(this.blocks.map(block => block.cloneOrThrow())); } } (function (Blocks) { function readOrThrow(cursor) { const blocks = new Array(); for (let index = 0n; true; index++) { const block = Block.readOrThrow(cursor); blocks.push(new BlockWithIndex(index, block)); if (block.data.bytes.length === 0) break; continue; } return new Blocks(blocks); } Blocks.readOrThrow = readOrThrow; })(Blocks || (Blocks = {})); class BlockWithIndexPreHmacData { index; block; constructor(index, block) { this.index = index; this.block = block; } sizeOrThrow() { return 8 + 4 + this.block.bytes.length; } writeOrThrow(cursor) { cursor.writeUint64OrThrow(this.index, true); cursor.writeUint32OrThrow(this.block.bytes.length, true); cursor.writeOrThrow(this.block.bytes); } } class BlockWithIndex { index; block; constructor(index, block) { this.index = index; this.block = block; } sizeOrThrow() { return this.block.sizeOrThrow(); } writeOrThrow(cursor) { this.block.writeOrThrow(cursor); } cloneOrThrow() { return new BlockWithIndex(this.index, this.block.cloneOrThrow()); } async verifyOrThrow(keys) { const { index } = this; const major = keys.authifier.bytes; const key = await new PreHmacKey(index, major).digestOrThrow(); const preimage = new BlockWithIndexPreHmacData(this.index, this.block.data); const prebytes = Writable.writeToBytesOrThrow(preimage); await key.verifyOrThrow(prebytes, this.block.hmac.bytes); } } (function (BlockWithIndex) { async function fromOrThrow(keys, index, data) { const major = keys.authifier.bytes; const key = await new PreHmacKey(index, major).digestOrThrow(); const preimage = new BlockWithIndexPreHmacData(index, new Opaque(data)); const prebytes = Writable.writeToBytesOrThrow(preimage); const hmac = new Opaque(await key.signOrThrow(prebytes)); const block = new Block(hmac, new Opaque(data)); return new BlockWithIndex(index, block); } BlockWithIndex.fromOrThrow = fromOrThrow; })(BlockWithIndex || (BlockWithIndex = {})); class Block { hmac; data; constructor(hmac, data) { this.hmac = hmac; this.data = data; } sizeOrThrow() { return 32 + 4 + this.data.bytes.length; } writeOrThrow(cursor) { cursor.writeOrThrow(this.hmac.bytes); cursor.writeUint32OrThrow(this.data.bytes.length, true); cursor.writeOrThrow(this.data.bytes); } cloneOrThrow() { return new Block(this.hmac.cloneOrThrow(), this.data.cloneOrThrow()); } } (function (Block) { function readOrThrow(cursor) { const hmac = new Opaque(cursor.readOrThrow(32)); const size = cursor.readUint32OrThrow(true); const data = new Opaque(cursor.readOrThrow(size)); return new Block(hmac, data); } Block.readOrThrow = readOrThrow; })(Block || (Block = {})); export { Block, BlockWithIndex, BlockWithIndexPreHmacData, Blocks, CompositeKey, Database, DerivedKey, HmacMasterKey, MasterKey, MasterKeys, PasswordKey, PreHmacMasterKey, PreMasterKey }; //# sourceMappingURL=index.mjs.map