androidengineers.Book a session

Security Architecture

Data at Rest/In Transit Encryption

article25 minHard

Every app handles data in two states: in transit (moving over the network) and at rest (stored on the device). Each state has different threats and requires different defenses.

Data in Transit: TLS

All network traffic must use TLS. Android enforces this via the Network Security Configuration:

<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <!-- Block all cleartext traffic (enforces HTTPS everywhere) -->
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <!-- Trust only the system CA store — no user-installed CAs -->
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>
<!-- AndroidManifest.xml -->
<application
    android:networkSecurityConfig="@xml/network_security_config"
    ... />

cleartextTrafficPermitted="false" causes any HTTP (non-TLS) request to throw a java.io.IOException. This is the default on API 28+, but making it explicit is good practice.

Certificate Pinning (In Transit)

For high-security endpoints, pin the certificate hash so the app rejects unexpected certificates:

val certificatePinner = CertificatePinner.Builder()
    .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")   // leaf
    .add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")   // backup
    .build()

val client = OkHttpClient.Builder()
    .certificatePinner(certificatePinner)
    .build()

Get the pin hash:

# From the certificate file
openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

Certificate pinning risks:

  • If the pin expires without an app update → all users are blocked
  • Pin at the intermediate CA level, not the leaf, to reduce rotation risk
  • Always include a backup pin

Data at Rest: File Encryption

Use EncryptedFile for files that contain sensitive data:

// implementation("androidx.security:security-crypto:1.1.0-alpha06")

val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val encryptedFile = EncryptedFile.Builder(
    context,
    File(context.filesDir, "sensitive_data.enc"),
    masterKey,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

// Write
encryptedFile.openFileOutput().use { output ->
    output.write(sensitiveData.toByteArray())
}

// Read
encryptedFile.openFileInput().use { input ->
    val content = input.readBytes().toString(Charsets.UTF_8)
}

Data at Rest: Database Encryption (SQLCipher)

For full database encryption, use SQLCipher — a Room-compatible SQLite variant that encrypts the entire database file:

// implementation("net.zetetic:android-database-sqlcipher:4.5.4")
// implementation("androidx.sqlite:sqlite-ktx:2.3.1")

val passphrase = SQLiteDatabase.getBytes(userPassword.toCharArray())
val factory = SupportFactory(passphrase)

val db = Room.databaseBuilder(context, AppDatabase::class.java, "encrypted.db")
    .openHelperFactory(factory)  // ← uses SQLCipher instead of standard SQLite
    .build()

Passphrase management:

  • Don't hardcode the passphrase — generate it on first run and store in Keystore-encrypted preferences
  • Or derive from user's biometric/PIN-gated Keystore key — requires authentication before any DB access

What NOT to Encrypt

Over-encryption has costs — increased complexity, performance overhead, and key management burden:

DataEncrypt at Rest?
Auth tokens, session keysYes — EncryptedSharedPreferences
Private messages, health dataYes — EncryptedFile or SQLCipher
User name, profile photo URLNo — public data, low sensitivity
App config, feature flagsNo — not sensitive
Cached API responsesSituational — if they contain PII

Key Takeaways

ConcernSolution
All network trafficcleartextTrafficPermitted="false" in Network Security Config
High-security API endpointsCertificate pinning with OkHttp CertificatePinner
Sensitive preference valuesEncryptedSharedPreferences (Jetpack Security)
Sensitive filesEncryptedFile (Jetpack Security)
Full database encryptionSQLCipher with Room
Passphrase storageGenerate once, encrypt with Keystore

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
Data at Rest/In Transit Encryption | Android System Design | Android Engineers