ARTICLE AD BOX
I recently started a new Android app project using Kotlin and Jetpack Compose. I added code to setup the Room database, so I can store data locally with the app. I now have a need to encrypt the data that is stored in the database. I have found multiple different sources online saying that I should use EncryptedSharedPreferences and MasterKey/MasterKeys, but all of which are deprecated. Since they are deprecated, I thought there might be a new way of handling the secure generation and storage of a key, but I cannot seem to find any examples. It seems Google deprecated the code and then did not provide any new proper way of encrypting the Room database.
I tried using KeyGenerator to generate the key so that I can then store it in a KeyStore, but the generateKey method only seems to return back a SecretKey object with null for format and encoded. Since format and encoded are null, then I have nothing to store in the KeyStore and I have nothing to send SupportFactory constructor. Therefore I have no SupportFactory object that I can send to the openHelperFactory method when building the Room database.
AeadConfig.register() val alias = "DatabaseKey" val keySpec = KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore" ) keyGenerator.init(keySpec) val secretKey = keyGenerator.generateKey() Log.d("AppDatabase", "secretKey = $secretKey") Log.d("AppDatabase", "secretKey.format = ${secretKey.format}") Log.d("AppDatabase", "secretKey.encoded = ${secretKey.encoded}") Log.d("AppDatabase", "secretKey.algorithm = ${secretKey.algorithm}") val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(null) val secretKey2 = (keyStore.getEntry(alias, null) as KeyStore.SecretKeyEntry).secretKey Log.d("AppDatabase", "secretKey2 = $secretKey2") Log.d("AppDatabase", "secretKey2.format = ${secretKey2.format}") Log.d("App val factory = SupportFactory(<NOT_SURE_WHAT_GOES_HERE_secretKey.encoded,_secretKeyString,_OR_SOMETHING_ELSE????>) return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, "app_database" ) .openHelperFactory(factory) .addCallback(object : Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) // Insert demo data here on a background thread // since database operations can be long-running. CoroutineScope(IO).launch { addDevelopmentData(getDatabase(context.applicationContext)) } } }) val returnInstance = instance.build() INSTANCE = returnInstance returnInstance }Does anyone know what I might be doing wrong? Does anyone know of a working non-deprecated solution?
