Encrypted partitions that can deny they exist.
scubed3 hides any number of encrypted partitions in one disk full of random data. Without its passphrase, a partition looks exactly like unused space, so you can hand over one passphrase and keep quiet about the rest.
This is a simulated device of 1 024 blocks. Three of the passphrases above open a partition. Any other passphrase opens nothing, and nobody can see how many partitions there are.
The idea
Ordinary disk encryption protects what is in your files, but not the fact that you have them. Someone who can force you to open an encrypted disk can see that it is encrypted, and can keep insisting until you give up the passphrase.
scubed3 takes a different approach. You start with a device, or a big file, filled with random data. Encrypted data looks like random data too. So when scubed3 stores a partition on the device, the blocks it uses look the same as the blocks it does not use. Nothing on the device lists the partitions: each passphrase finds only its own blocks.
That allows plausible deniability. You can keep a partition with things you can admit to, and give up its passphrase when you have to. Other partitions on the same device stay invisible, and there is no way to prove that they are there. Unused space and hidden partitions look the same.
The name comes from Simple Steganographic Store: three S's, s cubed. Steganography is the art of hiding that a message exists at all, not only what it says.
How it works
The device is divided into macroblocks, 4 MiB each by default. A macroblock is the unit scubed3 writes: always a whole macroblock at once, always encrypted with AES-256. Each one starts with a small index that says what is in the rest of it.
Scattered blocks, one straight file
A partition's blocks lie anywhere on the device, in no particular order. When you open a partition, scubed3 reads every block, keeps the ones its key can decrypt, and uses their indexes to put the pieces back in order. You get a plain file that behaves like a disk: you can format it, mount it, or put LUKS on it.
Never overwriting in place
Changing data in place would give the game away: an observer who compares two snapshots of the device would see the same few blocks change, over and over. So scubed3 is log-structured. Changes collect in memory, and when there is a full block of them it is written to another macroblock. The old copy becomes garbage, and its space is reused later. Which macroblock is next is up to the paranoia level, explained in the next section.
Where it sits
scubed3 is a small daemon that runs in user space, through FUSE. It presents each open partition as a file, and you control it with scubed3ctl, an interactive tool that works like a partition editor: create, open, resize, mount, close.
A key store, for fewer passphrases
One passphrase per partition, plus one per LUKS volume, adds up. The optional key store holds those keys for you. It is a file of 64 equal slots. A passphrase unlocks one slot, its view: a list of partitions with their keys. Unused slots are random data, so the file does not show how many passphrases it has, or whether it is used at all. Every change rewrites the whole file, so two copies of it are no help to an observer either.
The key store also makes it practical to put the root filesystem itself on scubed3: the scripts in contrib/initramfs-tools (for Debian and its derivatives) start the daemon at boot and ask for one passphrase, in exactly the words and the place an encrypted disk asks for it, then open everything. To someone watching the boot it looks like an ordinary encrypted laptop.
How paranoid are you?
Hidden data is not the only thing that can give you away. Where and when the writes go matters too. If an observer has two snapshots of your device, and only the blocks of one partition changed, then those blocks are a partition. Flash drives make this worse: an SSD keeps its own record of the order of writes, so you have to assume many snapshots. scubed3 has four levels, from fast to completely uninformative.
Try it below. The left grid is what you know: blue is your partition, amber is another, grey is free space. The right grid is what an observer with snapshots sees: how often each block was written. Press the button and watch the right-hand grid.
Your view
Which partition owns which block. A ring marks the latest write.
The observer's view
How often each block was written. Darker means more often.
Not paranoid
The emptiest block of the partition is reused. The fastest level, and the order of the writes shows which blocks hold old data.
Moderately paranoid
A random block of the partition. Writes still land only on the partition's own blocks. This is the level after starting scubed3.
Just paranoid
Every write goes to a uniformly random block of the whole device. Free blocks get fresh random data, other partitions rewrite theirs. All partitions must be open: a partition that is not open would be overwritten.
Extremely paranoid
As level 2, but on a random clock that ticks whether or not you write. The number, the timing and the places of the writes reveal nothing.
The price of levels 2 and 3 is speed and wear. In level 2, a partition with a quarter of the blocks needs four writes, on average, for each block of its own data. In level 3 the device is written all the time, and a partition can never write faster than its share of the clock. The next section has the numbers.
Performance
Hiding comes at a cost, and most of it is a choice: you pick the paranoia level. These measurements are from the test suite in dev/, on a file on an ordinary Linux machine. Your numbers will depend on your disk.
Opening a partition
Seconds to open one partition on a device of 29 000 macroblocks. Every block must be tried, but only the first 128 bytes are decrypted now, and the result is cached.
Show the numbers
| open | before | now |
|---|---|---|
| first after start | 1.77 s | 0.145 s |
| later | 0.151 s | 0.008 s |
Reading while a writer waits
In level 3, a writer waits for its turn on the clock. Reads used to wait with it; now they go on. Read latency in milliseconds, on a log scale.
Show the numbers
| read latency | median | maximum |
|---|---|---|
| before | 312 ms | 3 447 ms |
| now | 0.2 ms | 14 ms |
How fast can a partition write in level 3?
At most its share of the device times the rate of the clock. The garbage collector takes part of that. Big partitions are fast, small partitions are slow.
Show the numbers
| rate | a 4 MiB block every | written per day | per year |
|---|---|---|---|
| 4 096 KiB/s | 1 s | 362 GB | 132 TB |
| 800 KiB/s (default) | 5.12 s | 71 GB | 26 TB |
| 400 KiB/s | 10.24 s | 35 GB | 13 TB |
| 128 KiB/s | 32 s | 11 GB | 4.1 TB |
SSDs are rated for a number of terabytes written, typically a few hundred per terabyte of capacity.
Get it
scubed3 runs on Linux. Building it needs libfuse 3, libgcrypt and readline with their development files, and autoconf, automake and pkg-config.
svn checkout https://snel.it/svn/misc/trunk/scubed3 cd scubed3 ./autogen.sh && ./configure && make
A first partition, as root, on a 4 GB file. scubed3ctl asks for the passphrase, twice when creating.
# head -c 4G /dev/urandom > /var/lib/scubed3.base # scubed3 -b /var/lib/scubed3.base /mnt/scubed3 # scubed3ctl s3> create secret s3> resize secret 400 400 macroblocks of 4 MiB s3> luksformat secret s3> mke2fs secret s3> mount secret /mnt/secret s3> umount secret
For levels 2 and 3, open all partitions first, then switch the level with paranoia 2, then mount. Or set up a key store with the guided keys-setup and open everything at once with scubed3ctl -c unlock-all -c open-all. The README explains every command, the on-disk format and the threat model.
scubed3 is alpha software. Its design and code have not been reviewed by anyone else yet. Keep backups, and keep a copy of /etc/scubed3.conf, which holds the salt: without it the partitions cannot be opened. Reviews and bug reports are very welcome.
History
scubed3 is the third attempt at the same idea.
- scubed
The original scubed followed in the footsteps of rubberhose, stegfs and phonebook. It was built on the Linux kernel's device mapper: dm-crypt for the encryption and dm-linear to put the pieces together into partitions. It was simple, and it worked on anything, even a rewritable DVD.
It wrote data in place, so anyone with two snapshots of the device could see where the partitions were. StarWorld from Brazil ported it to C++, as scubed++.
- scubed2
The second version tried to solve the snapshot problem with small blocks. On spinning disks, performance was terrible, and it never became usable. Two things did come out of it: the XTS mode and the benbi IV generator, both of which made it into the Linux kernel.
- scubed3
Large macroblocks, written whole, a log-structured design that never overwrites in place, and paranoia levels that hide where and when the writes go. The data is exposed through FUSE as plain files, managed with
scubed3ctl.
I had the design of scubed3 in my head for about fifteen years, and I was stuck. Claude, by Anthropic, was instrumental in bringing that vision to life. It wrote the code, the tests and the documentation in a couple of days, in my coding style, and talked the hard problems through with me along the way.
Rik Snel
License
scubed3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The full text is in the file COPYING.
It is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.
This website uses TeX Gyre Adventor, TeX Gyre Schola and Latin Modern Mono, under the GUST Font License (doc/fonts/GUST-FONT-LICENSE.txt). It loads nothing from other sites.
Contact
Questions, reviews and bug reports: Rik Snel, rik@snel.it.