Security
Encryption
FitBuddy encrypts your backup data with AES-256-GCM — the same cipher used by governments, banks, and secure messaging apps. Your health data is protected by cryptography that is computationally infeasible to break.
Overview
When you set a backup password, FitBuddy encrypts all exported and cloud-uploaded data on your device before it ever leaves the app. The encrypted backup is a self-describing JSON envelope containing the ciphertext and the non-secret parameters needed to decrypt it — but never the password itself.
- Cipher: AES-256-GCM (authenticated encryption)
- Key derivation: PBKDF2-HMAC-SHA256, 120,000 iterations
- Salt: 128-bit (16 bytes), cryptographically random, per-backup
- Nonce/IV: 96-bit (12 bytes), cryptographically random, per-backup
- Auth tag: 128-bit GCM authentication tag
- Key size: 256 bits
Without the password, the ciphertext is indistinguishable from random noise. There is no backdoor, no master key, and no recovery mechanism — this is by design.
AES-256-GCM cipher
AES (Advanced Encryption Standard) with a 256-bit key is the gold standard of symmetric encryption. It was selected by NIST through a rigorous multi-year public competition and is approved for Top Secret classified data by the US government (NSA Suite B / CNSA). There is no known practical attack against AES-256 — a brute-force search of the 2256 key space would require more energy than exists in the observable universe.
GCM (Galois/Counter Mode) adds authenticated encryption: it simultaneously encrypts and integrity-protects the data. If even a single bit of the ciphertext or envelope metadata is tampered with, decryption fails immediately with an authentication error rather than producing garbled output. This means:
- Confidentiality — no one without the key can read the plaintext
- Integrity — any modification to the encrypted file is detected
- Authenticity — the data provably came from the same password holder
Key derivation (PBKDF2)
Your password is never used directly as an encryption key. Instead, FitBuddy derives a 256-bit key from it using PBKDF2-HMAC-SHA256 with the following parameters:
| Parameter | Value |
|---|---|
| Algorithm | PBKDF2WithHmacSHA256 |
| Iterations | 120,000 |
| Salt length | 128 bits (16 bytes) |
| Output key length | 256 bits |
The high iteration count makes each password guess computationally expensive. At 120,000 rounds of HMAC-SHA256, even a dedicated GPU cluster testing billions of passwords would need astronomical time to crack a strong password. A random 16-character password at this iteration count would take longer than the age of the universe to brute-force.
The random salt (generated fresh for each backup via SecureRandom) ensures
that identical passwords produce different keys across different backups. This defeats
precomputation attacks (rainbow tables) entirely — an attacker cannot build a lookup table
because every backup has a unique salt.
Envelope format
Encrypted backups are stored in a versioned, self-describing JSON envelope:
{
"fitbuddyBackup": 1,
"enc": "AES-GCM",
"kdf": "PBKDF2-HMAC-SHA256",
"iterations": 120000,
"salt": "<base64, 16 random bytes>",
"iv": "<base64, 12 random bytes>",
"ciphertext": "<base64, AES-256-GCM(payload) + 128-bit auth tag>"
}
The envelope stores only the non-secret parameters needed to re-derive the key and decrypt. The password is never written into the envelope, the file, or any export. Key fields:
-
fitbuddyBackup— version marker (currently1); allows future upgrades without breaking older files -
enc— cipher identifier;"AES-GCM"for encrypted,"none"for unencrypted-but-wrapped exports -
kdf/iterations/salt— everything needed to re-derive the same 256-bit key from the correct password -
iv— the unique 96-bit nonce used for GCM encryption; never reused with the same key -
ciphertext— base64 of the AES-GCM encrypted payload (your backup JSON) concatenated with the 128-bit authentication tag
FitBuddy also supports importing legacy plain-JSON backups (pre-encryption) and
unencrypted-but-wrapped backups ("enc": "none") for forward compatibility.
The format is classified automatically at import time without needing user input about
the file type.
Android Keystore protection
If you set a custom cloud-backup password, FitBuddy remembers it on-device so automatic uploads can re-encrypt without prompting you each time. This remembered password is itself encrypted using the Android Keystore — a hardware-backed (on supported devices) secure key storage:
- A dedicated AES-256-GCM key is generated inside the Keystore under the alias
fitbuddy_cloud_backup_pw_v1 - This key is non-exportable — it can never be read out, even by root or a device backup
- The password is encrypted with this Keystore key; only the resulting ciphertext blob
(base64 of
IV ‖ ciphertext) is persisted in DataStore - The plaintext password is never written to disk, never included in exported backups, and never uploaded to any server
On devices with a hardware security module (StrongBox or TEE), the Keystore key lives in dedicated tamper-resistant silicon. Extracting it would require physically attacking the chip — a level of effort beyond virtually all threat models.
Zero-knowledge design
FitBuddy's encryption follows a zero-knowledge architecture:
- The cloud never sees your plaintext. Data is encrypted on-device before upload. The server stores only the opaque ciphertext blob — it cannot read, index, or analyze your health data.
- No password recovery. There is no "forgot password" flow because the password is not stored anywhere — not on the device (only the Keystore-protected local copy for auto-upload), not in the cloud, not on any server. If you forget your password, the encrypted backup is irrecoverable.
- No master key / backdoor. There is no server-side key, admin override, or law-enforcement access mechanism. Only someone who knows your password can decrypt.
-
Per-backup randomness. Every export generates a fresh random salt and IV
via
java.security.SecureRandom. Even encrypting the same data with the same password twice produces entirely different ciphertext.
In-memory safety
FitBuddy takes care to minimise the time sensitive material spends in memory:
-
Passwords are handled as
CharArray(mutable) rather thanString(immutable, lingering in the heap). After use, every password array is explicitly zeroed withfill('\u0000'). -
Derived key bytes are zeroed in a
finallyblock immediately after the cipher operation completes — regardless of success or failure. -
The
PBEKeySpecis cleared viaclearPassword()as soon as key derivation finishes. -
UTF-8 encoding of the password avoids creating an intermediate immutable
String— it goes directly fromCharArraytoByteArrayvia aCharBufferwrap.
These measures ensure no recoverable copy of your password or key material survives in process memory after the operation.
Why this is unbreakable
"Unbreakable" is a strong claim, so here's the math:
- Key space: AES-256 has a key space of 2256 — approximately 1.16 × 1077 possible keys. For context, the estimated number of atoms in the observable universe is ~1080.
- Brute-force cost: Even at 1018 (one quintillion) key attempts per second — beyond any hardware that exists or is theoretically projected — exhausting 2256 keys would take ~3.7 × 1051 years. The universe is approximately 1.4 × 1010 years old.
- PBKDF2 cost amplification: The 120,000-iteration KDF means each password guess requires 120,000 HMAC-SHA256 operations. A high-end GPU that can do ~10 billion SHA-256/s would manage only ~83,000 PBKDF2 guesses/second. A strong 12-character alphanumeric password has ~71 bits of entropy — that's 2.4 × 1021 combinations, requiring ~900 million years on that GPU.
- No known shortcut: No practical attack against AES-256 exists. The best known theoretical attack (biclique) reduces the effective key strength from 256 bits to 254.4 bits — a meaningless difference at this scale.
- Quantum resistance: Grover's algorithm halves the effective key length against symmetric ciphers, reducing AES-256 to the equivalent of 128 bits — still far beyond feasible quantum brute-force for the foreseeable future and well above the 128-bit security threshold considered safe.
The weakest link is always the password.
The cryptography is unbreakable, but a weak or guessable password (like "password123") can still be cracked through dictionary attacks. Use a strong, unique password of at least 12 characters mixing letters, digits, and symbols. FitBuddy enforces a minimum of 8 characters.
Summary
| Layer | What it does |
|---|---|
| AES-256-GCM | Encrypts and authenticates your backup data with a 256-bit key |
| PBKDF2-HMAC-SHA256 | Derives the key from your password; 120k iterations make guessing expensive |
| Random salt (128-bit) | Unique per backup; defeats rainbow tables and precomputation |
| Random IV (96-bit) | Unique per backup; ensures identical data encrypts differently each time |
| GCM auth tag (128-bit) | Detects any tampering or corruption of the encrypted file |
| Android Keystore | Hardware-backed protection for the remembered cloud password on-device |
| Zero-knowledge upload | Cloud receives only ciphertext; plaintext never leaves the device |
| Memory zeroing | Passwords and keys are wiped from RAM after each operation |
FitBuddy treats your health data with the same seriousness as a banking app treats financial data. The encryption is not optional security theatre — it is a rigorous, standards-based implementation that makes your backed-up data cryptographically inaccessible to anyone without the password.
See also: Backup & cloud guide · Privacy policy · FAQ