Bundles (.bhb)¶
Two flavors. With a password, .bhb packs a directory to tar.gz and
encrypts the whole thing, names and all - only blackhole opens it.
With --no-password it packs plain: no encryption, opens with no
flags, same as a zip with no password. Pick per bundle.
Creating one¶
# password mode (prompts twice)
blackhole bundle create ./photos ./photos.bhb
# same, explicit flag
blackhole bundle create ./photos ./photos.bhb --password
# plain mode: no password, no extra files, anyone can open it
blackhole bundle create ./photos ./photos.bhb --no-password
Opening one¶
blackhole bundle extract ./photos.bhb ./restored --password
blackhole bundle extract ./photos.bhb ./restored # plain bundles need nothing
A wrong password or a tampered file just refuses to open. There is no
partial extract. Bundles made back when --no-password wrote a .key
file still open with --keyfile, nothing else changed for them.
Peeking without unpacking¶
blackhole bundle list ./photos.bhb --password
blackhole bundle verify ./photos.bhb --password; echo $?
list prints every file with its size. verify only checks the
password/key and authenticity: exit 0 opens, 1 does not.
Root-owned files¶
create never deletes or moves your source; it only reads it. If a
bundle (or its directory) belongs to root, run the same command with
sudo - blackhole says so in the error. Files created that way are
root-owned too, including anything you extract.
How it compares to zip¶
| Problem with zip | What .bhb password mode does |
|---|---|
| ZipCrypto breaks in minutes | Argon2id into AES-256-GCM, no legacy modes |
| Filenames visible without the password | Names are inside the encrypted blob |
ZipSlip (../../evil) on extract |
Absolute paths, .., symlinks and devices are skipped |
| Every website unzips it | Only blackhole reads .bhb |
Format v1¶
Big-endian, one header, one payload:
BHB1 | kdf_id | t,m,p | salt | [nonce (12)] | ct_len (u64) | ct
kdf_id 1 (password) and 0 (old keyfile) carry a nonce and ct is
AES-GCM with the header as AAD. kdf_id 2 (plain) has no nonce and
ct is the tar.gz as-is.
Implementation lives in src/blackhole_sec/bundle/__init__.py. It is
short enough to read in one sitting, which is intentional.
Tips¶
- Bundle the cleaned copies (
*.cleaned.jpg), not the originals, when you share photos with other people. .bhbfiles are chmod 0600 on creation. Copy them normally, perms do not survive every filesystem, so check after moving.