Software case study
Encryptron
A file encryption prototype, from the upload form to access checks.
- Languages
- Python & JavaScript
- Framework
- Flask & Jinja
- Database
- SQLite
- Scope
- Educational prototype
- Upload
File + password
- Process
Flask / Python
- Download
Processed file
File processing happens in memory.
What I built
I built a Flask app with account registration, encryption and decryption flows, and an interface for managing file permissions. Users select a file, enter a passphrase, and download the result with an .enc extension.
The frontend uses HTML, CSS, JavaScript, and Jinja templates. The backend handles sessions, compression, file transformations, and SQLite records. It is an educational prototype with a custom cipher.
The upload flow
I split the interface into three steps, with JavaScript controlling which fields and instructions are visible.
Choose a file
The selected filename replaces “Browse Files.” Reset clears the selection, and Next moves to the passphrase step.
Enter a passphrase
A password field collects the passphrase. Back returns to the file step; an empty passphrase prevents moving forward.
Submit and download
The final screen names the file being processed. On submission, the selected file and passphrase are copied into a multipart form and sent to Flask.
Behind the form
Accounts and sessions
Werkzeug hashes account passwords with PBKDF2-SHA256 and checks them at sign-in. Flask sessions carry the user’s ID, and protected routes redirect signed-out visitors to the login page.
Compression and processing
The app reads the upload into memory, compresses it with
zipfile, and applies the custom transformation. The decryption flow reverses the transformation and decompresses the result.Passphrase and cipher
The file passphrase is hashed with SHA-256, and the first 16 bytes become key material for a custom ten-round, Feistel-style transformation. It processes 16-byte blocks. This experimental routine is separate from the PBKDF2 hashing used for account passwords.
Three database tables
usersholds accounts and password hashes.filesrecords the filename, owner, and timestamp.permissionsconnects file IDs to users with access; the owner gets a permission record when a file is processed.
Returning the file
The processing route wraps the result in BytesIO and returns it with Flask’s send_file. The file contents stay in memory for this request; SQLite stores the associated records.
return send_file(
io.BytesIO(encrypted_data),
mimetype='application/octet-stream',
as_attachment=True,
download_name=encrypted_filename
)From the encryption route in app.py.
Decryption and sharing
Before decryption, the app looks up the uploaded filename and checks whether the signed-in user owns the record or has a matching permission entry. A missing record or failed permission check stops the request before processing.
The Manage Access page lists the owner’s files and the usernames with access. Its forms can grant access, revoke a permission, or remove a file’s database record. Granting access does not send the file itself.
Memory and storage
In-memory processing keeps this workflow straightforward, but the file size directly affects memory usage. A larger deployment would need explicit limits and a different strategy for large files.
SQLite makes local setup simple. Moving to multiple application instances would require revisiting database access and deployment choices.
What I’d carry forward
Building the full flow made the different responsibilities clearer: form validation, file processing, account authentication, and file permissions each need their own checks.
For the next backend project, I’d define access rules and failure cases earlier, and keep file-processing logic separate from route handlers so it can be tested independently.
What I’d change next
The custom cipher is experimental, so this version is not intended to protect sensitive files. I’d replace it with vetted authenticated encryption before considering production use.
I’d also make ownership checks consistent across every permission-changing route, use an unambiguous file identifier instead of relying on filename lookup, and add upload limits. Tests should cover missing files, invalid passphrases, duplicate filenames, and unauthorized permission changes.
On the frontend, I’d replace browser alerts with inline validation and simplify the form submission so the file input does not need to be copied.