The Crypto Experiment

The Crypto Experiment article image

I recently created a little console application to encrypt text files before storing them into my Dropbox folder. But I thought it would be great to automate this process instead of doing it manually.

THE IDEA

ISOLATED STORAGE

Instead of storing the text files in an optional folder, I thought it would be nice having a more standardized way of storage. So I Googled around and came across the Isolated Storage in .NET. It provides a standardized way of data storage, isolation and safety to associate code with saved data.

So the file storage area will be isolated from the user but not from the application itself and by the virtual drive reachable from Windows Explorer.

crypto-device-drive

VIRTUAL DRIVE

The DefineDosDevice function is used to setup a virtual drive device. It will be visible in Windows Explorer as a regular drive. The device is mapped to the isolated storage path. But the IsolatedStorageFile object doesn´t contain any public properties that holds the full system path. Probably because Isolated Storage is an abstraction rather than a specific disk location. Anyway, after a debugging session in Visual Studio the private field m_RootDirholds the path.

Note: The new virtual drive will automatically be named “Local Disk” (EN). You can use theSetVolumeLabel function to change its name. You can also take a look theSystem.IO.DriveInfo class instead of this managed API.

Example using reflection to extract the value.

// Obtains isolated storage corresponding to the given user, domain and assembly
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null))
{
 // Using reflection to get the value of the private field m_RootDir
 return isoStore.GetType().GetField("m_RootDir", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(isoStore).ToString();
}

ENCRYPTION

The content of the text files will be encrypted using the Rijndael (AES) symmetric encryption algorithm. To ensure following the AES specification the block size is fixed to 128-bit and we´re not using the CFB (Cipher Feedback) mode. The encrypted content will be put into a CryptoStream and copied to the Dropbox folder.

crypto-encrypted-content

Thoughts: There are much to dig into when it comes to encryption and security in general – from how security should be implemented in a specific solution to which algorithm to use and what parameters to set. There are for example many ways in .NET to perform AES encryption. Anyway, here´s a great quote from Security Pitfalls in Cryptography by Bruce Schneier:

“A cryptographic system can only be as strong as the encryption algorithms, digital signature algorithms, one-way hash functions, and message authentication codes it relies on. Break any of them, and you’ve broken the system. And just as it’s possible to build a weak structure using strong materials, it’s possible to build a weak cryptographic system using strong algorithms and protocols.“

FILE SYSTEM WATCHER

The FileSystemWatcher class within the System.IO namespace is used to automate the process. It listens to changes in the file system and raises events when a directory or file changes. A watcher will be attached to the specific isolated storage folder listening to following events: changed, created, deleted and renamed. For example, if the changed event got raised the content of the target text file will be encrypted and copied to the Dropbox folder.

Tip: The standard Dropbox folder path can be retrieved from the host.db file inside the Windows AppData\Roaming folder. The information is Base64 encoded.

string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string dropboxPath = Path.Combine(appDataPath, "Dropbox\\host.db");

string[] textLines = System.IO.File.ReadAllLines(dropboxPath);
byte[] base64Arr = Convert.FromBase64String(textLines[1]);

string dropboxFolderPath = System.Text.ASCIIEncoding.ASCII.GetString(base64Arr);

A problem I encountered with the file system watcher was that a single event can generate multiple events. For example if you are using Notepad to create a file the Created event got raised twice. The MSDN documentation Troubleshooting FileSystemWatcher Componentssays that Notepad performs multiple file system actions during the writing process. It writes to the disk in batches that create the content of the file and then the file attributes. Other programs may also perform in the same way.

A workaround I tested here is when an event is raised, the EnableRaisingEvents flag is disabled before doing any futher operations. When done it is enabled again.

try
{
 _fileSystemWatcherInstance.EnableRaisingEvents = false;
 // Futher actions like file encryption goes here...
}
catch (IOException ioex)
{
 // An I/O exception was thrown
}
finally
{
 _fileSystemWatcherInstance.EnableRaisingEvents = true;
}

Note: Another thing to pay attention to when it comes to the FileSystemWatcher, in general, is the internal buffer. The system notifies the watcher component of file changes and those are stored in a buffer. Too many events in a short time can result in a buffer overflow. This causes the component to loose file system change events.

FINALLY

Well, a funny little project. A mix-up of things to suit a need. And yes, I know, there are products like Boxcryptor around. There´s an app for everything ;). To get the whole application flow, this experimental project can be downloaded using the button below.

download