file-encryption
AES-256-GCM file encryption and PBKDF2 key derivation as used in health-records-vault. Use when you need to understand or implement the encryption model, derive a key from a password, encrypt or decrypt a file manually, restore an encrypted backup, or verify the cryptographic integrity of a .enc file. Triggers include "AES-256-GCM", "PBKDF2", "decrypt .enc file", "restore backup", "encryption key derivation", "IV", "salt", or any task about the cryptographic internals of the vault.
Best use case
file-encryption is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
AES-256-GCM file encryption and PBKDF2 key derivation as used in health-records-vault. Use when you need to understand or implement the encryption model, derive a key from a password, encrypt or decrypt a file manually, restore an encrypted backup, or verify the cryptographic integrity of a .enc file. Triggers include "AES-256-GCM", "PBKDF2", "decrypt .enc file", "restore backup", "encryption key derivation", "IV", "salt", or any task about the cryptographic internals of the vault.
Teams using file-encryption should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/file-encryption/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How file-encryption Compares
| Feature / Agent | file-encryption | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
AES-256-GCM file encryption and PBKDF2 key derivation as used in health-records-vault. Use when you need to understand or implement the encryption model, derive a key from a password, encrypt or decrypt a file manually, restore an encrypted backup, or verify the cryptographic integrity of a .enc file. Triggers include "AES-256-GCM", "PBKDF2", "decrypt .enc file", "restore backup", "encryption key derivation", "IV", "salt", or any task about the cryptographic internals of the vault.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# file-encryption
AES-256-GCM encryption model used by health-records-vault. Covers key derivation, encryption, decryption, and manual restoration from a backup archive.
## Encryption model overview
```
master password + salt
|
v
PBKDF2(password, salt, 100000 iterations, SHA-256, 32 bytes)
|
v
256-bit AES key (K)
|
v
IV = randomBytes(12) # unique per file
|
v
AES-256-GCM.encrypt(K, IV, plaintext) -> ciphertext + authTag (16 bytes)
|
v
stored on disk: ciphertext || authTag (.enc file)
stored in DB: IV (hex), salt (hex)
```
Key points:
- Every file has a unique 12-byte IV and a unique 32-byte salt
- The auth tag provides integrity verification (tampering detection)
- The master password is never stored anywhere
- The derived key exists only in server RAM for the duration of the session
## PBKDF2 parameters
| Parameter | Value |
|---|---|
| Hash | SHA-256 |
| Iterations | 100,000 |
| Key length | 32 bytes (256 bits) |
| Salt length | 32 bytes (256 bits, random per file) |
## Encrypting a file (Node.js)
```typescript
import crypto from 'node:crypto';
import fs from 'node:fs';
function encryptFile(
plaintextPath: string,
outputPath: string,
key: Buffer // 32-byte derived key
): { iv: string; salt: string } {
const iv = crypto.randomBytes(12);
const salt = crypto.randomBytes(32);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const plaintext = fs.readFileSync(plaintextPath);
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const authTag = cipher.getAuthTag(); // 16 bytes
fs.writeFileSync(outputPath, Buffer.concat([ciphertext, authTag]));
return {
iv: iv.toString('hex'),
salt: salt.toString('hex'),
};
}
```
## Decrypting a file (Node.js)
```typescript
function decryptFile(
encPath: string,
key: Buffer, // 32-byte derived key
ivHex: string,
saltHex: string // saltHex is stored in DB but not used directly here
): Buffer {
const iv = Buffer.from(ivHex, 'hex');
const raw = fs.readFileSync(encPath);
// Last 16 bytes are the auth tag
const authTag = raw.slice(raw.length - 16);
const ciphertext = raw.slice(0, raw.length - 16);
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
}
```
If the auth tag does not match, `decipher.final()` throws `Error: Unsupported state or unable to authenticate data`. This indicates tampering or a wrong key.
## Deriving a key from password
```typescript
function deriveKey(password: string, saltHex: string): Promise<Buffer> {
return new Promise((resolve, reject) => {
crypto.pbkdf2(
password,
Buffer.from(saltHex, 'hex'),
100_000,
32,
'sha256',
(err, key) => (err ? reject(err) : resolve(key))
);
});
}
```
Note: each file stores its own salt in the DB. To decrypt file X, use X's salt to re-derive the key.
## Manually restoring from a backup archive
Given a backup .zip archive from `/api/backup`:
1. Extract the archive
2. Open `vault-metadata.json` to get the list of records with their IV and salt values
3. For each record, derive the key using the stored salt and your master password
4. Decrypt the .enc file using the derived key and stored IV
```bash
# Example using the Node.js REPL or a restore script
node restore.mjs \
--archive vault-backup-2026-03-20.zip \
--password "your-master-password" \
--output ./restored/
```
## Verifying file integrity
A successful AES-256-GCM decryption proves:
- The file was encrypted with a key derived from your password
- The ciphertext has not been tampered with since encryption
- The IV matches the one stored in the database
If decryption throws an authentication error, possible causes are:
- Wrong master password (wrong key derived)
- .enc file has been corrupted or modified
- IV stored in the database does not match the IV used during encryption
## Security considerations
- Never log the derived key or decrypted file contents
- Delete the plaintext temp file immediately after encryption (multer temp file)
- Use `crypto.timingSafeEqual` for any token comparison to prevent timing attacks
- The session key must not be serialized to a persistent session store (use memory store only)
- In production: set `NODE_ENV=production` to enable `secure: true` on the session cookie
## File format of .enc files
```
+------ ciphertext (variable length) ------+---- auth tag (16 bytes) ----+
| AES-256-GCM encrypted content | GCM authentication tag |
+-------------------------------------------+-----------------------------+
```
The IV and salt are stored separately in the SQLite database. They are not embedded in the .enc file itself.Related Skills
file-sharing
Upload files, create expiring share links with optional password protection, and track downloads on a self-hosted file drop service.
file-permissions
Reference guide for Unix file permission bits, octal notation, symbolic notation, and security-relevant permission combinations used by the permissions-auditor rules engine.
env-encryption
AES-256-GCM encryption and PBKDF2 key derivation patterns for secure secret storage in Node.js
file-tree-diff
Compare two directory trees and show added, removed, and changed files with color output. Use when you need to compare two versions of a directory, find what changed between releases, audit differences between staging and production file sets, or verify a deployment. Triggers include "compare directories", "directory diff", "what changed in", "file differences between", "ftd", "tree diff".
machine-profiles
Use dotfile-sync profiles to manage machine-specific configurations. Use when different machines need different subsets of dotfiles, handling OS-specific configs, or setting up work vs personal machine profiles. Triggers include "machine profile", "per-machine config", "dfs profile", "different configs per machine", "work vs home dotfiles".
dotfile-sync
Manage dotfiles with symlinks from a central git repository. Use when tracking config files, syncing dotfiles between machines, or bootstrapping a new machine. Triggers include "dotfiles", "sync config", "dfs", "track dotfiles", "symlink config", "new machine setup".
file-processing
Handle file upload, validation, processing pipelines, and temporary file management in Node.js servers. Use when building file processing APIs with Express and multer, managing temporary files with cleanup, or implementing secure file handling patterns. Triggers include "file upload", "multipart form", "temp file cleanup", "multer config", or any server-side file handling task.
Skill: Uptime Monitoring
## Overview
Skill: Status Page
## Overview
Skill: unit-conversion
## Overview
Skill: recipe-scaler
## Overview
reading-list
Operate the reading-list API to save, manage, tag, search, and export articles.