Implementing Local Data Encryption in a Mobile Application

Implementing Local Data Encryption in a Mobile Application We have been integrating local data encryption on iOS and Android for over 5 years. Clients often come with a problem: after a device is compromised, user data ends up in plain sight. The reason is simple — encryption is either not implem

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1003
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

Implementing Local Data Encryption in a Mobile Application

We have been integrating local data encryption on iOS and Android for over 5 years. Clients often come with a problem: after a device is compromised, user data ends up in plain sight. The reason is simple — encryption is either not implemented or implemented with errors. An unencrypted SQLite database on Android is just a file: adb pull /data/data/com.yourapp/databases/app.db on a rooted device — and all data is readable with any SQLite browser. On iOS, the situation is slightly better due to the Data Protection API, but only if the developer hasn't forgotten to set the correct NSFileProtectionKey — and this is often overlooked. We guarantee that after our work, your data remains protected even with physical access to the device.

What we encrypt and how

The task breaks down into three independent layers: database, files, secrets.

Database. The standard is SQLCipher. A fork of SQLite with transparent AES-256 encryption at the page level. On Android it is integrated via net.zetetic:android-database-sqlcipher, on iOS via SQLCipher.xcframework. Room on Android works with SQLCipher through SupportOpenHelperFactory — switching involves simply replacing the factory in Room.databaseBuilder() and adding the key. The key is generated once, stored in Keystore/Keychain, never stored in SharedPreferences or UserDefaults in plaintext.

On first launch on Android:

val key = generateAes256Key() // via KeyGenerator with KeyStore provider val encryptedKey = encryptWithKeystore(key) // RSA/AES through AndroidKeyStore prefs.putString("db_key_enc", Base64.encode(encryptedKey)) 

Then every time the database is opened, we decrypt the key and pass it to SQLCipher. Without PRAGMA key, the database simply won't open.

Files. For images, PDFs, cache — AES-256-GCM via javax.crypto.Cipher on Android or CryptoKit.AES.GCM on iOS (Swift 5.5+). GCM is important: it provides both confidentiality and integrity authentication. CBC without a MAC is a poor choice, vulnerable to padding oracle attacks.

On Flutter, the flutter_secure_storage package is convenient for secrets and encrypt for files, but under the hood both use the same native APIs — wrappers, not replacements.

Secrets (API keys, tokens). Only Keychain (iOS) and Android Keystore. Not UserDefaults, not SharedPreferences, not AsyncStorage in React Native. Keychain on iOS is encrypted with keys bound to the Secure Enclave; Keystore on Android with API 23+ binds keys to TEE or SE — they cannot be exported even with root.

Why encrypting the database specifically is important

The database is the most vulnerable point. It typically stores user profiles, shopping lists, operation history. If an attacker gains physical access to the device (loss, theft) and bypasses the lock screen, an unencrypted database means full data access. SQLCipher makes the database unreadable without the key. Even when analyzing a RAM dump, the key does not surface because it is stored in hardware-backed Keystore.

Typical mistakes that break the entire scheme

First — incorrect protection class on iOS. FileProtectionType.complete means the file is inaccessible while the device is locked. But if the app receives a push notification in the background and tries to read the database — crash. Developers panic and switch to completeUnlessOpen or remove protection altogether. The correct solution is to separate data: critical under .complete, background operations under .completeUnlessOpen.

Second — storing the key alongside the data. We encountered a case where the database encryption key was in the same directory as the encrypted database, simply in a file key.bin. That's not encryption, that's renaming.

Third — using the user's password directly as the key. AES requires 128 or 256 bits. A password like "qwerty123" is not a key. A KDF is needed: PBKDF2 with a minimum of 100,000 iterations or Argon2id. On iOS — CommonCrypto.CCKeyDerivationPBKDF, on Android — SecretKeyFactory with PBKDF2WithHmacSHA256.

Layer iOS Android
Database SQLCipher + CoreData SQLCipher + Room
Files CryptoKit AES-GCM javax.crypto.Cipher AES-GCM
Secrets Keychain (Secure Enclave) Android Keystore (TEE/SE)

Integration with biometrics

An advanced option — the database encryption key is protected by biometrics via Keystore/Keychain. On Android: KeyGenParameterSpec.Builder with .setUserAuthenticationRequired(true) and .setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG). The key is created once on first biometric login; then each time the app opens, the user authenticates, the key is unlocked from Keystore, and the database opens.

On iOS, similarly via kSecAttrAccessControl with SecAccessControlCreateWithFlags and the .biometryAny or .biometryCurrentSet flag. Difference: .biometryCurrentSet invalidates the key when new fingerprints are added — this is important for banking apps (according to official Apple documentation).

What is included in the work

Full-cycle encryption implementation turnkey:

  • Inventory of stored data and classification by criticality.
  • Key scheme selection and integration with Keystore/Keychain.
  • Implementation of encryption layer for database, files, and secrets.
  • Migration of existing data (if any).
  • Testing all scenarios: app update, restore from backup, biometric changes.
  • Documentation and training for your team.

Process

We start with an inventory: what is stored where, whether encryption already exists, which data falls under requirements (PCI DSS, GDPR, local regulations). Then — key scheme selection, encryption layer implementation, integration with the existing storage. Separately — testing scenarios: app update, restore from backup, user biometric changes.

The timeline depends on data volume and the existence of a current storage scheme. If a database already exists and needs migration to SQLCipher — 3–5 days including testing. File cache encryption and Keychain integration — an additional 1–2 days. A full scheme from scratch for a new project is faster.

We will assess your project for free. Contact us — we will analyze your current storage scheme and offer the optimal solution with a security guarantee.