chore(standalone): remove async encryption

This commit is contained in:
Elian Doran
2026-04-12 19:57:30 +03:00
parent 395c71fa0d
commit 91d4e77a48
4 changed files with 3 additions and 144 deletions

View File

@@ -1,8 +1,6 @@
export interface Cipher {
update(data: Uint8Array): Uint8Array;
final(): Uint8Array;
/** Async finalization for browser environments where Web Crypto API is async-only */
finalizeAsync?(): Promise<Uint8Array>;
}
export interface ScryptOptions {

View File

@@ -108,118 +108,8 @@ function decryptString(dataKey: Uint8Array, cipherText: string) {
return decodeUtf8(buffer);
}
/**
* Async version of encrypt that works in both Node.js and browser environments.
* Uses finalizeAsync() for browser compatibility when available.
*/
async function encryptAsync(key: Uint8Array, plainText: Uint8Array | string): Promise<string> {
if (!key) {
throw new Error("No data key!");
}
const plainTextUint8Array = ArrayBuffer.isView(plainText) ? plainText : encodeUtf8(plainText);
const iv = getCrypto().randomBytes(16);
const cipher = getCrypto().createCipheriv("aes-128-cbc", pad(key), pad(iv));
const digest = shaArray(plainTextUint8Array).slice(0, 4);
const digestWithPayload = concat2(digest, plainTextUint8Array);
// Use async finalization if available (browser), otherwise sync (Node.js)
let encryptedData: Uint8Array;
if (cipher.finalizeAsync) {
// Browser: update() buffers data, finalizeAsync() encrypts and returns all
cipher.update(digestWithPayload);
encryptedData = await cipher.finalizeAsync();
} else {
// Node.js: update() and final() both return encrypted chunks
encryptedData = concat2(cipher.update(digestWithPayload), cipher.final());
}
const encryptedDataWithIv = concat2(iv, encryptedData);
return encodeBase64(encryptedDataWithIv);
}
/**
* Async version of decrypt that works in both Node.js and browser environments.
* Uses finalizeAsync() for browser compatibility when available.
*/
async function decryptAsync(key: Uint8Array, cipherText: string | Uint8Array): Promise<Uint8Array | false | null> {
if (cipherText === null) {
return null;
}
if (!key) {
return encodeUtf8("[protected]");
}
try {
const cipherTextStr = typeof cipherText === "string" ? cipherText : decodeUtf8(cipherText);
const cipherTextUint8ArrayWithIv = decodeBase64(cipherTextStr);
// old encrypted data can have IV of length 13, see some details here: https://github.com/zadam/trilium/issues/3017
const ivLength = cipherTextUint8ArrayWithIv.length % 16 === 0 ? 16 : 13;
const iv = cipherTextUint8ArrayWithIv.slice(0, ivLength);
const cipherTextUint8Array = cipherTextUint8ArrayWithIv.slice(ivLength);
const decipher = getCrypto().createDecipheriv("aes-128-cbc", pad(key), pad(iv));
// Use async finalization if available (browser), otherwise sync (Node.js)
let decryptedBytes: Uint8Array;
if (decipher.finalizeAsync) {
// Browser: update() buffers data, finalizeAsync() decrypts and returns all
decipher.update(cipherTextUint8Array);
decryptedBytes = await decipher.finalizeAsync();
} else {
// Node.js: update() and final() both return decrypted chunks
decryptedBytes = concat2(decipher.update(cipherTextUint8Array), decipher.final());
}
const digest = decryptedBytes.slice(0, 4);
const payload = decryptedBytes.slice(4);
const computedDigest = shaArray(payload).slice(0, 4);
if (!arraysIdentical(digest, computedDigest)) {
return false;
}
return payload;
} catch (e: any) {
// recovery from https://github.com/zadam/trilium/issues/510
if (e.message?.includes("WRONG_FINAL_BLOCK_LENGTH") || e.message?.includes("wrong final block length")) {
getLog().info("Caught WRONG_FINAL_BLOCK_LENGTH, returning cipherText instead");
return (ArrayBuffer.isView(cipherText) ? cipherText : Uint8Array.from(cipherText));
}
throw e;
}
}
/**
* Async version of decryptString that works in both Node.js and browser environments.
*/
async function decryptStringAsync(dataKey: Uint8Array, cipherText: string): Promise<string | null> {
const buffer = await decryptAsync(dataKey, cipherText);
if (buffer === null) {
return null;
} else if (buffer === false) {
getLog().error(`Could not decrypt string. Uint8Array: ${buffer}`);
throw new Error("Could not decrypt string.");
}
return decodeUtf8(buffer);
}
export default {
encrypt,
decrypt,
decryptString,
encryptAsync,
decryptAsync,
decryptStringAsync
decryptString
};

View File

@@ -31,7 +31,7 @@ export async function setDataKey(
plainTextDataKey: string | Uint8Array
): Promise<void> {
const passwordDerivedKey = await scryptService.getPasswordDerivedKey(password);
const newEncryptedDataKey = await data_encryption.encryptAsync(passwordDerivedKey, plainTextDataKey);
const newEncryptedDataKey = data_encryption.encrypt(passwordDerivedKey, plainTextDataKey);
options.setOption("encryptedDataKey", newEncryptedDataKey);
}
@@ -41,7 +41,7 @@ export async function setDataKey(
export async function getDataKey(password: string): Promise<Uint8Array | false | null> {
const passwordDerivedKey = await scryptService.getPasswordDerivedKey(password);
const encryptedDataKey = options.getOption("encryptedDataKey");
return data_encryption.decryptAsync(passwordDerivedKey, encryptedDataKey);
return data_encryption.decrypt(passwordDerivedKey, encryptedDataKey);
}
export default {

View File

@@ -29,15 +29,6 @@ function encrypt(plainText: string | Uint8Array) {
return dataEncryptionService.encrypt(dataKey, plainText);
}
async function encryptAsync(plainText: string | Uint8Array): Promise<string | null> {
const dataKey = getDataKey();
if (plainText === null || dataKey === null) {
return null;
}
return dataEncryptionService.encryptAsync(dataKey, plainText);
}
function decrypt(cipherText: string | Uint8Array): Uint8Array | null {
const dataKey = getDataKey();
if (cipherText === null || dataKey === null) {
@@ -47,15 +38,6 @@ function decrypt(cipherText: string | Uint8Array): Uint8Array | null {
return dataEncryptionService.decrypt(dataKey, cipherText) || null;
}
async function decryptAsync(cipherText: string | Uint8Array): Promise<Uint8Array | null> {
const dataKey = getDataKey();
if (cipherText === null || dataKey === null) {
return null;
}
return (await dataEncryptionService.decryptAsync(dataKey, cipherText)) || null;
}
function decryptString(cipherText: string): string | null {
const dataKey = getDataKey();
if (dataKey === null) {
@@ -64,14 +46,6 @@ function decryptString(cipherText: string): string | null {
return dataEncryptionService.decryptString(dataKey, cipherText);
}
async function decryptStringAsync(cipherText: string): Promise<string | null> {
const dataKey = getDataKey();
if (dataKey === null) {
return null;
}
return dataEncryptionService.decryptStringAsync(dataKey, cipherText);
}
let lastProtectedSessionOperationDate: number | null = null;
function touchProtectedSession() {
@@ -89,11 +63,8 @@ export default {
resetDataKey,
isProtectedSessionAvailable,
encrypt,
encryptAsync,
decrypt,
decryptAsync,
decryptString,
decryptStringAsync,
touchProtectedSession,
getLastProtectedSessionOperationDate
};