Security Architecture &
Technical Internals
A complete breakdown of how Qlerky Password Manager handles encryption, key derivation, TOTP two-factor authentication, and all four export formats — including the steganographic image encoding pipeline.
System Architecture #
Qlerky is designed around a zero-trust, offline-first architecture. The application makes no outbound network requests related to user data. There is no backend service, no authentication server, no telemetry endpoint, and no cloud synchronization layer. The entire security perimeter is the user's physical device.
Core Design Principles
- Local-only storage: All vault data resides in the Android app's private data directory, inaccessible to other apps without root access.
- Encryption at rest: The vault file is always stored in encrypted form. The derived key only exists in memory during an active session.
- No plaintext persistence: Decrypted data is never written to disk, log files, or shared storage.
- Zero network surface: No passwords, keys, or credentials are transmitted over any network interface under any circumstances.
- Offline TOTP: Time-based one-time passwords are calculated locally using device time, with no external time server required.
Threat Model #
Understanding what Qlerky protects against — and what it does not — is essential for correct usage.
Threats Mitigated
| Threat | Mitigation | Confidence |
|---|---|---|
| Server breach / cloud hack | No server exists. No data is stored remotely. | 🟢 Eliminated |
| Network interception (MITM) | No network transmission of vault data. | 🟢 Eliminated |
| Third-party data sale | No third-party involved. No account created. | 🟢 Eliminated |
| App shutdown / service discontinuation | Data is local. App can be sideloaded. CSV export always available. | 🟢 Mitigated |
| Unauthorized device access | AES encryption + master password required to read vault. | 🟡 Mitigated (depends on password strength) |
| Malware on same device | Android sandbox + no plaintext persistence reduces risk. | 🟡 Partially mitigated |
Out of Scope
- Compromised device (rooted/jailbroken): Root access can bypass the Android sandbox. If your device is rooted, no application can guarantee complete security.
- Weak master password: Qlerky's encryption strength is directly proportional to master password entropy. A weak password significantly degrades protection.
- Physical coercion: Qlerky cannot protect against someone forcing you to reveal your master password.
- Screen recording / keylogging malware: If malware is already installed and active on your device, it may capture credentials as you type them into Qlerky.
AES Encryption #
Qlerky uses AES (Advanced Encryption Standard), the same symmetric cipher used by governments, financial institutions, and security-critical applications worldwide. AES was selected by NIST in 2001 and remains unbroken by any publicly known attack against properly implemented instances.
Why AES?
AES offers an optimal balance of security,
performance, and hardware acceleration. On modern
Android devices, AES operations are accelerated by
dedicated CPU instructions (AES-NI on
ARMv8), making encryption and decryption fast enough
to be imperceptible to the user while maintaining
cryptographic strength.
Key Derivation with Argon2
A master password alone cannot directly serve as an AES key — passwords are short, human-memorable strings with insufficient entropy and non-uniform bit distribution. Qlerky uses Argon2 — the winner of the Password Hashing Competition (PHC) in 2015 and the current gold standard for password-based key derivation — to transform the master password into a cryptographically strong encryption key.
Argon2 is superior to older KDFs like PBKDF2 and bcrypt because it is designed to be:
- Memory-hard: Requires a configurable amount of RAM to compute, making GPU and ASIC-based brute-force attacks extremely costly
- Time-hard: Configurable iteration count adds CPU cost on top of memory cost
- Parallelism-resistant: Controls how many parallel threads can be used, limiting attacker hardware advantage
- Salt-protected: A random salt prevents precomputed rainbow table attacks
- Deterministic: The same password + salt + parameters always produces the same key
Argon2d (GPU resistance),
Argon2i (side-channel resistance), and
Argon2id (hybrid — recommended by RFC
9106). Qlerky uses Argon2id, the
variant recommended for password hashing and key
derivation in interactive applications.
pseudocode · Argon2id // Key derivation pipeline salt = generateRandomBytes(32) // 256-bit random salt key = Argon2id( password = masterPassword, salt = salt, memory = 65536, // 64 MB RAM required iterations = 3, // time cost passes parallelism = 4, // thread lanes keyLength = 32 // 256-bit AES key output ) // Encrypt vault with derived key iv = generateRandomBytes(12) // 96-bit IV for GCM encryptedVault = AES_GCM_encrypt(key, iv, vaultJSON) // Stored on disk: salt + iv + encryptedVault // masterPassword and key are NEVER persisted
The 64 MB memory requirement is the key differentiator from PBKDF2. An attacker trying to brute-force a master password cannot run millions of parallel attempts on a GPU — each attempt consumes 64 MB of RAM, making large-scale parallelism hardware-prohibitive rather than just computationally slow.
Master Password Handling
The master password has a carefully constrained lifecycle inside Qlerky:
Password Entry
The user types the master password into a secure text field. The string is held in memory only for the duration of key derivation.
Key Derivation
Argon2id transforms the password into a 256-bit AES key. The original password string is released for garbage collection immediately after.
Session Key in Memory
The derived key remains in memory for the duration of the active session. It is used to decrypt vault entries on-demand.
Session Termination
When the app is backgrounded, locked, or closed, the in-memory key is zeroed out. The next open requires re-entry of the master password (or biometric verification if configured).
Biometric Unlock
For user convenience, Qlerky supports Android's
BiometricPrompt API to allow
fingerprint or face unlock. Biometric authentication
does not replace the master password — instead, the
derived key is stored in the Android
Keystore (hardware-backed secure
enclave when available) and is only released by the
OS after successful biometric verification. The
master password is still required to initially
unlock after a fresh install or if biometrics are
unavailable.
TOTP Two-Factor Authentication #
Qlerky implements TOTP (Time-based One-Time Password) as defined in RFC 6238. TOTP is the standard used by Google Authenticator, Authy, Microsoft Authenticator, and all major 2FA implementations.
TOTP Algorithm Internals
A TOTP code is generated from two inputs: a shared secret (the Base32-encoded key from a QR code scan) and the current Unix timestamp divided into 30-second time windows.
TOTP · RFC 6238 // Step 1: Calculate current time window (T0 = 0, step = 30s) T = floor(currentUnixTime / 30) // Step 2: HMAC-SHA1 with secret key and time counter hmac = HMAC_SHA1( key = base32Decode(sharedSecret), message = toBytes(T, length=8) // 8-byte big-endian ) // Returns 20-byte hash // Step 3: Dynamic truncation offset = hmac[19] & 0x0F binary = (hmac[offset] & 0x7F) << 24 | (hmac[offset+1] & 0xFF) << 16 | (hmac[offset+2] & 0xFF) << 8 | (hmac[offset+3] & 0xFF) // Step 4: Extract 6-digit code otp = binary % 1_000_000 // yields 000000 – 999999
Next Code Preview
Most TOTP authenticators show only the current time window's code. This creates a frustrating user experience when a code expires in 1-3 seconds — not enough time to switch apps and paste it into a login field. Qlerky solves this with a next code preview.
The implementation is straightforward: Qlerky
computes TOTP for both T (current
window) and T + 1 (next window)
simultaneously, displaying both codes side by side
with a countdown timer for the current code's
remaining validity.
Next Code Logic currentT = floor(unixTime / 30) nextT = currentT + 1 currentCode = computeTOTP(secret, currentT) nextCode = computeTOTP(secret, nextT) secondsRemaining = 30 - (unixTime % 30) // UI: show currentCode + countdown + nextCode preview
2FA Secret Key Storage
The Base32-encoded TOTP secret (the key that would be revealed if you click "Can't scan QR code?" on a 2FA setup page) is treated identically to any other sensitive field in Qlerky — it is encrypted inside the vault using the same AES-GCM scheme. The secret is only decrypted into memory when the TOTP screen is active, and is zeroed from memory when the screen is dismissed.
Export Architecture #
Qlerky supports four export formats for individual vault entries. Each format makes a deliberate trade-off between security, portability, and covertness.
🗝️ Qlerky File
Max Security📷 QR Code
Encrypted🖼️ Inside Image
Steganographic📄 CSV
UnencryptedQlerky File Format (.qlerky) #
The .qlerky file is Qlerky's native
export format. It encodes a single vault entry as an
encrypted, self-contained binary blob that can only
be opened by another Qlerky installation knowing the
correct export password.
File Structure
binary layout ┌─────────────────────────────────────────────────────┐ │ 4 bytes │ Magic header: 0x514C4B59 ("QLKY") │ │ 1 byte │ Format version │ │ 32 bytes │ KDF salt (random per export) │ │ 4 bytes │ KDF iteration count │ │ 12 bytes │ AES-GCM IV (nonce) │ │ 16 bytes │ GCM authentication tag │ │ N bytes │ AES-GCM encrypted JSON payload │ └─────────────────────────────────────────────────────┘ // Decrypted JSON payload structure { "version": 1, "title": "Discord", "login": "user@multitools.ovh", "password": "s3cur3p4ss", "totp_secret": "BASE32SECRET...", // optional "notes": "...", "tags": ["exchange", "2fa"], "created_at": "2025-01-15T10:00:00Z" }
The export password (which can differ from the
master password) is used as input to the same KDF
pipeline. This means sharing a
.qlerky file requires communicating
only the export password to the recipient — the file
itself reveals nothing without it.
QR Code Export #
QR code export is designed for rapid, cable-free transfer between two Android devices running Qlerky. It encodes the same encrypted payload as the Qlerky File format, but represents it as a scannable QR code rather than a file.
Encoding Pipeline
Serialize entry to JSON
The vault entry is serialized to a compact JSON string.
AES-GCM encrypt
The JSON is encrypted using the same AES-GCM scheme with a user-provided export password.
Base64 encode
The binary ciphertext (salt + IV + tag + ciphertext) is Base64-encoded to produce a printable string safe for QR encoding.
QR generation
The Base64 string is encoded into a QR code using Error Correction Level M (15% redundancy). The QR is displayed full-screen for scanning.
Steganographic Image Export (LSB) #
Inside Image is Qlerky's most technically sophisticated export format. It uses Least Significant Bit (LSB) steganography to embed encrypted payload data into a cover image in a way that produces no visually detectable change to the image.
What is Steganography?
Steganography is the practice of hiding information inside a non-secret carrier medium. Unlike encryption (which obscures content but reveals the existence of a secret), steganography aims to hide the very existence of the hidden message. The word comes from Greek: steganos (covered) + graphein (writing).
In Qlerky's implementation, the carrier medium is a PNG image chosen by the user. The hidden payload is the AES-encrypted vault entry. The resulting stego-image is visually identical to the original — it can be shared publicly without revealing that any hidden data exists.
LSB Encoding Explained
Each pixel in a digital image is represented by three color channels: Red, Green, Blue (RGB). Each channel is an 8-bit value (0–255). The least significant bit of any channel value contributes only 1 unit out of 255 to the color — a change of 1 is completely imperceptible to human vision.
R: 200 → 11001000 G: 140 → 10001100 B: 80 → 01010000
R: 201 → 11001001 ← bit changed G: 140 → 10001100 B: 80 → 01010000
By modifying only the LSB of the Red channel, the
pixel color shifts from
RGB(200, 140, 80) to
RGB(201, 140, 80) — a difference of one
unit in a range of 256. This change is far below the
threshold of human color discrimination (typically
~2-5 units) and is also below the noise introduced
by most camera sensors.
Full Encoding Pipeline
LSB Steganography Pipeline // Phase 1: Prepare payload entryJSON = serialize(vaultEntry) encrypted = AES_GCM_encrypt(exportPassword, entryJSON) payload = [4-byte length header] + encrypted // Phase 2: Convert to bit stream bits = toBitArray(payload) // e.g. [1,0,1,1,0,0,1,0, ...] // Phase 3: Embed bits into image pixels for i, bit in enumerate(bits): pixel = coverImage[i / 3] // one bit per R/G/B channel channel = i % 3 // 0=R, 1=G, 2=B // Replace LSB of channel with payload bit pixel[channel] = (pixel[channel] & 0xFE) | bit // Phase 4: Export as lossless PNG savePNG(coverImage) // PNG preserves exact pixel values // JPEG would destroy LSB data
Capacity Calculation
Each pixel can hold 3 bits of payload (one per RGB channel). A 1920×1080 cover image has 2,073,600 pixels, giving a maximum capacity of ~6.2 million bits (~776 KB). A typical Qlerky vault entry (with password, login, 2FA secret, and notes) is well under 1 KB when JSON-serialized, so even a small 200×200 thumbnail has sufficient capacity.
| Image Size | Pixels | Max Payload | Suitable for |
|---|---|---|---|
| 200×200 | 40,000 | ~15 KB | Single entry ✓ |
| 1280×720 | 921,600 | ~345 KB | Multiple entries ✓ |
| 1920×1080 | 2,073,600 | ~776 KB | Full vault export ✓ |
Why PNG Only?
LSB steganography requires the cover image to preserve exact pixel values after saving. PNG uses lossless compression — pixel values are stored bit-for-bit identically. JPEG uses lossy compression — its discrete cosine transform (DCT) quantization step modifies pixel values throughout the image, destroying any LSB-encoded data. This is also why sharing the stego-image through platforms that re-compress images (WhatsApp, Instagram, most messengers) will corrupt the payload.
CSV Export #
CSV (Comma-Separated Values) export produces a plaintext, unencrypted file compatible with most major password managers including Bitwarden, 1Password, LastPass, KeePass, and others. It is intended for data migration scenarios — not for secure long-term storage.
CSV Schema
CSV Format name,login,password,totp_secret,url,notes,tags "Discord","user@multitools.ovh","p4ssw0rd!","BASE32SECRET","discord.com","","social" "Binance","trader@mail.com","exch4ng3pass","TOTPSECRET123","binance.com","Main account","exchange,2fa"
Ready to take back control of your credentials?
Qlerky is free, offline, and available right now on Android.
Download on Google Play →Technical FAQ #
Can I verify Qlerky isn't making network requests?
Yes. Enable Android's built-in
Developer Options → Network traffic
monitor, or use an app like NetGuard to
observe that Qlerky makes zero outbound connections
during normal operation. You can also run it in
airplane mode — all functionality remains available.
How does Qlerky compare to KeePass for Android?
Both are offline-first password managers. Qlerky differentiates with native TOTP 2FA storage with next-code preview, steganographic export, and a purpose-built mobile UI designed specifically for credential management for exchanges and services. KeePass-compatible formats (KDBX) are not directly supported, but CSV import/export enables migration in both directions.
What happens to the vault if I uninstall the app?
Android removes the app's private data directory on uninstall by default. Your vault is deleted along with the app unless you first export a backup using the Qlerky File format. Always export a backup before uninstalling.
Is the source code available?
Qlerky is a private application by Hidden Flame. The security model described in this document represents the implemented architecture. If you are a security researcher and wish to discuss the implementation in more detail, feedback and responsible disclosure inquiries are welcome through the app's Play Store listing.
Does Qlerky support HOTP (counter-based OTP)?
Currently, Qlerky supports TOTP (time-based) only, which covers the vast majority of 2FA implementations used by exchanges, email providers, and social platforms. HOTP (HMAC-based, counter-driven) support is under consideration for future releases.
Topic Index #
Keywords and topics covered in this documentation, useful for finding related information: