sFS - the steganographic filesystem

The project started during my forth year in university when I was wondering if it would be possible to create an entire filesystem within steganographic space. sFS is an implementation of such a system. It currently only supports JPEG as a place to store data, but the system is easily extendable to allow any other file type along side JPEG, you just need to tell it how to do three things.

  • How much data can you store?
  • How do I read from any part in your file?
  • How to I write to any part in your file?

These are the major components of any steg piece. sFS is built in layers to make it easy to modify and understand how it works. 

  • FuseFS
  • FileManager
  • StorageManager
  • Stegs

Each of these layers is more or less independent of each other and the encryption happens in the FileManager and is file based.

How does encryption work?

This is probably the best question about the system because it's one most prone to errors and I make no assertions that the encryption is implemented in a secure way, just that it works and as far as I know, is at least ok.

No data from the system is stored in unencrypted, all data blocks, pointer blocks and the MFT are encrypted at rest. The process for starting the system works like this:

  • Take the first block size of space from the StorageManager and try to decrypt it. The key is an 128 bit AES key being the first 16 bytes of the SHA-256 of the supplied password.
  • Decryption is successful if the first four bytes are "STEG" (if decryption is not successful, ask if they want to create a new filesystem)
  • If it is successful, parse the first block to find all the files and their indirection blocks.
  • When the user tries to access a file, get the indirection block and decrypt it (the first 16 bytes are a random IV)
  • Now that we know where all the file blocks are, read all of those into a contiguous buffer and decrypt that (the IV for the file is stored in indirection block and is changed every time the file is flushed)
  • We know have the entire decrypted file stored in a memory buffer. The user will indirectly interact with this for speed because writing and reading from the files is very slow (especially for JPEGs because of the compression that happens)
  • When the user is done and closes the file (and sometimes before that) we will flush the file to disk. This basically does the entire above process in reverse.
  • Generate a new IV for the file and encrypt it, update the indirection block, and then flush.
  • Generate a new IV for the indirection block, encrypt it and flush.