From dee6739c5428d4fe66f85e698080a7fe08c8f54b Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Mon, 22 Jan 2024 19:27:38 +0530 Subject: [PATCH] TP-53465 | Migration of encryption library from android-database-sqlcipher to sqlcipher-android (#9246) --- app/proguard-rules.pro | 4 +- gradle/libs.versions.toml | 6 +- navi-pay/build.gradle | 3 +- .../com/navi/pay/db/SqlCipherOpenerFactory.kt | 153 ------------------ .../com/navi/pay/network/di/NaviPayModule.kt | 21 ++- .../com/navi/pay/utils/NaviPayConstants.kt | 3 - 6 files changed, 18 insertions(+), 172 deletions(-) delete mode 100644 navi-pay/src/main/kotlin/com/navi/pay/db/SqlCipherOpenerFactory.kt diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index d911005cb7..4be6e56e26 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -269,7 +269,7 @@ } # SQL Cipher --keep,includedescriptorclasses class net.sqlcipher.** { *; } --keep,includedescriptorclasses interface net.sqlcipher.** { *; } +-keep,includedescriptorclasses class net.zetetic.database.** { *; } +-keep,includedescriptorclasses interface net.zetetic.database.** { *; } -keep class androidx.lifecycle.SavedStateHandle { *; } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5912b5efb6..1dcb851523 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,6 +35,7 @@ androidx-pagingRuntimeKtx = "3.1.1" androidx-preferenceKtx = "1.2.0" androidx-securityCryptoKtx = "1.1.0-alpha03" androidx-test-espresso = "3.5.1" +androidx-sqlite = "2.2.0" androidx-test-junit = "1.1.5" androidx-test-monitor = "1.6.0" androidx-test-rules = "1.4.0" @@ -109,7 +110,7 @@ spotless = "6.24.0" truecaller = "3.0.0" visit = "1.24" wasabeef-recyclerviewAnimators = "4.0.1" -zetetic-androidDatabaseSqlcipher = "4.5.4" +zetetic-sqlcipherAndroid = "4.5.5" zxing = "3.3.3" [libraries] @@ -198,6 +199,7 @@ androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = " androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "room" } androidx-security-crypto-ktx = { module = "androidx.security:security-crypto-ktx", version.ref = "androidx-securityCryptoKtx" } +androidx-sqlite = { module = "androidx.sqlite:sqlite", version.ref = "androidx-sqlite" } androidx-test-espresso-contrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "androidx-test-espresso" } androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" } @@ -351,7 +353,7 @@ visit = { module = "com.github.VisitApp:VisitSDK", version.ref = "visit" } wasabeef-recyclerview-animators = { module = "jp.wasabeef:recyclerview-animators", version.ref = "wasabeef-recyclerviewAnimators" } -zetetic-android-database-sqlcipher = { module = "net.zetetic:android-database-sqlcipher", version.ref = "zetetic-androidDatabaseSqlcipher" } +zetetic-sqlcipher-android = { module = "net.zetetic:sqlcipher-android", version.ref = "zetetic-sqlcipherAndroid" } zxing = { module = "com.google.zxing:core", version.ref = "zxing" } diff --git a/navi-pay/build.gradle b/navi-pay/build.gradle index a4ed2437fe..dda5caf506 100644 --- a/navi-pay/build.gradle +++ b/navi-pay/build.gradle @@ -87,6 +87,7 @@ dependencies { implementation libs.androidx.lifecycle.viewmodel.ktx implementation libs.androidx.paging.compose implementation libs.androidx.room.paging + implementation libs.androidx.sqlite implementation libs.android.material implementation libs.android.play.core.ktx @@ -99,7 +100,7 @@ dependencies { implementation libs.raamcosta.composeDestinations.animation.core - implementation libs.zetetic.android.database.sqlcipher + implementation libs.zetetic.sqlcipher.android implementation libs.zxing diff --git a/navi-pay/src/main/kotlin/com/navi/pay/db/SqlCipherOpenerFactory.kt b/navi-pay/src/main/kotlin/com/navi/pay/db/SqlCipherOpenerFactory.kt deleted file mode 100644 index 0394463899..0000000000 --- a/navi-pay/src/main/kotlin/com/navi/pay/db/SqlCipherOpenerFactory.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * - * * Copyright © 2024 by Navi Technologies Limited - * * All rights reserved. Strictly confidential - * - */ - -package com.navi.pay.db - -import android.content.Context -import android.database.sqlite.SQLiteException -import androidx.sqlite.db.SupportSQLiteDatabase -import androidx.sqlite.db.SupportSQLiteOpenHelper -import com.google.android.play.core.splitinstall.SplitInstallHelper -import java.io.File -import net.sqlcipher.database.SQLiteDatabase -import net.sqlcipher.database.SQLiteDatabaseHook -import net.sqlcipher.database.SQLiteOpenHelper - -/** - * A factory to create [SupportSQLiteOpenHelper] instances that uses SQLCipher to encrypt the - * database. It is created to load the SQLCipher native libraries before opening the database using - * SplitInstallHelper Keep this updated with new SupportSQLiteOpenHelper in-case of Cipher Lin - * Update - * - * @param passphrase The passphrase to use to encrypt the database. - * @param hook The hook to use to configure the database. - * @param clearPassphrase Whether to clear the passphrase after opening the database. - */ -class SqlCipherOpenerFactory -@JvmOverloads -constructor( - private val passphrase: ByteArray, - private val hook: SQLiteDatabaseHook? = null, - private val clearPassphrase: Boolean = true -) : SupportSQLiteOpenHelper.Factory { - override fun create( - configuration: SupportSQLiteOpenHelper.Configuration - ): SupportSQLiteOpenHelper { - return SqlCipherOpenerHelper(configuration, passphrase, hook, clearPassphrase) - } -} - -class SqlCipherOpenerHelper -internal constructor( - configuration: SupportSQLiteOpenHelper.Configuration, - passphrase: ByteArray?, - hook: SQLiteDatabaseHook?, - clearPassphrase: Boolean -) : SupportSQLiteOpenHelper { - private val standardHelper: SQLiteOpenHelper - private val passphrase: ByteArray? - private val clearPassphrase: Boolean - - init { - loadLibs(configuration.context, configuration.context.filesDir) - this.passphrase = passphrase - this.clearPassphrase = clearPassphrase - standardHelper = - object : - SQLiteOpenHelper( - configuration.context, - configuration.name, - null as SQLiteDatabase.CursorFactory?, - configuration.callback.version, - hook - ) { - override fun onCreate(db: SQLiteDatabase) { - configuration.callback.onCreate(db) - } - - override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { - configuration.callback.onUpgrade(db, oldVersion, newVersion) - } - - override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { - configuration.callback.onDowngrade(db, oldVersion, newVersion) - } - - override fun onOpen(db: SQLiteDatabase) { - configuration.callback.onOpen(db) - } - - override fun onConfigure(db: SQLiteDatabase) { - configuration.callback.onConfigure(db) - } - } - } - - override val databaseName: String - get() = standardHelper.databaseName - - override val readableDatabase: SupportSQLiteDatabase - get() = writableDatabase - - override fun setWriteAheadLoggingEnabled(enabled: Boolean) { - standardHelper.setWriteAheadLoggingEnabled(enabled) - } - - override val writableDatabase: SupportSQLiteDatabase - get() { - val result: SQLiteDatabase - try { - result = standardHelper.getWritableDatabase(passphrase) - } catch (var8: SQLiteException) { - if (passphrase != null) { - var isCleared = true - val var4 = passphrase - val var5 = var4.size - var var6 = 0 - while (var6 < var5) { - val b = var4[var6] - isCleared = isCleared && b.toInt() == 0 - ++var6 - } - if (isCleared) { - throw IllegalStateException( - "The passphrase appears to be cleared. This happens by default the first time you use the factory to open a database, so we can remove the cleartext passphrase from memory. If you close the database yourself, please use a fresh SupportFactory to reopen it. If something else (e.g., Room) closed the database, and you cannot control that, use SupportFactory boolean constructor option to opt out of the automatic password clearing step. See the project README for more information.", - var8 - ) - } - } - throw var8 - } - if (clearPassphrase && passphrase != null) { - for (i in passphrase.indices) { - passphrase[i] = 0 - } - } - return result - } - - override fun close() { - standardHelper.close() - } -} - -/** - * Loads the SQLCipher native libraries using SplitInstallHelper - * - * @param context The context to use to load the libraries. - * @param workingDir The working directory to use to load the libraries. - */ -@Synchronized -fun loadLibs(context: Context, workingDir: File?) { - SQLiteDatabase.loadLibs(context, workingDir) { libNames -> - val var3 = libNames.size - for (var4 in 0 until var3) { - val libName = libNames[var4] - SplitInstallHelper.loadLibrary(context, libName) - } - } -} diff --git a/navi-pay/src/main/kotlin/com/navi/pay/network/di/NaviPayModule.kt b/navi-pay/src/main/kotlin/com/navi/pay/network/di/NaviPayModule.kt index 6d93b2337f..9ce5a71543 100644 --- a/navi-pay/src/main/kotlin/com/navi/pay/network/di/NaviPayModule.kt +++ b/navi-pay/src/main/kotlin/com/navi/pay/network/di/NaviPayModule.kt @@ -9,9 +9,9 @@ package com.navi.pay.network.di import android.content.Context import androidx.room.Room +import com.google.android.play.core.splitinstall.SplitInstallHelper import com.google.gson.Gson import com.navi.base.sharedpref.PreferenceManager -import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper import com.navi.common.model.ModuleName import com.navi.common.model.NetworkInfo import com.navi.common.utils.log @@ -35,7 +35,6 @@ import com.navi.pay.db.NAVI_PAY_APP_ENCRYPTED_DATABASE_MIGRATION_2_3 import com.navi.pay.db.NAVI_PAY_APP_ENCRYPTED_DATABASE_MIGRATION_3_4 import com.navi.pay.db.NaviPayAppDatabase import com.navi.pay.db.NaviPayAppEncryptedDatabase -import com.navi.pay.db.SqlCipherOpenerFactory import com.navi.pay.management.paytocontacts.PhoneContactManager import com.navi.pay.management.paytocontacts.PhoneContactManagerImpl import com.navi.pay.network.NaviPayHttpClient @@ -48,7 +47,6 @@ import com.navi.pay.onboarding.home.VpaQRCodeManager import com.navi.pay.onboarding.home.VpaQRCodeManagerImpl import com.navi.pay.permission.utils.PermissionStateProvider import com.navi.pay.permission.utils.PermissionStateProviderImpl -import com.navi.pay.utils.ENABLE_DEFAULT_SUPPORT_FACTORY import com.navi.pay.utils.KEY_DB_ENCRYPTION import com.navi.pay.utils.NAVIPAY_NETWORK_INFO_TIMEOUT import com.navi.pay.utils.NAVI_PAY_DATABASE_NAME @@ -61,7 +59,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Qualifier import javax.inject.Singleton -import net.sqlcipher.database.SupportFactory +import net.zetetic.database.sqlcipher.SupportOpenHelperFactory import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory @@ -138,17 +136,18 @@ object NaviPayNetworkModule { value = passphrase.toString(Charsets.ISO_8859_1) ) } - val sqlCipherOpenerFactory = + try { + SplitInstallHelper.loadLibrary(context, "sqlcipher") + } catch (e: Exception) { + e.log() try { - if (FirebaseRemoteConfigHelper.getBoolean(ENABLE_DEFAULT_SUPPORT_FACTORY)) { - SupportFactory(passphrase) - } else { - SqlCipherOpenerFactory(passphrase) - } + System.loadLibrary("sqlcipher") } catch (e: Exception) { e.log() - SqlCipherOpenerFactory(passphrase) } + } + + val sqlCipherOpenerFactory = SupportOpenHelperFactory(passphrase, null, true) return Room.databaseBuilder( context, NaviPayAppEncryptedDatabase::class.java, diff --git a/navi-pay/src/main/kotlin/com/navi/pay/utils/NaviPayConstants.kt b/navi-pay/src/main/kotlin/com/navi/pay/utils/NaviPayConstants.kt index 6b29733745..f090acea71 100644 --- a/navi-pay/src/main/kotlin/com/navi/pay/utils/NaviPayConstants.kt +++ b/navi-pay/src/main/kotlin/com/navi/pay/utils/NaviPayConstants.kt @@ -264,9 +264,6 @@ const val VPA_QR_CODE_IMAGES = "vpa_qr_code_images" const val QR_CODE_IMAGE_EXTENSION = ".jpeg" const val NAVI_PAY_DEBUG_LOG = "NAVI_PAY_DEBUG_LOG" -// Firebase Config Keys -const val ENABLE_DEFAULT_SUPPORT_FACTORY = "ENABLE_DEFAULT_SUPPORT_FACTORY" - // Image Quality Constant const val IMAGE_QUALITY = 20