Encrypted Notes (ep-plugin)

unlisted

by ep-plugin

Create notes that are encrypted on disk with a passphrase (AES-GCM 256). Open them inside Obsidian with the same passphrase.

1 starsUpdated 11d agoMIT
View on GitHub

ep-plugin — Encrypted Notes

把 Obsidian 的笔记用 AES-GCM 256 + PBKDF2 加密后存盘。任何不安装本插件的软件打开文件只会看到 base64 密文;在 Obsidian 里输入密码即可解密、正常编辑、保存时自动重新加密。

Release Downloads License Topics

📥 Download latest release · Report bug · Request feature

Encrypted note open in the editor, decrypted and ready to edit


目录


特性

  • 🔐 强加密:AES-GCM 256 位,PBKDF2 / SHA-256 / 250 000 次派生密钥
  • 📁 磁盘上始终是密文:除了本插件,没有任何软件能读出原文
  • 🔄 透明的保存流程:保存时自动加密,编辑器里仍是明文
  • 🚀 零摩擦切 tab:已解锁的笔记,切来切去永远显示明文,不会变密文
  • 🔑 改密码:随时改,文件重新加密写盘
  • 🔓 永久解密:一键把加密文件转回明文(一次性、不可逆)
  • 🖱️ 右键菜单 + 工具栏按钮 + 命令面板:三种入口
  • 🤖 AI Agent 集成:附带的 ep CLI 共用同一份加密代码,AI agent 可以读 / 写加密笔记

安装

方式 A:从 GitHub Release 直接装(推荐给普通用户)

每个 release 提供两个 zip,按需取用:

文件内容给谁
ep-plugin.zipmain.js + manifest.json + styles.cssObsidian 用户
ep-cli.zipep (含 shebang,10 KB)AI agent / CLI 用户

Obsidian 端:

  1. Releases 下载最新版的 ep-plugin.zip
  2. 在你的 vault 里建目录:<vault>/.obsidian/plugins/ep-plugin/
  3. ep-plugin.zip 里的三个文件解压进去
  4. Obsidian → Settings → Community plugins → Installed plugins → 打开 Restricted mode(如果开着)→ 找到 Encrypted Notes (ep-plugin)Enable

CLI 端(让 AI agent 读写加密笔记):

  1. 下载 ep-cli.zip
  2. 解压得到单个 ep 文件
  3. chmod +x ep && mv ep /usr/local/bin/(或任何 $PATH 目录)
  4. export EP_PASSPHRASE='你的密码'

方式 B:从源码构建(开发者)

git clone https://github.com/yccb-ly/ep-plugin.git
cd ep-plugin
npm install
npm run build       # 生产构建,产物在 main.js
# 然后把整个目录链接或复制到 <vault>/.obsidian/plugins/ep-plugin/
# 想边改边自动重新构建?
npm run dev

快速上手

第 1 步:创建一个加密笔记

两种方式:

  • 点击左侧 ribbon 的 🔒 图标
  • 命令面板搜 "Create encrypted note"

弹出对话框:

create modal

填文件名 + 两次密码 → Create。

ASCII mockup:
┌────────────────────────────────────────────┐
│ Create encrypted note                      │
│ ─────────────────────────────────────      │
│ File name (with or without .md)            │
│ ┌────────────────────────────────────┐     │
│ │ my-secret.md                       │     │
│ └────────────────────────────────────┘     │
│ Passphrase                                 │
│ ┌────────────────────────────────────┐     │
│ │ ••••••••                           │     │
│ └────────────────────────────────────┘     │
│ Confirm passphrase                         │
│ ┌────────────────────────────────────┐     │
│ │ ••••••••                           │     │
│ └────────────────────────────────────┘     │
│                       [ Cancel ] [ Create ]│
└────────────────────────────────────────────┘

新文件落盘后会自动在当前 pane 打开,并显示解密后的内容(默认模板):

after create

第 2 步:写入内容 + Ctrl+S

