Skip to content

Instantly share code, notes, and snippets.

@lynsei
Created February 26, 2025 20:50
Show Gist options
  • Select an option

  • Save lynsei/0f61dfe7819921e64a0f0330bc2a6d93 to your computer and use it in GitHub Desktop.

Select an option

Save lynsei/0f61dfe7819921e64a0f0330bc2a6d93 to your computer and use it in GitHub Desktop.
[deno-keepass]
import { encode as btoa, decode as atob } from "https://deno.land/[email protected]/encoding/base64.ts";
import kdbxweb from "npm:kdbxweb";
// KeePass Configuration
const KEEPASS_DB_PATH = "/path/to/your/database.kdbx";
const KEEPASS_MASTER_PASSWORD = "your-master-password"; // Secure this in an env variable
const TARGET_ENTRY_TITLE = "AES-GCM Key";
const TARGET_ENTRY_URL = "keepass://AES-Key";
// Read the KeePass database
async function readKeepassFile(): Promise<ArrayBuffer> {
const data = await Deno.readFile(KEEPASS_DB_PATH);
return data.buffer;
}
// Fetch encryption key from KeePass
async function fetchKeyFromKeepass(): Promise<CryptoKey> {
const credentials = new kdbxweb.Credentials(kdbxweb.ProtectedValue.fromString(KEEPASS_MASTER_PASSWORD));
const dbData = await readKeepassFile();
const db = await kdbxweb.Kdbx.load(dbData, credentials);
for (const group of db.getDefaultGroup().groups) {
for (const entry of group.entries) {
if (
entry.fields.Title === TARGET_ENTRY_TITLE &&
entry.fields.URL === TARGET_ENTRY_URL
) {
const rawKey = atob(entry.fields.Password);
return await crypto.subtle.importKey(
"raw",
new Uint8Array([...rawKey].map((c) => c.charCodeAt(0))),
{ name: "AES-GCM" },
false,
["encrypt", "decrypt"]
);
}
}
}
console.error("Error: Could not retrieve encryption key from KeePass.");
Deno.exit(1);
}
// Static IV (Should ideally be randomized per encryption)
const IV = new Uint8Array([21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252]);
// Encrypt function
async function encrypt(text: string): Promise<string> {
const key = await fetchKeyFromKeepass();
const encoded = new TextEncoder().encode(text);
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv: IV }, key, encoded);
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}
// Decrypt function
async function decrypt(encryptedText: string): Promise<string> {
const key = await fetchKeyFromKeepass();
const encryptedData = new Uint8Array([...atob(encryptedText)].map((char) => char.charCodeAt(0)));
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: IV }, key, encryptedData);
return new TextDecoder().decode(decrypted);
}
// Command-line argument handling
if (Deno.args.length < 2) {
console.error("Usage: deno run --allow-read encryptor.ts -e|-d <text>");
Deno.exit(1);
}
const mode = Deno.args[0];
const inputText = Deno.args[1];
if (mode === "-e") {
console.log(await encrypt(inputText));
} else if (mode === "-d") {
console.log(await decrypt(inputText));
} else {
console.error("Invalid option. Use -e for encryption or -d for decryption.");
Deno.exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment