stegfs - 2015.08.1 21st July 2016
$ mkstegfs /dev/sda $ stegfs /dev/sda /mnt/stegfs $ mkdir /mnt/stegfs/docs $ touch /mnt/stegfs/docs/file:password
stegfs is a steganographic file system in userspace. Steganographic file systems allow the user plausible deniability of files within. It achieves this by becoming a lossy file system: writing a file to the file system may overwrite an existing file without warning.
The typical use case for stegfs is either as a file on an existing file system, similar to many other FUSE based file systems, but it can also function as a file system on its own partition, like traditional “in-kernel” file systems---it doesn’t really matter. With that in mind, it’s not expected to be a primary workstation file system, but more of a USB or SD-card file system. Great for keeping documents hidden from prying eyes when moving data between systems. (It also works well with online based storage provides too.)
One suggested way of using stegfs is to have it located as the final partition on a USB drive, and keep less secret data in the root or within one or two subdirectories, and then keep more secret data further down the hierarchy---obviously with each file having a unique password.
stegfs uses a file hierarchy similar to that of conventional file systems. For each subdirectory, a check is made to ensure that the current block isn’t already being used by another file down that path. Files written at deeper levels will not overwrite files above them, but files in the root directory are likely to overwrite portions of files further away from the root. Therefore, files at a deeper level are less likely to overwrite another file, but are more susceptible to being overwritten themselves.
Files can be stored with or without a password. The convention adopted for stegfs is “/dir/tree/file:passwd”; that is, everything after a colon is used at the password for encrypting and decrypting the file. In addition to this, as with the directory hierarchy and the file name, the password is also used to locate the header blocks for files.
One point worth making is that even though writing multiple files in one session ensures that the later files do not overwrite the previous ones, the same is not true regarding the file inodes/headers. They are written where they want (their location is deterministic based on the file name/ path). As an example: copying the source code for our encrypt project on to a stegfs partition causes several of the files to become corrupt and unrecoverable. Obviously one way to avoid this is to bundle files in to an archive (tar, zip, etc).
The paranoid mode doesn’t disclose the fact that a stegfs partition is present; the entire file or device will appear as random data. Whilst this is good for security it does mean that the stegfs application is unable to confirm that it is mounting an actual stegfs partition; it will ignore some basic sanity checks and then succeed regardless---this could cause serious data loss! You have to way up the risks for yourself: security and increased plausible deniability, or risk of destroying data if you accidentally mount something that isn’t a stegfs partition. The set libgcrypt options for when in extreme paranoia mode are the same as the defaults for mkstegfs.
The default cipher (Rijndael/AES) has been chosen because it might give slight performance improvements over other algorithms, as it’s likely modern chipsets have it implemented in hardware. The reason for choosing SHA-2 256 is so that the path and data checksum make use of all of the available space within their locations of each file system block.
When creating a stegfs file system, the size of the file created (or the size of the partition on which it will be created) is shown; this is the number of bytes (MB, GB, etc) which are used to house everything, including header information, about the files on the file system. Below this is the capacity available for actual file data---roughly 95% of a block is used for data. Finally, the maximum usable space under ideal conditions where no files are compromised: each file is written 8 times to minimise the loss, and maximise the chance of being able to recover it. Under normal working conditions it’s highly likely this value will never be achieved due to the Birthday Paradox.
By default the mkfs utility will use the Rijndael cipher with a 256 bit key (AES256), in cipher block chaining mode, and the SHA-2 hash algorithm with a 256 bit output. These can be changed by passing the appropriate arguments and values to mkstegfs. You can find a list of supported algorithms/modes either from encrypt (as it uses libgcrypt) or from: https://www.gnupg.org/documentation/manuals/gcrypt/
If you use the extreme paranoia mode any changes to the defaults are ignored. This is because stegfs will be unable to detect which algorithms/mode was selected when the file system was created. (This may change in the future.)
Compiling from source is as simple as running one of the following commands:
- Fix FUSE initialisation bug (caused by update to FUSE library that was stricter than before)
- Update documentation and man pages
- Bring back multi-threaded support
- Cache time limit (force forget if a file isn’t accessed)
- Don’t break backwards compatibility (again)!
- Start using ECC