正常写文字,正常保存。插件会在 Vault.modify 这一步拦截,自动加密再写盘。编辑器里始终是明文,磁盘上始终是密文。

第 3 步:用其它软件打开验证

cat 一下那个 .md

$ cat /path/to/vault/my-secret.md
RVBNA...(一坨 base64)...AAAA==

任何不知道密码的人 / 软件都只能看到这串密文。

第 4 步:关掉再打开 → 自动解密

关掉这个 tab → 在文件管理器重新点开同一个文件 → 不需要重新输密码(密码还在内存里),Obsidian 会自动调用 vault.read,被插件拦截后返回明文,渲染在编辑器里。

完全退出 Obsidian 再开 → 弹密码框 → 输入正确密码 → 解密。

操作截图

⚠️ 截图占位:请把实际截图放到 docs/screenshots/ 下,文件名对应下面的引用。

#场景文件
01创建加密笔记的弹窗docs/screenshots/01-create.png
02创建后的编辑器(明文)docs/screenshots/02-after-create.png
03重新打开时的密码弹窗docs/screenshots/03-unlock.png
04工具栏上的 🔒 按钮docs/screenshots/04-toolbar.png
05编辑器内右键菜单docs/screenshots/05-editor-menu.png
06文件管理器右键菜单docs/screenshots/06-file-menu.png
07永久解密的确认弹窗docs/screenshots/07-decrypt-confirm.png
08加密文件用其它软件打开docs/screenshots/08-other-software.png

ASCII mockup:编辑器内右键菜单(已解锁状态)

┌──────────────────────────────────────┐
│ ─────────────────────────────────    │
│ 🔒 Lock note (ep-plugin)             │
│ 🔑 Change passphrase (ep-plugin)     │
│ 📝 Decrypt → save as plaintext       │     ← ep-plugin
│ ─────────────────────────────────    │
│ Cut                                 │
│ Copy                                │
│ Paste                               │
│ ...                                 │
└──────────────────────────────────────┘

所有命令与菜单

命令面板

命令何时可用
Create encrypted note总是
Encrypt / Unlock note (current)编辑器中(智能判断:明文加密 / 密文解锁)
Lock current note (forget passphrase)已解锁文件
Change passphrase for current encrypted note已解锁文件
Decrypt current note (save as plaintext, one-way)已解锁文件

右键菜单

文件管理器右键(.md 文件):

  • 🔒 Encrypt / Unlock note (ep-plugin) — 点下去智能判断

编辑器内右键:

  • 未解锁时:🔒 Encrypt / Unlock note (ep-plugin)
  • 已解锁时:
    • 🔒 Lock note (ep-plugin)
    • 🔑 Change passphrase (ep-plugin)
    • 📝 Decrypt → save as plaintext (ep-plugin)

工具栏(编辑器右上角)

打开加密文件时会出现一个锁形按钮:

状态图标点击效果
加密 + 未解锁🔒弹密码框 → 解密
加密 + 已解锁🔓立刻忘掉密钥,编辑器内容变回密文
明文文件不显示按钮

AI Agent 集成 (ep CLI)

仓库里附带一个 ep 命令行工具,跟 Obsidian 插件 共用同一份加密代码src/crypto.ts),所以 AI agent(Claude Code 等)可以读 / 写加密笔记,磁盘上始终是密文。

它能干什么

ep decrypt <note> --out <file>     # 解密 → file(agent 接下来 Edit/Write)
ep encrypt <note> --from <file>   # file → 加密写回 note(原子写)
ep cat <note>                     # 解密到 stdout(明文则透传)
ep pipe <note>                    # 从 stdin 读明文,加密覆盖 note
ep is-encrypted <note>            # exit 0 = 加密,1 = 明文,3 = 缺文件
ep info <note>                    # JSON: { encrypted, version?, sizeBytes }

Exit code 约定

Code含义Agent 怎么处理
0成功继续
2密码错停下来问用户,别瞎试
3文件不存在ls 确认路径
64用法错 / 缺 EP_PASSPHRASE重读 --help
65数据格式错别解密,问用户

安装

