CipherPadTransparent encryption editor for VS Code — edit plaintext, save ciphertext. CipherPad lets you edit Features
Screenshots
Getting StartedInstallationOption A — VS Code Marketplace:
Option B — Manual VSIX:
UsageCreating a new encrypted file
Opening an existing
|
| Command | Description |
|---|---|
CipherPad: Change Password |
Re-encrypt the current file with a new password |
CipherPad: Show History |
View all saved snapshots with timestamps |
CipherPad: Restore from History |
Restore a previous snapshot as the current version |
CipherPad: Export Plaintext |
Export decrypted content to a temporary .txt file |
Decrypting Without VS Code
CipherPad uses AES-256-CBC with an explicit random IV and PBKDF2 key derivation.
Because the IV is stored separately in the file (not derived from the password), you need
a two-step process: first derive the key from the password+salt, then pass the key and IV
explicitly to openssl enc -K/-iv.
Full decryption script (Python + openssl)
#!/usr/bin/env python3
"""
decrypt_ctxt.py — Decrypt a CipherPad .ctxt file
Usage: python3 decrypt_ctxt.py secrets.ctxt
"""
import json, sys, base64, hashlib, subprocess, getpass
def main():
file_path = sys.argv[1] if len(sys.argv) > 1 else input("Path to .ctxt file: ")
password = getpass.getpass("Password: ")
with open(file_path) as f:
data = json.load(f)
latest = data["history"][0]
salt_b = base64.b64decode(latest["salt"])
iv_b = base64.b64decode(latest["iv"])
cipher = latest["ciphertext"]
# Derive 256-bit key with PBKDF2-SHA256 (100000 iterations)
key = hashlib.pbkdf2_hmac("sha256", password.encode(), salt_b, 100000, dklen=32)
key_hex = key.hex()
iv_hex = iv_b.hex()
# Pipe ciphertext through openssl
result = subprocess.run(
["openssl", "enc", "-d", "-aes-256-cbc",
"-K", key_hex, "-iv", iv_hex, "-base64"],
input=cipher.encode(),
capture_output=True
)
if result.returncode != 0:
print("Decryption failed:", result.stderr.decode(), file=sys.stderr)
sys.exit(1)
print(result.stdout.decode(), end="")
if __name__ == "__main__":
main()
Quick one-liner (bash — requires Python 3)
PASSWORD="your_password"
FILE="secrets.ctxt"
python3 -c "
import json, base64, hashlib
data = json.load(open('$FILE'))
h = data['history'][0]
key = hashlib.pbkdf2_hmac('sha256', b'$PASSWORD', base64.b64decode(h['salt']), 100000, 32)
print(key.hex(), base64.b64decode(h['iv']).hex(), h['ciphertext'])
" | read KEY IV CIPHER && echo "\$CIPHER" | openssl enc -d -aes-256-cbc -K "\$KEY" -iv "\$IV" -base64
Why not openssl enc -pbkdf2 -pass pass:... directly?
openssl enc -pbkdf2 derives both the key AND the IV from the password in one step,
discarding any explicit IV. CipherPad intentionally generates a cryptographically random
IV per save (stronger security — prevents ciphertext comparison attacks across saves),
which requires the explicit -K key_hex -iv iv_hex form of openssl enc.
The security properties are equivalent; the decryption is just a two-step process.
File Format
.ctxt files are stored as JSON on disk:
{
"version": 1,
"algorithm": "aes-256-cbc",
"kdf": "pbkdf2",
"iterations": 100000,
"history": [
{
"salt": "<base64-encoded salt>",
"iv": "<base64-encoded IV>",
"ciphertext": "<base64-encoded ciphertext>",
"savedAt": "2024-01-15T10:30:00.000Z",
"hint": ""
},
{
"salt": "...",
"iv": "...",
"ciphertext": "...",
"savedAt": "2024-01-14T09:00:00.000Z",
"hint": ""
}
]
}
history[0]is always the most recent version- Up to 3 snapshots are kept (oldest are discarded)
- Each snapshot uses an independently generated salt and IV
- The password is never stored in the file
Security Notes
- AES-256-CBC with random IV per save (prevents ciphertext comparison attacks)
- PBKDF2-SHA256 with 100,000 iterations (slows down brute-force)
- Passwords are stored in memory only — cleared on file close and extension deactivation
- History snapshots are re-encrypted if you change the password
Requirements
- VS Code 1.85.0 or later
- No external npm dependencies — uses Node.js built-in
cryptomodule
License
MIT

