@hazae41/kdbx
Version:
Rust-like KeePass (KDBX 4) file format for TypeScript
356 lines (353 loc) • 12.8 kB
JavaScript
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