PageSourceSearch

https://brianhoskins.uk/js/passwordManagerCrypto.eqaqv2p756.js

js brianhoskins.uk collected 2026-10-04 03:53:54 UTC 2,751 bytes, 89 lines download raw bytes

1function ensureWebCrypto() {
2    if (!globalThis.crypto || !globalThis.crypto.subtle) {
3        throw new Error("Web Crypto API is unavailable. Password Manager requires a modern browser over HTTPS.");
4    }
5
6    return globalThis.crypto;
7}
8
9function fromBase64(base64) {
10    const binary = globalThis.atob(base64);
11    const bytes = new Uint8Array(binary.length);
12
13    for (let index = 0; index < binary.length; index += 1) {
14        bytes[index] = binary.charCodeAt(index);
15    }
16
17    return bytes;
18}
19
20function toBase64(bytes) {
21    const chunkSize = 0x8000;
22    let binary = "";
23
24    for (let index = 0; index < bytes.length; index += chunkSize) {
25        const chunk = bytes.subarray(index, index + chunkSize);
26        binary += String.fromCharCode(...chunk);
27    }
28
29    return globalThis.btoa(binary);
30}
31
32export function getRandomBytes(length) {
33    const crypto = ensureWebCrypto();
34    const bytes = new Uint8Array(length);
35    crypto.getRandomValues(bytes);
36    return toBase64(bytes);
37}
38
39export async function derivePbkdf2Sha256(passwordBase64, saltBase64, iterations, outputLengthBytes) {
40    const crypto = ensureWebCrypto();
41    const password = fromBase64(passwordBase64);
42    const salt = fromBase64(saltBase64);
43    const keyMaterial = await crypto.subtle.importKey("raw", password, "PBKDF2", false, ["deriveBits"]);
44    const derivedBits = await crypto.subtle.deriveBits(
45        {
46            name: "PBKDF2",
47            hash: "SHA-256",
48            salt,
49            iterations
50        },
51        keyMaterial,
52        outputLengthBytes * 8);
53
54    return toBase64(new Uint8Array(derivedBits));
55}
56
57export async function sha256(dataBase64) {
58    const crypto = ensureWebCrypto();
59    const digest = await crypto.subtle.digest("SHA-256", fromBase64(dataBase64));
60    return toBase64(new Uint8Array(digest));
61}
62
63export async function aesCbcEncrypt(keyBase64, ivBase64, dataBase64) {
64    const crypto = ensureWebCrypto();
65    const key = await crypto.subtle.importKey("raw", fromBase64(keyBase64), { name: "AES-CBC" }, false, ["encrypt"]);
66    const ciphertext = await crypto.subtle.encrypt(
67        {
68            name: "AES-CBC",
69            iv: fromBase64(ivBase64)
70        },
71        key,
72        fromBase64(dataBase64));
73
74    return toBase64(new Uint8Array(ciphertext));
75}
76
77export async function aesCbcDecrypt(keyBase64, ivBase64, dataBase64) {
78    const crypto = ensureWebCrypto();
79    const key = await crypto.subtle.importKey("raw", fromBase64(keyBase64), { name: "AES-CBC" }, false, ["decrypt"]);
80    const plaintext = await crypto.subtle.decrypt(
81        {
82            name: "AES-CBC",
83            iv: fromBase64(ivBase64)
84        },
85        key,
86        fromBase64(dataBase64));
87
88    return toBase64(new Uint8Array(plaintext));
89}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.