*.monsecrets
A .monsecrets file is one or more profiles, their keys and their secrets, encrypted together so they can be handed to someone.
pack writes one, a.monsecrets unless you name it, and unpack reads it.
That is the only way a secret leaves the vault.
Format
Two lines of text:
monkeys bundle 1 scrypt 17 8 1
<salt and sealed bytes, base64>The first line names the format and the scrypt cost the key was derived
with, log2 N, r and p. A bundle therefore keeps opening after the default
cost rises. The
second is the salt followed by the sealed bytes, in
base64. Inside, the bundle keeps the
shape of the .monkeys file, namespace line and blocks, so unpack can write
the file back and remember each secret under its profile. The KEY=value lines of the
packed profiles follow, after a line that says values, and unpack writes
them back as lines. A bundle without that line was written before values
existed, and opens too.
Security
The sealed bytes are ChaCha20-Poly1305, the AEAD of RFC 8439 that TLS 1.3, WireGuard and OpenSSH use. A bundle that has been altered fails to open rather than opening wrong, and a wrong passphrase fails the same way.
The key is derived from the passphrase with
scrypt (RFC
7914) and a fresh 16-byte salt each
time, at N = 2^17, r = 8, p = 1. Deriving it costs 128 MiB of memory and a fraction of a
second, once for pack and once for unpack; that memory is what keeps a
guess from being cheap to run in parallel. The passphrase is the weakest part,
so it goes by another route than the file.
A header that asks for a cost outside a fixed range is refused before any
work is done, so a crafted file cannot make unpack run for hours.
Sharing one
The file is safe to send over whatever you already use, and the passphrase
goes another way. unpack deletes the bundle once it has done its job; pack
writes it to /tmp, outside any repository. pack and
unpack are the two halves. A bundle written before a
rename still carries the old name, and unpacks to it.
If one is committed
A bundle has no reason to be in a repository, and .monkeys needs no ignore
rule, since it is meant to be committed. If a bundle is committed by mistake
anyway, what leaked is a sealed file, and the passphrase it was sealed with is
the only thing standing in the way. That passphrase cannot be changed after
the fact: the copy that leaked stays readable by whoever guesses the one it
already carries, and scrypt only makes each guess cost about 128 MB.
Take the file out of the repository, and out of its history if it was pushed. Then rotate the secrets it held, the way you would for any secret that has been somewhere it should not be. A new passphrase protects the next bundle, never the one that leaked.