Key Takeaways:
• Client-Side Encryption First: Data is encrypted locally on your device using AES-256-GCM before it ever touches a network connection.
• The Zero-Knowledge Principle: Firebase Cloud Firestore acts merely as a "dumb" storage locker for Base64 encrypted blobs. We have no keys to decrypt your journal.
• Robust Key Derivation: Master keys are derived dynamically in memory using PBKDF2-HMAC-SHA256 with 100,000 iterations, combining your User ID, PIN, and a 16-byte random salt.
• Blind Search: Searching across encrypted data is achieved via a local SQLite database utilizing HMAC-SHA256 blind indexing tokens.
- 1. The Synchronization Paradox: Convenience vs. Confidentiality
- 2. RozVibe’s Trust Model: The Zero-Knowledge Approach
- 3. Core Architecture: How the Data Flows
- 4. Key Derivation and Multi-Device Synchronization
- 5. The Anatomy of a Secure Payload
- 6. Blind Search and State Management
- 7. Handling Offline Scenarios and Eventual Consistency
- 8. Trade-offs, Limitations, and Threat Realities
- 9. Conclusion
1. The Synchronization Paradox: Convenience vs. Confidentiality
In the modern software ecosystem, users rightfully expect their data to magically appear across all their devices. If you write a journal entry on your smartphone during your morning commute, you expect it to be waiting for you on your desktop when you sit down with your coffee. This continuous availability is achieved through cloud synchronization.
However, traditional cloud synchronization models introduce a massive vulnerability: Server-Side Encryption (SSE). In an SSE paradigm, the application sends your plaintext data over a secure connection (TLS) to the provider's servers. Once there, the provider encrypts the data using a key they own and control, and stores it in their database. While this protects against physical theft of the server hardware, it provides zero protection against insider threats, compelled government access, or sophisticated server breaches.
For a platform like RozVibe, which handles intimate emotional data—such as 5 mood states ranging from Radiant to Stormy, personal calendar histories, and deeply private textual reflections—an SSE model is fundamentally unacceptable. We faced a distinct paradox: How do we offer the seamless multi-device synchronization users expect without ever possessing the capability to read the data we synchronize?
2. RozVibe’s Trust Model: The Zero-Knowledge Approach
To resolve the synchronization paradox, we built RozVibe entirely on a Client-Side Encryption (CSE) architecture. In this model, the cryptography happens directly on your device's hardware before any network request is ever initialized.
This is often referred to informally as a "Zero-Knowledge" architecture. While strictly speaking, "Zero-Knowledge Proofs" are a specific mathematical concept, in systems architecture, a zero-knowledge cloud means the server operator has zero knowledge of the plaintext data residing on their infrastructure. They store ciphertext, manage authentication, and handle data routing, but they lack the cryptographic keys required to decipher the payloads.
Our threat model assumes that our cloud infrastructure (Firebase) could be entirely compromised. If an attacker dumps the entire Cloud Firestore database, they will find nothing but randomized Base64 strings. Because we do not possess the cryptographic keys, we cannot comply with data requests, nor can malicious actors scrape emotional insights from our database.
3. Core Architecture: How the Data Flows
RozVibe is engineered using Flutter (specifically leveraging Dart SDK versions >=3.3.0 and <4.0.0). For our backend and synchronization layer, we utilize Firebase Auth and Cloud Firestore. However, Firestore is heavily abstracted behind our local cryptographic layer.
Captures rich-text journal, generates a fresh 12-byte IV.
Encrypts data using Dart's
encrypt package.
Concatenates IV + Ciphertext + Auth Tag, encodes to Base64.
Stores the encrypted BLOB and pushes updates to other devices.
When you save an entry, your rich-text content is intercepted by our state management system (powered by Riverpod). The plaintext is immediately routed to our encryption service. Only the resulting encrypted BLOB, alongside minimal unencrypted metadata necessary for database querying (such as your userId, an encrypted date_index, and an isFavorite boolean flag), is pushed to Firestore.
4. Key Derivation and Multi-Device Synchronization
The most complex challenge in Client-Side Encryption is key management. If the server doesn't hold the encryption key, how does your secondary device decrypt the data?
Instead of manually transferring a key file between devices, RozVibe utilizes deterministic key derivation. We use PBKDF2-HMAC-SHA256 (Password-Based Key Derivation Function 2) configured to 100,000 iterations. This function is intentionally computationally expensive. It takes an input password and "stretches" it, making brute-force guessing attacks mathematically unfeasible for modern hardware.
The 76-Byte Key Breakdown
Our implementation derives exactly 76 bytes of key material from your inputs. Here is how that memory is allocated:
- Bytes 0–31 (32 bytes): The master AES-256 encryption key used for your journal entries.
- Bytes 32–43 (12 bytes): A legacy fallback Initialization Vector (used only for backward compatibility with older database schemas).
- Bytes 44–75 (32 bytes): An HMAC-SHA256 search key utilized exclusively for our blind indexing search functionality.
The Role of the 16-Byte Salt
A deterministic key derivation function requires a "salt" to prevent attackers from using precomputed hash tables (rainbow tables). When you first create your RozVibe account, the app generates a cryptographically secure 16-byte random salt using IV.fromSecureRandom(16).
This salt is stored locally in FlutterSecureStorage (which interfaces with Android's EncryptedSharedPreferences and the iOS Keychain) but is also synchronized to Cloud Firestore. Is syncing the salt a security risk? No. A cryptographic salt is not designed to be a secret. Its sole purpose is to ensure that even if two users choose the exact same PIN, their derived encryption keys will be completely different. Because the salt is available in Firestore, when you log into a new device, the app fetches your unique salt, asks for your PIN, and runs the PBKDF2 function to derive the exact same 76 bytes of key material locally.
The Derivation Input
The actual input string fed into the PBKDF2 algorithm is a combination of your account identifier and your local security credential: ${userId}_${pin ?? "default_secure_vault"}. If a user opts not to use a custom PIN lock, the system defaults to a standard vault string, relying entirely on Firebase Auth to gatekeep access to the ciphertext blob.
5. The Anatomy of a Secure Payload
We utilize AES-256 in GCM mode (Galois/Counter Mode). GCM was specifically chosen over older modes like CBC (Cipher Block Chaining) because it is an Authenticated Encryption with Associated Data (AEAD) cipher.
This means GCM doesn't just provide confidentiality (hiding the data); it also provides integrity. It generates an Authentication Tag. If an attacker or a database glitch modifies even a single bit of your encrypted journal entry in Firestore, the GCM decryption process will immediately fail, preventing the app from displaying corrupted or maliciously altered data.
Managing Initialization Vectors (IVs)
A critical rule of AES-GCM is that an Initialization Vector (IV) must never be reused with the same key. To guarantee this, RozVibe generates a fresh, cryptographically secure 12-byte IV for every single encryption event via IV.fromSecureRandom(12).
When the data is downloaded from Firestore, the client decodes the Base64 string, slices off the first 12 bytes to use as the IV, and passes the remainder (ciphertext + auth tag) to the AES decrypter. Because the IV is unique per entry, pattern analysis on the ciphertext is impossible.
6. Blind Search and State Management
If all your journal entries are encrypted before reaching the cloud, how can you search for a specific word across years of journals? A standard database query like WHERE content LIKE "%anxiety%" is impossible because the database only sees random Base64 noise.
RozVibe solves this using a local SQLite implementation (rozvibe_search.db) combined with Blind Indexing. We utilize the 32-byte HMAC-SHA256 search key generated during our PBKDF2 derivation.
When you type a journal entry locally, the app tokenizes the words. Each word is hashed using the HMAC-SHA256 key, creating a "blind token." These tokens are stored locally on your device mapping to specific entry IDs. When you search for a word, the app hashes your search term using the same key and looks up the resulting token in the local SQLite database. The actual plaintext words are never indexed.
Because these search indexes are stored locally, logging into a new device requires a lazy backfill system. The new device will slowly pull down encrypted entries in the background, decrypt them locally in memory, generate the blind tokens, and populate the fresh local SQLite database—all without exposing the plaintext to the cloud.
In-Memory Key Hygiene
Cryptography is only as strong as its key management. Within the RozVibe architecture, keys exist exclusively in ephemeral memory (RAM) managed by Riverpod. They are never written to disk in plaintext. When a user manually logs out or triggers the Danger Zone data wipe, a strict clear() method is invoked, setting _key = null and _searchKey = null, immediately obliterating the keys from memory and rendering the local device entirely locked until the PBKDF2 derivation happens again.
7. Handling Offline Scenarios and Eventual Consistency
A journaling application must function flawlessly in low-connectivity environments—whether you are on a subway or deep in a forest. To achieve this, RozVibe leans heavily on Firebase's built-in offline caching mechanisms.
When you are offline, all encryption pipelines execute normally. The resulting encrypted payloads are queued in the local Firebase cache. The app UI reads directly from this local cache, providing instantaneous feedback. Once the operating system detects network availability, the Firebase SDK automatically pushes the queued mutations to the cloud.
If you modify an entry on your phone while offline, and simultaneously modify the same entry on your iPad, RozVibe relies on a Last-Write-Wins (LWW) resolution strategy based on Firestore server timestamps upon reconciliation. Because both writes are cryptographically sound, eventual consistency is achieved without compromising the encryption wrapper.
8. Trade-offs, Limitations, and Threat Realities
Transparency is a core tenet of our security philosophy. No system is invincible, and we refuse to use marketing terminology like "military-grade" or "unhackable." Client-Side Encryption has specific limitations.
Our architecture protects your data against network interception, server breaches, and rogue database administrators. However, it cannot protect against endpoint compromise. If your smartphone is infected with a sophisticated keylogger or OS-level malware, the attacker operates at the same privilege level as the application. They can capture your PIN as you type it or read the plaintext from RAM before it hits our encryption pipeline.
Similarly, if you use a weak PIN, an adversary who gains physical access to your unlocked device and extracts the local application sandbox could theoretically brute-force the PBKDF2 derivation locally. The security of RozVibe is a partnership between our cryptographic architecture and your personal device hygiene.
9. Conclusion
Building a secure, multi-device syncing application that respects user privacy is not trivial. It requires abandoning the convenience of Server-Side Encryption and dealing with the complex realities of deterministic key derivation, distributed state management, and blind search indexing.
By enforcing a strict Client-Side Encryption architecture using AES-256-GCM and keeping the server completely blind, RozVibe ensures that your emotional insights, daily reflections, and calendar history remain exactly where they belong: under your exclusive control.
Frequently Asked Questions
We actively avoid marketing terms like "military-grade" as they are vague and often misleading. We use AES-256-GCM, which is the exact same cryptographic standard approved by the NSA for top-secret information. However, we prefer precise technical terminology over hype. What matters more than the algorithm itself is our Client-Side architecture, which ensures we do not possess the keys.
Because RozVibe operates on a zero-knowledge architecture, your PIN is fundamentally tied to the mathematical derivation of your encryption key. We do not store your PIN on our servers. If you forget your PIN, we have absolutely no way to reset it or recover your data. The data remains mathematically locked forever.
AES-GCM provides both confidentiality and data integrity. Older modes like CBC encrypt data but do not inherently verify if the ciphertext has been tampered with. GCM appends an Authentication Tag to the encrypted blob. If even a single byte is altered during sync, the decryption fails, preventing malicious data manipulation.
No. While we use Google's Cloud Firestore infrastructure to store and sync data, the data leaves your device already encrypted as a Base64 blob. Firebase servers only see random, unintelligible text. They do not have access to your local PIN or the PBKDF2 execution process happening in your device's RAM.
No. In cryptography, a salt is not a secret; it is a public modifier. Its purpose is to ensure that two users with the same PIN do not end up with the same encryption key, and to prevent attackers from using precomputed "rainbow tables" to guess keys rapidly. Syncing the salt is standard practice and required for multi-device login.
We use a technique called "Blind Indexing." When you write an entry, your device locally hashes the words using an HMAC-SHA256 key derived exclusively on your device. These hashed tokens are stored in a local SQLite database (rozvibe_search.db). When you search, the term is hashed, and the database looks for matching hashes. The plaintext words are never exposed to the index.
Yes. RozVibe is designed as an offline-first application. When you have no connection, entries are encrypted locally and stored in a secure local Firebase cache. You can view, edit, and search normally. Once your device reconnects to the internet, the encrypted changes are silently synced in the background.