简体   繁体   中英

Android Room TypeConverter to encrypt String column optionally based on other column value

Given the Entity:

@Entity(tableName = "otp_tokens")
data class DBEntity (
    @PrimaryKey(autoGenerate = true) 
    val id: Long,
    val data: String,
    val encryptionType: EncryptionType
)

EncryptionType :

enum class EncryptionType {
    PLAIN_TEXT,
    ENCRYPTED
}

I want to use a @TypeConverter to encrypt/decrypt the data String field when accessing the database, based on the value of the encryptionType field value. So for example if encryptionType == PLAIN_TEXT the TypeConverter should not do anything with the String value, but if encryptionType == ENCRPYTED it should encrypt/decrypt the data field.

When I write a TypeConverter for the data field I only get the String value of data in the encrypt/decrypt methods of the Converter and have no access to the encryptionType field, so how can I implement this?

Type Converters will only convert an unhandled Type to a Type that can be handled (stored).

So your options would be to

  • either have the Type for the data member/field as such a (unhandled) Type, or
  • to have DAO function that encrypts the data when inserting (and possibly similar when extracting the data)

Here's an example of the latter.

First the data field is changed to var to allow it's manipulation (encryption/decryption). Then the encryption/decryption functions are added so DBEntity becomes:-

@Entity(tableName = "otp_tokens")
data class DBEntity (
    @PrimaryKey(autoGenerate = true)
    val id: Long,
    var data: String,
    val encryptionType: EncryptionType
) {
    fun encryptData() {
        if (this.encryptionType.equals(EncryptionType.ENCRYPTED) ) {
            val sb = StringBuilder()
            for (i in 0..this.data.length - 1) {
                sb.append("~", this.data[i])
            }
            this.data = sb.toString()
        }
    }

    /* Not Tested/Used in the demo */
    fun decryptData(): String {
        if (this.encryptionType.equals(EncryptionType.ENCRYPTED)) {
            val sb = StringBuilder()
            for (i in 0..this.data.length - 2 step 2) {
                sb.append(this.data[i + 1])
            }
            return this.data
        } else {
            return this.data
        }
    }
}
  • obviously the encryption is just a very simple change to the data and that whatever encryption/decryption process you would want to implement would replace the method used for the example/demo.

    • Obviously there would be issues, if for example you encrypted the already encrypted or decrypted the already decrypted.

As stated a DAO function could then utilise the above to encrypt or not encrypt when inserting, so the @Dao annotated interface could include:-

@Dao
interface DBEntityDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(dbEntity: DBEntity)

    fun insertAndEncrypt(dbEntity: DBEntity) {
        dbEntity.encryptData()
        insert(dbEntity)
    }

}

Putting this into action ( note .allowMainThreadQueries has been utilised for brevity and convenience ), the following is coded in an activity:-

    db = TheDatabase.getInstance(this)
    dao = db.getDBEntityDao()

    val d1 = DBEntity(0,"Rumplestiltskin",EncryptionType.PLAIN_TEXT)
    val d2 = DBEntity(0,"Rumplestiltskin",EncryptionType.ENCRYPTED)
    dao.insert(d1)
    dao.insert(d2)
    dao.insertAndEncrypt(d1)
    dao.insertAndEncrypt(d2)

The resultant data, view via App Inspection:-

在此处输入图像描述

As can be seen:-

  1. The first two rows have been inserted without encryption using the convenience @Insert annotated insert function.
  2. The 3rd row was inserted with encryption, ie using the insertAndEncrypt function, BUT due to the state of the encryptionType field (PLAIN_TYPE) the data was not encrypted.
  3. The 4th row has been encrypted as the encryptionType is ENCRYPTED and the insertAndEncrypt function was used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM