Shockwave330123 downloadsEncrypt and decrypt selected text in place with AES-256-GCM. No external tools, binaries or key files.
Select any text in a note, give it a password, and it becomes unreadable on disk. Everything else in the note stays exactly as it was.
Most encryption tools for Obsidian work on whole notes or whole vaults. This one works on a selection: a password, a recovery code, a paragraph of a journal entry, one line of an otherwise ordinary note. You highlight it, run a command, type a password, and the highlighted text is replaced by an opaque token. The rest of the note is untouched and still searchable, linkable and editable.
Reading it back does not require putting the plaintext into the note again. The primary read command, peek, decrypts into a modal and leaves the file alone, so the plaintext never reaches disk just because you wanted to look at it.
Encryption is AES-256-GCM through the browser's own Web Crypto API. There are no external binaries, no key files, no GPG setup and no runtime dependencies, and it works on mobile as well as desktop.

From inside Obsidian: Settings → Community plugins → Browse, search for Encrypt Selection, install and enable it.
Manually: download main.js, manifest.json and styles.css from the latest release into <your vault>/.obsidian/plugins/encrypt-selection/, then enable the plugin in Settings → Community plugins.
Three things, in about a minute:
Ctrl/Cmd + P) and run Encrypt. Type a password, then type it again to confirm. The selected text is replaced by a token.Use Decrypt in place only when you actually need to edit the text, and re-encrypt when you are done. That command writes the plaintext back into the file.
Before:
Router admin: 192.168.1.1 — password hunter2-correct-horse
After encrypting the password with a single-line selection, you get an inline code span:
Router admin: 192.168.1.1 — password `aes256:rlIBAQEAAAGGoAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDE=`
A multi-line selection becomes a fenced block instead:
```aes256
rlIBAQEAAAGGoAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd
Hh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNE
```
In reading view neither form shows up as a wall of base64. Both render as a lock pill you can click to decrypt; the text is revealed in that view only and the file is never rewritten. Click again to hide it.

Locked: a fenced block renders as one pill, with no base64 in sight.

Unlocked: the text is revealed in this view only. The file on disk is unchanged, and "hide" locks it again.
All four live in the command palette.
| Command | What it does | Touches the file? |
|---|---|---|
| Encrypt | Replaces the highlighted text with an encrypted token | Yes |
| Decrypt (peek, read-only) | Shows the plaintext in a modal | No |
| Decrypt in place | Writes the plaintext back into the note so you can edit it | Yes |
| Forget the cached password | Clears the password held in memory | No |
Both decrypt commands find the token from your cursor position, so you can simply click into it. If decryption fails — wrong password, altered text — you get a notice and the note is left exactly as it was.
| Setting | Default | Notes |
|---|---|---|
| Token style | Auto | Auto uses an inline span for single-line selections and a fenced block for multi-line ones. Can be forced either way. |
| Key derivation iterations | 600,000 | PBKDF2 rounds, between 100,000 and 5,000,000. Stored in each payload, so changing it never breaks existing text. |
| Confirm password when encrypting | On | Asks twice. A typo here is unrecoverable. Leave it on. |
| Offer a password hint | Off | Adds an optional hint field. The hint is stored unencrypted next to the ciphertext — it has to be readable before you type the password. |
| Remember password for this session | On | Keeps the password in memory until Obsidian closes. Never written to disk. |
| Show lock widget in reading view | On | Renders tokens as a clickable lock pill instead of base64. |
This plugin exists for one threat: someone gets your vault files — a stolen laptop, a synced folder on a compromised machine, a backup someone else can read. It is not designed to hide anything from software already running as you on an unlocked machine.
Encrypting the text is not the whole job. Several Obsidian features keep copies of your notes from before you encrypted them, and encrypting today does nothing about yesterday's copy.
The plugin repeats the first two warnings in its settings tab, since they are the ones most likely to catch you out.
Also true, and unavoidable:
Bank logins.md does not hide much.Verifiable in the source, and in the shipped main.js:
fetch, no XMLHttpRequest, no WebSocket, no remote assets. The built bundle contains no URLs. Your passwords and note contents never leave the machine, because there is nothing in the code that could send them.eval, no new Function, no downloaded scripts. It cannot change its own behaviour after installation.main.js is built from this repository's source and requires nothing but obsidian itself, so there is no third-party code in the trust surface and no supply chain to compromise.For a tool whose entire job is keeping secrets, "you can check this yourself" matters more than any promise. Everything above is a one-line grep against the source or the released bundle.
If you forget the password, the text is gone. Permanently. There is no backdoor, no reset, no support address that can help, and no amount of remembering nearly the right password will do. That is exactly what makes it work.
The confirm-password prompt is on by default for this reason. Leave it on, and keep the password somewhere that is not the note you just encrypted.
saveData().npm install
npm test # crypto round-trip, tamper detection, token parsing
npm run typecheck
npm run build # production bundle
npm run dev # watch mode
npm run dev builds and installs the plugin into the throwaway test-vault/ inside this repository (test-vault/.obsidian/plugins/encrypt-selection/). Open that folder as a vault in Obsidian — File → Open vault → Open folder as vault — and enable the plugin there.
You can point the install elsewhere with the OBSIDIAN_PLUGIN_DIR environment variable, and the build will warn you loudly when you do. Never point it at a vault you care about: dev builds reload on every keystroke, and this plugin writes ciphertext into notes.
src/crypto/ AES-GCM + PBKDF2 and the binary payload format (pure, unit-tested)
src/format/ how tokens are written into and found in markdown (pure, unit-tested)
src/ui/ password modal, peek modal, reading-view pill
src/commands.ts command handlers
src/session.ts in-memory password and derived-key cache
src/settings.ts settings tab, including the security notice
src/main.ts plugin entry point
crypto/ and format/ never import from obsidian, which is what lets them be tested in plain Node without an Obsidian runtime.
Each token is the base64 encoding of a self-describing binary struct, big-endian and length-prefixed:
magic 0xAE 0x52 | version u8 | kdfId u8 | cipherId u8 | iterations u32be
| saltLen u8 | salt | ivLen u8 | iv | hintLen u16be | hint (UTF-8)
| ciphertext || GCM tag (16 bytes)
Everything before the ciphertext is the header, and the whole header is passed to AES-GCM as additional authenticated data — so it is authenticated but not encrypted. Overhead is about 57 bytes, or roughly 76 base64 characters.
The hint, if you enable it, is stored in the clear by necessity: it has to be readable before the password is known. Do not put anything in a hint that you would not write in the note itself.
In markdown, the base64 appears in one of two forms, both recognised by the same parser (base64 never contains a backtick, so neither form can break its own delimiters):
`aes256:<base64>`aes256, with the base64 wrapped at 64 columnsMIT. See LICENSE.