Skip to content
D0n9X1n edited this page Jun 7, 2026 · 3 revisions

hexo-blog-encrypt

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


What you get in v4

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.

Pick your path

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.


60-second taste

# _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 generate

Open the post → prompt appears → type hello → click Decrypt → content reveals.


License

MIT. See LICENSE.

Clone this wiki locally