Files
Kordant/docs/encrypted-storage-audit-report.md
2026-06-01 12:58:34 -04:00

6.7 KiB
Raw Permalink Blame History

Encrypted Storage Audit Report

Overview

Security audit of all local data storage in the Kordant Android app, completed as part of Android Production Readiness (Task 07).

Audit Date

2026-06-01

Classification: Sensitive vs Non-Sensitive

Sensitive Data (requires encryption at rest)

Data Storage Location Encryption Reason
Auth access token SecureStorageManager (EncryptedSharedPreferences) AES-256-GCM Session credential
Auth refresh token SecureStorageManager (EncryptedSharedPreferences) AES-256-GCM Long-lived credential
User profile (name, email, phone) SecureStorageManager + CacheManager AES-256-GCM + AES-256-GCM file PII
Biometric preference SecureStorageManager (EncryptedSharedPreferences) AES-256-GCM Security-sensitive setting
Subscription data CacheManager (encrypted file) AES-256-GCM file Payment-related info
Voice enrollments (biometric prints) CacheManager (encrypted file) AES-256-GCM file Biometric data
FCM device token SecureStorageManager (EncryptedSharedPreferences) AES-256-GCM Device identifier

Non-Sensitive Data (plaintext acceptable)

Data Storage Location Notes
Theme preference (system/light/dark) UserPreferencesDataStore User setting, no PII
Dark mode toggle UserPreferencesDataStore User setting
Notification preferences UserPreferencesDataStore User setting
Language/locale UserPreferencesDataStore User setting
Onboarding completion UserPreferencesDataStore App state
Watchlist items CacheManager (plain file) External entities being monitored
Data exposures CacheManager (plain file) Public data breach records
Alerts CacheManager (plain file) Notification records
Spam rules CacheManager (plain file) Call filtering rules
Properties CacheManager (plain file) Property addresses (public record)
Voice analysis results CacheManager (plain file) Analysis output, not raw prints
Broker listings CacheManager (plain file) Public broker data
Removal requests CacheManager (plain file) Request status
Pending request queue cacheDir/pending_requests.json Offline queue (transient)

Architecture Decisions

1. Two-tier Secure Storage

  • SecureStorageManager: Wraps EncryptedSharedPreferences (AES-256-GCM, key in Android Keystore) for persistently stored secrets that survive app restarts (auth tokens, biometric pref, cached user profile).
  • CacheManager (encrypted mode): AES-256-GCM file-level encryption for TTL-bounded cached responses containing PII. Uses a derived key (acceptable for transient cache data).

2. DataStore for Non-Sensitive Preferences

  • UserPreferencesDataStore uses androidx.datastore:datastore-preferences for non-sensitive user settings.
  • Replaces in-memory-only preferences (previous state: ViewModels held settings in memory without persistence).
  • Excluded from encrypted storage because these settings contain no PII or credentials.

3. Secure Deletion Strategy

  • Overwrite-before-remove: Sensitive keys in SecureStorageManager are overwritten with random data 3× before removal.
  • Logout: Clears auth tokens (with overwrite), cache files (with secure delete), and DataStore preferences.
  • Account deletion (GDPR): clearAllData() removes absolutely everything including biometric preferences.

4. Cache Security

  • 50 MB size limit: CacheManager enforces a global 50 MB limit with LRU-like eviction (oldest files deleted first).
  • Sensitive key encryption: Cache files for current_user, subscription, and voice_enrollments are AES-256-GCM encrypted.
  • Secure eviction: When evicting cache files, sensitive ones are overwritten with random data before deletion.

5. Backup Exclusion Strategy

  • kordant_secure_storage.xml and kordant_auth_prefs.xml: Excluded from both cloud backup and device transfer because:
    • Master key is device-bound (Android Keystore), so backup would be undecryptable on another device.
    • Auth tokens and PII should not persist across device transfers for security reasons.
  • kordant_user_preferences.xml (DataStore): Included in backup (non-sensitive settings).
  • Cache directories: Excluded from backup (rebuilt from API).
  • Cached PII files: Explicitly excluded from file-level backup.

Before vs After

SharedPreferences

Before After
Auth tokens in EncryptedSharedPreferences (but duplicated in AuthRepository and AuthInterceptor with separate instances) Unified SecureStorageManager singleton accessed via KordantApp.secureStorageManager
Biometric pref in plain SharedPreferences: kordant_biometric_prefs Migrated to EncryptedSharedPreferences via SecureStorageManager
No user profile persistence User profile persisted in SecureStorageManager (encrypted)

DataStore

Before After
No DataStore usage (settings were in-memory only in ViewModels) UserPreferencesDataStore for theme, language, notification preferences, onboarding status

CacheManager

Before After
All cache files in cacheDir/*.cache in plain JSON Sensitive keys (current_user, subscription, voice_enrollments) encrypted with AES-256-GCM on disk
No cache size limit 50 MB limit with automatic eviction
Simple file.delete() Secure overwrite + delete for sensitive cache files

Backup Rules

Before After
Default rules (everything included) Encrypted prefs explicitly excluded; only non-sensitive DataStore included

Verification Checklist

  • All sensitive data in EncryptedSharedPreferences
  • Auth tokens encrypted at rest
  • Refresh tokens encrypted at rest
  • Non-sensitive preferences in DataStore
  • No sensitive data in unencrypted cache
  • Secure deletion overwriting data
  • Sensitive storage excluded from backup
  • Logout clears all auth data
  • Account deletion removes all local data
  • No plaintext sensitive data discoverable in app files

Verification Commands (for QA)

# Check that encrypted prefs file exists and is binary (not plaintext)
# File is at /data/data/com.kordant.android/shared_prefs/kordant_secure_storage.xml
# It should NOT contain plaintext values

# Check that unencrypted cache files don't contain PII
# Files at /data/data/com.kordant.android/cache/*.cache
# grep for email, token, name patterns - should find nothing for sensitive keys

# Verify backup exclusion
# Check backup_rules.xml and data_extraction_rules.xml exclude encrypted prefs