-
Notifications
You must be signed in to change notification settings - Fork 106
Home
Encrypt individual Hexo blog posts at build time. Readers enter a password and decrypt client-side via the Web Crypto API. Zero server. Zero plaintext on disk after the build.
🔗 Live demo · 📦 npm · 📝 Source · 📋 Changelog
| Crypto | PBKDF2-SHA256 key derivation + AES-256-GCM authenticated encryption (Node.js crypto server-side, Web Crypto in the browser). The GCM auth tag detects ciphertext tampering — no separate HMAC needed. |
| Per-post salt + nonce | Every encrypted post gets a fresh 32-byte salt and 12-byte nonce. Two posts with identical content + password produce different ciphertexts. |
| 8 themes |
default, blink, flip, shrink, surge, up, wave, xray — see the Themes gallery. |
| Optional Decrypt button | Visible click-to-decrypt button alongside the password field. Configurable label. |
Optional autoSave |
Off by default. Opt in to cache the derived key in localStorage so reloads skip the prompt. |
Optional stableSalt |
Off by default. Derives the salt from the post permalink so it stays stable across clean rebuilds — keeps autoSave caches valid on Cloudflare Pages / Vercel / Netlify / GitHub Actions. Nonce stays random. See Security Model. |
| Tag-based encryption | Define a {name, password} registry in _config.yml; matching post tags get encrypted with the registry password. |
| Decryption callback |
window.addEventListener('hexo-blog-decrypt', fn) — re-init MathJax / hljs / TOC / etc. after the post reveals. |
| Tested | 158 server tests at 100 % coverage + 44 Playwright e2e tests across all 8 themes. CI green on every push. |
New here? → Getting Started — install + first encrypted post in 60 seconds.
Upgrading from v3? → Migration v3 → v4 — what changed and why.
Need a config option? → Configuration Reference — every key, every default.
Want a custom look? → Themes — 8 built-in themes + how to roll your own.
Embedding JS / MathJax / hljs? → Callbacks & MathJax — the hexo-blog-decrypt event with worked examples.
Encrypting by tag instead of per-post? → Tag-Based Encryption.
How safe is this, really? → Security Model — what is and isn't protected.
Decryption silently fails? → Browser Support and Troubleshooting.
Have a question? → FAQ.
# _config.yml
encrypt:
abstract: 'This post is locked.'
message: 'Password required.'
theme: default---
title: My Diary
date: 2024-01-01
password: hello
---
Only the holder of the password "hello" can read this.
<!-- more -->
The secret is...hexo clean && hexo generateOpen the post → prompt appears → type hello → click Decrypt → content reveals.
MIT. See LICENSE.