git clone https://github.com/yccb-ly/ep-plugin.git
cd ep-plugin
npm install
npm run build            # 同时产出 main.js (Obsidian) 和 bin/ep.js (CLI)

# 全局安装 ep 命令
npm link                 # 或:ln -s "$PWD/bin/ep.js" /usr/local/bin/ep

一次性配置密码

把密码写到 shell 启动文件里,让 Claude Code 这类 agent 自动继承。不要export EP_PASSPHRASE=… 直接在命令行执行 —— 会进 ~/.zsh_history

# ~/.zshenv(或 ~/.bashrc)
export EP_PASSPHRASE='你的密码'
chmod 600 ~/.zshenv     # 文件含 secret,必须 600

典型 agent 工作流

# 1. 把加密笔记解开到 tmp
ep decrypt "/path/to/vault/secret.md" --out /tmp/ep-xyz.md

# 2. agent 用 Read / Edit / Write 工具改 /tmp/ep-xyz.md(明文)

# 3. 改完重新加密写回原文件
ep encrypt "/path/to/vault/secret.md" --from /tmp/ep-xyz.md

# 4. 销毁 tmp
shred -u /tmp/ep-xyz.md     # Linux
rm -P /tmp/ep-xyz.md        # macOS

⚠️ 并发注意:如果 Obsidian 那边同一个笔记已经打开并解锁,agent 用 ep pipe / ep encrypt 改完后,下次 Obsidian 保存会用缓存的旧明文覆盖。先让用户关掉 Obsidian 那个 tab 再让 agent 改。

更详细的 agent 视角说明(Claude Code 的 ep-notes skill)见 ~/.claude/skills/ep-notes/SKILL.md


文件格式

┌──────────────────────────────────────────────────────┐
│ 字节偏移   长度   含义                               │
├──────────────────────────────────────────────────────┤
│ 0         6      魔数 "EPMARK"                       │
│ 6         1      格式版本 (0x01)                     │
│ 7         16     PBKDF2 salt(每文件随机)           │
│ 23        12     AES-GCM IV / nonce(每文件随机)    │
│ 35        …      密文(WebCrypto 自动追加 16B tag)  │
└──────────────────────────────────────────────────────┘

整体 base64 编码成一个字符串,所以 .md 后缀不变,任何文本编辑器都能打开(看到的只是 base64)。

file on disk (UTF-8):
"RVBNQVJLAQDDT9...AAAA=="
   ↓ base64 decode
bytes:  45 50 4D 41 52 4B 01 73 32 9a ... a3 ff 12
        └─EPMARK─┘ │└──── salt ────┘│└ IV ┘└ ct+tag ┘

安全说明

  • 密码仅存内存Map<path, passphrase>,插件卸载 / Obsidian 关闭即清空。下次再开要重新输。
  • 不强求密码强度:插件不限制密码长度或复杂度,但 弱密码 = 弱保护,请用长密码 / 密码管理器生成。
  • PBKDF2 250 000 轮:这让暴力破解一个强密码的成本很高(每次猜测 ~250ms)。
  • 每文件独立 salt + IV:同一明文 + 同一密码,每次加密结果都不同。
  • decryptAndSaveAsPlaintext 是不可逆的:执行后文件就是普通明文 .md 了,不会再被这个插件加密。如果想反悔,只能再次手动 Encrypt / Unlock note

已知边界

  • 不防键盘记录器 / 屏幕录像:输入密码时自己注意环境。
  • 不防已经 root 的恶意进程:如果有人能读 Obsidian 的内存,密码理论上能拿到。
  • 明文只在编辑器里短暂存在:写盘永远是密文,但解密后编辑器内存里有明文,直到文件锁 / 关闭。

开发与构建

项目结构

