Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1,600 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

β–ˆβ–ˆβ–ˆβ–„ β–„β–ˆβ–ˆβ–ˆβ–“ β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ   β–ˆβ–ˆβ–ˆβ–„    β–ˆ   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–„β–„β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆ   β–ˆβ–ˆβ–ˆβ–„ β–„β–ˆβ–ˆβ–ˆβ–“ β–„β–„β–„        β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  β–ˆβ–ˆβ–‘ β–ˆβ–ˆ 
β–“β–ˆβ–ˆβ–’β–€β–ˆβ–€ β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–’  β–ˆβ–ˆβ–’ β–ˆβ–ˆ β–€β–ˆ   β–ˆ β–’β–ˆβ–ˆ    β–’ β–“  β–ˆβ–ˆβ–’ β–“β–’β–“β–ˆ   β–€ β–“β–ˆβ–ˆ β–’ β–ˆβ–ˆβ–’β–“β–ˆβ–ˆβ–’β–€β–ˆβ–€ β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–„    β–’β–ˆβ–ˆ    β–’ β–“β–ˆβ–ˆβ–‘ β–ˆβ–ˆβ–’
β–“β–ˆβ–ˆ    β–“β–ˆβ–ˆβ–‘β–’β–ˆβ–ˆβ–‘  β–ˆβ–ˆβ–’β–“β–ˆβ–ˆ  β–€β–ˆ β–ˆβ–ˆβ–’β–‘ β–“β–ˆβ–ˆβ–„   β–’ β–“β–ˆβ–ˆβ–‘ β–’β–‘β–’β–ˆβ–ˆβ–ˆ   β–“β–ˆβ–ˆ β–‘β–„β–ˆ β–’β–“β–ˆβ–ˆ    β–“β–ˆβ–ˆβ–‘β–’β–ˆβ–ˆ  β–€β–ˆβ–„  β–‘ β–“β–ˆβ–ˆβ–„   β–’β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–‘
β–’β–ˆβ–ˆ    β–’β–ˆβ–ˆ β–’β–ˆβ–ˆ   β–ˆβ–ˆβ–‘β–“β–ˆβ–ˆβ–’  β–β–Œβ–ˆβ–ˆβ–’  β–’   β–ˆβ–ˆβ–’β–‘ β–“β–ˆβ–ˆβ–“ β–‘ β–’β–“β–ˆ  β–„ β–’β–ˆβ–ˆβ–€β–€β–ˆβ–„  β–’β–ˆβ–ˆ    β–’β–ˆβ–ˆ β–‘β–ˆβ–ˆβ–„β–„β–„β–„β–ˆβ–ˆ   β–’   β–ˆβ–ˆβ–’β–‘β–“β–ˆ β–‘β–ˆβ–ˆ 
β–’β–ˆβ–ˆβ–’   β–‘β–ˆβ–ˆβ–’β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–“β–’β–‘β–’β–ˆβ–ˆβ–‘   β–“β–ˆβ–ˆβ–‘β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’  β–’β–ˆβ–ˆβ–’ β–‘ β–‘β–’β–ˆβ–ˆβ–ˆβ–ˆβ–’β–‘β–ˆβ–ˆβ–“ β–’β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–’   β–‘β–ˆβ–ˆβ–’ β–“β–ˆ   β–“β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–‘β–“β–ˆβ–’β–‘β–ˆβ–ˆβ–“
β–‘ β–’β–‘   β–‘  β–‘β–‘ β–’β–‘β–’β–‘β–’β–‘ β–‘ β–’β–‘   β–’ β–’ β–’ β–’β–“β–’ β–’ β–‘  β–’ β–‘β–‘   β–‘β–‘ β–’β–‘ β–‘β–‘ β–’β–“ β–‘β–’β–“β–‘β–‘ β–’β–‘   β–‘  β–‘ β–’β–’   β–“β–’β–ˆβ–‘β–’ β–’β–“β–’ β–’ β–‘ β–’ β–‘β–‘β–’β–‘β–’
β–‘  β–‘      β–‘  β–‘ β–’ β–’β–‘ β–‘ β–‘β–‘   β–‘ β–’β–‘β–‘ β–‘β–’  β–‘ β–‘    β–‘     β–‘ β–‘  β–‘  β–‘β–’ β–‘ β–’β–‘β–‘  β–‘      β–‘  β–’   β–’β–’ β–‘β–‘ β–‘β–’  β–‘ β–‘ β–’ β–‘β–’β–‘ β–‘
β–‘      β–‘   β–‘ β–‘ β–‘ β–’     β–‘   β–‘ β–‘ β–‘  β–‘  β–‘    β–‘         β–‘     β–‘β–‘   β–‘ β–‘      β–‘     β–‘   β–’   β–‘  β–‘  β–‘   β–‘  β–‘β–‘ β–‘
       β–‘       β–‘ β–‘           β–‘       β–‘              β–‘  β–‘   β–‘            β–‘         β–‘  β–‘      β–‘   β–‘  β–‘  β–‘

