How one request runs
- Entry: A folder, read recursively into bytes - Windows Forms
- Orchestration: WCF service - WCF, .NET
- In parallel
- AES - CBC, from the .NET library - .NET
- RC6 - Written by hand, 20 rounds - C#
- XXTEA - Written by hand, Feistel network - C#
- Output: One encrypted file per input - SHA-512 recorded before and after
Overview
The unit of work here is a folder, not a file. You point the application at a directory, it reads everything inside it and inside every subfolder, and then one of three symmetric ciphers runs over the whole set. The encrypted tree, the decrypted tree and the hash log are each written somewhere you choose.
The reason there are three is that only one of them came for free. AES is the .NET library’s implementation, which is what any sensible application would use. RC6 and XXTEA are built from their specifications, and that is where the real work was: the key expansion, the padding, the rotations and the deliberate integer overflow that XXTEA depends on.
Technologies
- Client
- Windows FormsC#
- Service
- WCF.NETC#
Architecture
The client reads the folder
A folder dialog, then a recursive walk that reads every file as raw bytes regardless of extension and keeps its name, extension, directory and contents together as one record. Nothing interprets the file, so a .txt and an .exe take the same path through the program.
A background task keeps the window alive
Windows Forms gives the application one thread and that thread owns the controls, so reading a large folder on it would freeze the window and stop the spinner it is meant to be showing. The read runs as a Task instead, and the continuation is scheduled back onto the form’s own synchronization context, which is the only place the buttons can legally be re-enabled.
The list crosses to the service
The client calls the WCF service over HTTP. Both sides had to be reconfigured for the payload: the buffer limits go up to the largest value an int will hold, and the transfer mode changes from buffered to streamed so only the message header is buffered rather than the whole file list. Each end gets a ten-minute timeout.
The service encrypts, file by file
The chosen algorithm takes the list, the key and - for AES - the initialization vector. RC6 and XXTEA need their input to fill whole blocks, so each pads the byte array up to its block size and writes the original length into the first four bytes, which is what lets decryption trim the padding back off instead of guessing where the file ended.
Both ends are hashed
Every file gets a text file beside it holding four SHA-512 lines: before encryption, after encryption, before decryption, after decryption. The first and the last are the ones that matter, and they have to be identical. That is the whole integrity claim, and anyone who opens the file can check it.
What it does
A whole folder at a time
Subfolders included, to any depth. The output mirrors the input tree, which comes from diffing each file’s path against the root rather than from tracking the recursion.
Three ciphers, one form
AES with a 32-character key and a 16-character IV, RC6 and XXTEA with 16-character keys. Each gets its own window, and every field is validated before anything is written.
Proof it came back
The SHA-512 of the plaintext before encryption against the SHA-512 of the plaintext after decryption. Equal means the round trip was lossless.
Sequential or parallel
Both modes are built in, and a checkbox picks between them. In parallel mode the file list is split across a parallel loop, and since no file depends on another, nothing has to be locked or merged. The results below show what that is worth.
A progress bar that finishes with the job
Paced from the total byte count while the service works, and filled by way of a cancellation token the instant the real call returns, so it tracks the run and completes with it rather than after it.
The file tree up front
A tree view of everything that was loaded, fully expanded, so you can check what is about to be encrypted before you start.
Results
| Mode | Files | Encryption (s) | Decryption (s) |
|---|---|---|---|
| Sequential | 150 | 68.91 | 70.13 |
| Parallel | 150 | 44.16 | 40.39 |
The same 150 files, the same RC6 key, the same output folders, run once each way. Parallel encryption finished in 44.16 seconds against 68.91, and decryption in 40.39 against 70.13 - more than a third off in each direction.
The gain comes from the files being independent: the parallel loop needs no lock and no ordering, so no file waits for the one before it.
What I took from it
Implementing two of the three ciphers rather than calling them is what this project was for. They are short algorithms where almost every line is load-bearing: which direction a rotation goes, where the original length is stored, and the fact that XXTEA needs its arithmetic to wrap on overflow rather than throw. The matching hashes are what prove all of it lands correctly, byte for byte.
The client-server split is the other half of it. The cryptography runs in the service rather than in the process that draws the window, and the same three algorithms are available to anything else that can call it.