I built mdenc because I wanted to keep internal team docs in a public git repo without them being in plaintext, but GPG-encrypting whole files makes every commit a full-file diff.
mdenc encrypts at paragraph granularity with XChaCha20-Poly1305. Unchanged paragraphs produce identical ciphertext, so git only tracks what you actually edited. One paragraph changed = one line in the diff.
The tradeoff: it's deterministic encryption (same plaintext + same key = same ciphertext), which leaks some metadata (paragraph count, sizes, edit patterns). This is intentional -- it's what makes diffs work.
It uses git's native smudge/clean filter, so after setup you just `git add` and `git checkout` normally. Plaintext in your working directory, ciphertext in the repo.
Important caveats I want to be upfront about:
- *Not audited.* The crypto primitives are from audited libraries (@noble/ciphers, @noble/hashes), but the protocol itself has not been independently reviewed.
- *Not for real secrets.* The password is shared with everyone who needs access. A widely-shared password is a single point of failure. This is for internal docs that shouldn't be in plaintext on the internet, not for credentials or PII.
- *No forward secrecy.* Password + git history = full decrypt of all historical versions.
I built mdenc because I wanted to keep internal team docs in a public git repo without them being in plaintext, but GPG-encrypting whole files makes every commit a full-file diff.
mdenc encrypts at paragraph granularity with XChaCha20-Poly1305. Unchanged paragraphs produce identical ciphertext, so git only tracks what you actually edited. One paragraph changed = one line in the diff.
The tradeoff: it's deterministic encryption (same plaintext + same key = same ciphertext), which leaks some metadata (paragraph count, sizes, edit patterns). This is intentional -- it's what makes diffs work.
It uses git's native smudge/clean filter, so after setup you just `git add` and `git checkout` normally. Plaintext in your working directory, ciphertext in the repo.
Important caveats I want to be upfront about:
- *Not audited.* The crypto primitives are from audited libraries (@noble/ciphers, @noble/hashes), but the protocol itself has not been independently reviewed.
- *Not for real secrets.* The password is shared with everyone who needs access. A widely-shared password is a single point of failure. This is for internal docs that shouldn't be in plaintext on the internet, not for credentials or PII.
- *No forward secrecy.* Password + git history = full decrypt of all historical versions.
Spec: https://github.com/yogh-io/mdenc/blob/main/SPECIFICATION.md
Security model: https://github.com/yogh-io/mdenc/blob/main/SECURITY.md
Live demo: https://yogh-io.github.io/mdenc/
npm: https://www.npmjs.com/package/mdenc
Would love feedback on the construction.