ep-plugin/
├── manifest.json          # 插件元信息(id、版本、minAppVersion…)
├── main.ts                # Obsidian 插件源码(UI、命令、读写拦截)
├── src/
│   └── crypto.ts          # 加密核心(main.ts 和 bin/ep.ts 都引用这一份)
├── bin/
│   ├── ep.ts              # CLI 源码
│   └── ep.js              # CLI 产物(构建生成,gitignore)
├── test/
│   └── roundtrip.test.ts  # node:test round-trip 测试
├── styles.css             # 模态框样式
├── tsconfig.json          # TypeScript 配置
├── esbuild.config.mjs     # esbuild 打包脚本(多入口:main + bin/ep)
├── package.json
├── versions.json          # 插件版本 → Obsidian 最低版本映射
├── LICENSE                # MIT
├── docs/                  # README 引用的截图
├── scripts/
│   ├── release.mjs        # `npm run release` 的发布打包脚本
│   └── zip-writer.mjs     # 零依赖 STORE-method zip writer
└── README.md

开发流程

npm install
npm run dev          # watch 模式,main.ts / bin/ep.ts / src/crypto.ts 任一改动都自动重建
npm run typecheck    # tsc --noEmit
npm test             # node:test round-trip(13 个测试)

发布流程

打 release tag 时跑一条命令,产出两个 zip 到 release/

npm run release      # 先 build,再产出 release/ep-plugin.zip + release/ep-cli.zip
产物大小(参考)用途
release/ep-plugin.zip~36 KBObsidian 端安装(直接拖进 .obsidian/plugins/ep-plugin/
release/ep-cli.zip~11 KBCLI 端安装(解压 → chmod +x → 放到 $PATH

release/ 目录已 gitignore,里面的 zip 不进仓库;走 GitHub Releases 分发。zip writer 是 scripts/zip-writer.mjs,零依赖(用 Node 内置 zlib + 手写 STORE 头),所以发布脚本不引入任何运行时依赖。

如何加新功能

想加什么改哪里
新命令onload() 里加 this.addCommand({...})
新右键菜单项file-menu / editor-menu 监听
新工具栏按钮refreshToggleButton() 已经管了大多数情况
新加密算法只改 src/crypto.tsencryptContent / decryptContent,同步升级 VERSIONisEncryptedFile;插件和 CLI 自动同步
新弹窗仿 PassphraseModal / ConfirmModal
给 CLI 加新子命令bin/ep.tscase "..." 一处,外加 README 里 ## 所有命令与菜单 加一行

常见问题

Q: 我忘了密码怎么办? A: 没办法。设计如此。如果想保留数据,先确保你记得至少一个版本的密码;否则这个文件就废了。

Q: 文件能改扩展名 / 后缀吗? A: 可以,但插件目前只对 .md 后缀生效(这是默认配置,Settings 里可改 "Default file extension")。扩展名变了,isEncryptedFile 仍然能识别(靠魔数 EPMARK),只是插件不会自动触发解密。

Q: 我把 vault 同步到云盘 / Git,安全吗? A: 文件在云上 / Git 里就是密文(除非你执行过 Decrypt → save as plaintext)。只要密码不泄漏,云端偷走也解不出来。

Q: 跟其它"加密笔记"插件有什么不一样? A: 大多数同类插件是把内容存到一个外部 vault / 数据库,不修改 markdown 源文件。本插件是 真正的 .md 文件本身加密,磁盘上是 base64 密文,所以哪怕用 Obsidian 之外的软件看,看到的也是密文。

Q: 切 tab 会不会突然变密文? A: 不会。只要 Lock current note 没主动执行过(或者 Obsidian 没退出),同一个 vault 会话内密码一直在内存里,切 tab、切文件再切回来都是明文。

Q: 我想让 AI agent 帮我改加密笔记,怎么搞? A: 仓库里附带的 ep CLI 就是干这个的。装好后 export EP_PASSPHRASE='...',agent 调 ep decrypt … --out /tmp/x.md → 用 Edit/Write 改 tmp → ep encrypt … --from /tmp/x.md 写回,全程磁盘上是密文。详见 AI Agent 集成 一节。

Star History

如果这个插件帮到你了,欢迎点 ⭐!也欢迎提 Issue / PR。


MIT License · Made with ❤️ for the Obsidian community

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.