scubed3

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.

the base device: macroblocks of 4 MiB, all of them random-looking index 1 mesoblock data: 255 mesoblocks of 16 KiB, pieces of one partition After decryption with the right key, the index says: magic this block is mine (any other key gives noise) sequence number how new this block is; the newest copy of a piece wins piece numbers which pieces of the partition the data mesoblocks are checksum a torn or damaged block is ignored
Without the right key, the index decrypts to noise and the block is skipped. Only the blocks of the partitions you open are recognised.

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.

on disk, in the order the writes happened to land 4 1 6 2 5 3 7 1 2 3 4 5 6 7 the partition, as one ordinary file: /mnt/scubed3/photos
The numbers say which part of the partition each block holds. On the disk they are just noise.

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.

1 Changes collect in memory the current block fills up with new data 2 Written to a new place the paranoia level decides where 3 The old copy is garbage its space is reused later piece 4 changed, piece 9 is new, ... the full current block a whole macroblock is written at once old new the garbage collector moves what is still live

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.

Your files ext4, or any other filesystem LUKS (recommended) /dev/mapper/scubed3-photos: protects the data while it is not mounted The partition, a plain file /mnt/scubed3/photos, one file per open partition scubed3 the daemon: finds, decrypts, and writes the blocks of the open partitions The base device a disk, a partition or a file, filled with random data scubed3ctl you, over a socket
Putting LUKS on a partition is recommended: if someone takes the computer while it is running, a LUKS volume that is not mounted still keeps its data safe.

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.

/etc/scubed3.keys: 64 slots, every one the same size, every one random-looking view of passphrase 1 work partition key photos partition key + LUKS key view of passphrase 2 diary partition key + LUKS key work partition key archive partition key
One passphrase opens the partitions of its view and their LUKS volumes. Keep a view you can admit to and another one for the hidden partitions. A partition can be in more than one view.

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.

your partitionanother partitionfree

The observer's view

How often each block was written. Darker means more often.

0

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.

1

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.

2

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.

3

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
openbeforenow
first after start1.77 s0.145 s
later0.151 s0.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 latencymedianmaximum
before312 ms3 447 ms
now0.2 ms14 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.

800 KiB/s
Show the numbers
ratea 4 MiB block everywritten per dayper year
4 096 KiB/s1 s362 GB132 TB
800 KiB/s (default)5.12 s71 GB26 TB
400 KiB/s10.24 s35 GB13 TB
128 KiB/s32 s11 GB4.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.

  1. 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++.

  2. 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.

  3. 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.