Author: RajarshiB | AI-assistant: Claude
This is a security-hardened version of a gui-tool originally written in 2022.
KRYPTOPATH is a desktop GUI application built with Python and Tkinter that encrypts and decrypts text and binary files using nested (cascaded) cipher layers. Each encryption mode wraps plaintext in one or more independent cipher layers, where every layer performs its own key derivation (with a unique salt), generates its own IV/nonce, and produces its own authentication tag. This means an attacker must independently defeat every layer to recover the original data.
The application supports two operating modes — Text Mode for UTF-8 strings and Binary Mode for raw file encryption — and offers configurable Key Derivation Functions (PBKDF2 or Argon2id) independent of the cipher mode.
| # | Mode Name | Layers (inner → outer) | Recommended Use |
|---|---|---|---|
| 1 | AES-CBC(Serpent) | Serpent-256-CBC + HMAC-SHA256 → AES-256-CBC + HMAC-SHA256 | Text |
| 2 | AES-GCM(Serpent) | Serpent-256-CBC + HMAC-SHA256 → AES-256-GCM (AEAD) | Text (Default) |
| 3 | ChaCha20Poly1305(Serpent) | Serpent-256-CBC + HMAC-SHA256 → ChaCha20-Poly1305 (AEAD) | Text |
| 4 | ChaCha20Poly1305(AES) | AES-256-GCM (AEAD) → ChaCha20-Poly1305 (AEAD) | Binary (Recommended) |
-
Text Mode: For encrypting and decrypting UTF-8 text. Output is Base85-encoded with structural obfuscation (character-count-based rotation shift). Encrypted files are saved with a
.xencextension. Modes 1–3 are recommended for text. -
Binary Mode: For encrypting any file type — images, archives, executables, documents, etc. Operates entirely in raw bytes in memory with no Base85 encoding and no text box display. Encrypted output is saved as
.binxenc. File extension metadata is embedded in the encrypted payload so the original file type is restored losslessly on decryption. -
Mode 4 (
ChaCha20Poly1305(AES)) must be used for binary encryption. This mode operates purely on raw bytes throughout the entire pipeline, skipping the Serpent-CBC inner layer (which uses text-based Base85 encoding internally). This avoids encoding overhead and ensures binary integrity for arbitrarily large files.
Nested encryption provides defense-in-depth by requiring an attacker to independently break multiple cryptographic layers. Even if one layer is compromised, the remaining layers continue to protect the data.
| Attack Type | How Nesting Protects |
|---|---|
| Single-cipher cryptanalytic break | If one cipher (e.g., AES) is broken, the inner layer (Serpent) still protects the plaintext. An attacker must break both independently. |
| Key compromise (partial) | Each layer derives its own independent key from the password via separate KDF calls with unique salts. Compromising one derived key does not reveal the other. |
| Padding oracle attacks | The inner Serpent-CBC layer is wrapped inside an AEAD outer layer (GCM or Poly1305). The outer authentication fails before an attacker can probe the inner CBC padding. |
| Ciphertext tampering / bit-flipping | Every layer includes its own authentication — HMAC-SHA256 for CBC layers, built-in AEAD tags for GCM and ChaCha20. Tampering at any layer is immediately detected. |
| Known-plaintext attacks | Structural obfuscation (Base85 encoding + character-count-based shift) ensures the raw ciphertext layout is non-standard. Standard cryptanalytic tool assumptions do not apply. |
| Future quantum threats (hedge) | Algorithm diversity (Serpent + AES + ChaCha20) provides a hedge — a quantum break against one algorithm family does not immediately expose data protected by the others. |
KRYPTOPATH performs aggressive memory clearing after every cryptographic operation to minimize the window of exposure for sensitive key material:
-
secure_erase_bytes()— Wipes all derived encryption keys and HMAC keys usingctypes.memsetfor C-level zeroing, preventing the Python optimizer from skipping the overwrite. Falls back to a manual byte-by-byte loop if ctypes is unavailable. Forces garbage collection (gc.collect()) after wiping. -
_wipe_immutable_bytes()— Best-effort zeroing of immutablebytesobjects via raw pointer arithmetic (CPython-specific). Called immediately after copying sensitive KDF output into a mutablebytearray, so the original immutable copy does not linger in memory. -
Passcode widget scrubbing — After reading the passcode from the GUI text box, the Tkinter widget buffer is overwritten with zeros and then restored, limiting the window of exposure in Tkinter's internal memory structures.
KRYPTOPATH validates every passcode before allowing encryption to proceed:
-
Primary — zxcvbn (pattern-aware): If the
zxcvbnlibrary is installed, KRYPTOPATH uses pattern-aware strength estimation that detects dictionary words, keyboard walks, dates, repeated characters, and l33t substitutions. A minimum score of 3/4 is required ("safely unguessable" — estimated 10^8+ guesses at offline slow-hashing speeds). Detailed feedback and crack-time estimates are shown to the user. -
Fallback — Shannon entropy: If
zxcvbnis not available, KRYPTOPATH computes the true Shannon entropy of the passcode:H = -Σ(p_i × log₂(p_i)) × lengthThis measures actual character frequency distribution rather than assuming uniform random sampling, correctly penalizing repetitive passwords (e.g.,
"aaaaaaaaaa"yields near-zero entropy). The minimum threshold is 50 bits.
The KDF choice is independent of the cipher mode — any mode can use either KDF.
-
PBKDF2-HMAC-SHA512 — Default 1,000,000 iterations. Widely supported and NIST-approved. Configurable iteration count via the GUI.
-
Argon2id — Memory-hard KDF resistant to GPU and ASIC attacks. Configurable parameters:
- Time cost (iterations): default 4
- Memory cost: default 512 MB
- Parallelism (threads): default 2
Falls back to scrypt if
argon2-cffiis not installed, and further falls back to high-iteration PBKDF2 if neither is available.
KRYPTOPATH includes a built-in random password generator accessible from the main GUI. It uses Python's secrets.choice() module, which draws from OS hardware entropy (/dev/urandom on Unix, CryptGenRandom on Windows). The character set and password length are fully configurable.
The Serpent cipher implementation (Serpent.py, Serpent_Func.py) has been adapted and modified from pyserpent by sysopfb.
The Examples folder contains sample encrypted files you can use to verify your setup:
| File | Description |
|---|---|
Lc3_2018_(263682303)_(cropped).jpeg |
Original unencrypted image |
Lc3_2018_(263682303)_(cropped).binxenc |
The same image encrypted in Binary Mode (Mode 4, Argon2id) |
Text_Forntpage.xenc |
Encrypted text sample (Mode 2, Argon2id) |
To decrypt: open the encrypted file in KRYPTOPATH, select the matching mode and KDF, and use the password:
Password3.141592
Compare the decrypted output against the original to confirm everything works correctly.
pip install -r requirements.txt| Package | Role | Required? |
|---|---|---|
pycryptodome |
AES, ChaCha20-Poly1305, PBKDF2, padding | Required |
argon2-cffi |
Argon2id KDF (falls back to scrypt/PBKDF2 if absent) | Recommended |
zxcvbn |
Pattern-aware password strength (falls back to Shannon entropy if absent) | Recommended |