CoreData: ValueTransformer functions are not called

641 views Asked by At

I'm storing some key/value-pairs as Strings in CoreData which - in a newer version - should now be encrypted. To not alone relying on Apples DataProtection I now want to encrypt the data before storing with RNCryptor and with the help of the ValueTransformer class.

However, the transform-functions are not called, neither debug-outputs nor breakpoints are triggered. The strings are now stored as data objects, but can be read in plain text in binary representation - so they are obviously not encrypted.

DB Browser

Here is what I changed:

  • Added and activated a new migration/database scheme
  • Changed key and value column from Type String to Transformable
  • Set the Value Transformer to »EncryptedStringTransformer« and the Custom Class to »String«

Data model

  • and finally I added a file Encryption.swift with the following implementation:
import Foundation
import RNCryptor

class EncryptedStringTransformer : ValueTransformer {
    let password = "SuperSecurePassword"

    override class func allowsReverseTransformation() -> Bool{
        return true
    }

    func transformedValue(value: String?) -> NSData? {

        guard let data = value else {
            return nil
        }
        let encryptData = Data(data.utf8)
        let ciphertext = RNCryptor.encrypt(data: encryptData, withPassword: password)
        return ciphertext as NSData
    }

    func reverseTransformedValue(value: NSData?) -> String? {
        guard value != nil else {
            return "nil"
        }
        do {
            let originalData = try RNCryptor.decrypt(data: (value! as Data), withPassword: password)
            return String(data: originalData, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!

        } catch {
            print(error)
            return "nil"
        }
    }
}

So, the app continues to work flawlessly, and all database objects can be stored and retrieved (with the difference that they are now stored as a Data object rather than a String). I'm checking the SQLite database directly with »DB Browser for SQLite«.

The expected behavior would be encrypted entries in CoreData. Can someone tell me what I am missing? Some tutorials I found don't do any additional implementations and the few articles here on StackOverflow aren't helping either with this issue.

I tried to change the output data from the transform-functions from Data to NSData, with no result. Am I missing something, so that the ValueTransformer is actually called? Any hint would be highly appreciated!

1

There are 1 answers

4
Rob Napier On BEST ANSWER

You haven't overridden the correct methods of ValueTransformer. Your methods are:

func transformedValue(value: String?) -> NSData?
func reverseTransformedValue(value: NSData?) -> String?

The correct methods are:

func transformedValue(_ value: Any?) -> Any?
func reverseTransformedValue(_ value: Any?) -> Any?

The big hint that you're implementing the wrong methods is that you didn't need to add the override keyword.

BTW, this expression:

encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!

can be replaced with:

encoding: .uf8

It would also likely be better to replace your return "nil" with return nil; it's a String?, so it can be nil if things go wrong.