"He did the mash. He did the monster mash."

Encryption that doesn't bite. Monstermash wraps the battle-tested NaCl (libsodium) cryptography in a friendly CLI, a clean Python API, and an MCP server β€” so developers, engineers, and now AI agents can encrypt things correctly without touching a single cryptographic knob.

1️⃣ version: 2.1.0 Β Β·Β  ✍️ author: Mitchell Lisle

PyPI Python


Why Monstermash?

  • πŸ”’ Safe by default β€” built on NaCl's Box (Curve25519 + XSalsa20-Poly1305). No hand-rolled crypto, no caller-managed nonces, no footguns.
  • πŸͺ„ Decrypt with just your private key β€” the sender's public key rides inside the ciphertext (the "Mashed Envelope"), so the recipient needs nothing extra.
  • 🧰 One tool, three surfaces β€” the same guarantees from the CLI, the Python library, and an optional MCP server for LLMs.
  • πŸ—οΈ Profiles, not key-juggling β€” store keypairs once (mode 0600, just like your SSH keys) and reference them by name.
  • 🚨 Tamper-evident β€” authenticated encryption fails loudly; a corrupted or wrong-key ciphertext raises, it never returns garbage.

Install

pip install monstermash

Want the MCP server for AI agents? Grab the optional extra:

pip install "monstermash[mcp]"

Quickstart

1. Generate a keypair

monstermash generate
-----------------
Private Key (keep it secret, keep it safe)
a715a3d11d0f9c13de3bd6d390e36ba4e3322f4f2e4f1a13a54ba85be606de87
Public Key (you can share this one)
01765c67f451f3175f53bbe11d69d73a36d45074da935271473b4a1c460e3d79
-----------------

2. Save it as a profile (optional, but nice)

Profiles live in ~/.monstermashcfg and are written with owner-only (0600) permissions.

monstermash configure \
  --profile default \
  --private-key a715a3d11d0f9c13de3bd6d390e36ba4e3322f4f2e4f1a13a54ba85be606de87 \
  --public-key 01765c67f451f3175f53bbe11d69d73a36d45074da935271473b4a1c460e3d79

3. Encrypt

monstermash encrypt --profile default --data "hello world"

Or pass keys explicitly, or encrypt a whole file:

monstermash encrypt \
  --private-key a715a3d11d0f9c13de3bd6d390e36ba4e3322f4f2e4f1a13a54ba85be606de87 \
  --public-key 03ab4b8a77456729678a8022c2bfe22f64ed2db72692903e5f69e4a92649e646 \
  --file ./secret-plans.txt

4. Decrypt

monstermash decrypt \
  --private-key 91c7b2534454587a3330537bce60056e9da9a9bf75d32507152f49e85514970d \
  --data 01765c67f451f3175f53bbe11d69d73a36d45074da935271473b4a1c460e3d797bee92fa7ff1216eb5324b247fd41cce283adbcc4df92baacfea27765360a7c0feb226cccc1538c0397783003d0283d2841d2a

The --profile flag works here too β€” no public key needed, it's baked into the ciphertext.

How it works

Monstermash owns no cryptographic primitives β€” it leans entirely on NaCl. What it adds is ergonomics:

plaintext ──▢ NaCl Box (Curve25519 + XSalsa20-Poly1305) ──▢ [ sender public key β”‚ nonce β”‚ MAC β”‚ ciphertext ] ──▢ hex
                                                                └──────────── the "Mashed Envelope" β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Because the sender's public key travels inside the envelope, the recipient decrypts with only their private key. See docs/domain/cryptography.md for the full domain model and design decisions.

MCP Server

Monstermash ships an optional Model Context Protocol server so an LLM can do real encryption natively β€” without ever handling raw private keys.

Security model: tool arguments flow into the model's context, so private keys never cross the boundary. The model works by profile name (Γ  la ssh-agent); the server reads the key from disk locally. Set a default with MONSTERMASH_MCP_DEFAULT_PROFILE.

Run it over stdio:

monstermash-mcp

Register it with an MCP client (e.g. Claude Desktop):

{
  "mcpServers": {
    "monstermash": {
      "command": "monstermash-mcp"
    }
  }
}

Tools

Tool Description
generate_keypair Generate a keypair, store it under a profile, and return only the public key.
encrypt Encrypt text using a profile's keys. Recipient defaults to the profile; target a stored contact with recipient, or pass a raw public_key.
decrypt Decrypt a ciphertext using a profile's private key.
configure Import an existing keypair under a named profile.
add_contact Store a shared public key under a name (a contact); usable as an encrypt recipient, never able to decrypt.
list_profiles List profile names and public keys β€” private keys are never returned.

License

See the repository for license details.

About

🧟 A Private Key / Public Key Encryption Helper Library

Resources

Contributing

Stars

Watchers

Forks

Releases

Used by

Contributors

Languages