← Blog Home

Securing Your Core Data with Transformable Attributes

3 Replies.

In order to store private data in an iOS Core Data database, there are several methods available for encryption, including:

However, neither of these options is sufficient for if you need to use multiple encryption keys, encrypt only certain attributes, or preserve decrypted data while the device is locked.

Encryption Transformer class

Instead, it’s fairly simple and straight-forward to perform lazy decryption on only certain database fields using the special Transformable Core Data attribute type. Transformable attributes are configured with an NSValueTransformer subclass that you write that specifies:

  • a method for converting one object into another
  • an optional method for reversing that process (and whether reversing is supported)
  • the class of an object after transformation

Here’s an example class that converts from a decrypted NSData object to an encrypted one. It relies on a key method to get the encryption key, and a couple NSData category methods that perform AES-256 encryption and decryption.

The key method might get the secret key from any number of places, such as a password requested at login and stored in the app delegate. I’ll touch on the NSData category methods that actually perform the encryption in a little bit.

This encryption class can then easily be subclassed to handle different data types, like strings, dates, numbers, etc. Here’s an example string encryption class that converts between NSString and NSData in order to use its parent class transformation methods.

Once these classes are set up, the Core Data model editor lets you assign an entity attribute type of Transformable and a name of the NSValueTransformer class, such as StringEncryptionTransformer.

Core Data model editor in Xcode showing an entity’s Transformable attribute.

Now, these attributes can be written to in code just like any other (e.g. clark.secretIdentity = @"superman"), but when they are persisted to the underlying SQLite database (or other sort of data store), the appropriate NSValueTransformer class will be called to encrypt the values before writing them to the data store.

Likewise, at the time a persisted object is read from the data store, the NSValueTransformer class will decrypt it. Encryption and decryption is thus lazy and only performed when an object is used or updated — no need to decrypt an entire file or database during app startup.

AES-256 encryption category

There are a number of example classes that make performing AES-256 encryption as simple as shown above, such as Jim Dovey’s NSData+CommonCrypto category and this unattributed snippet.  The better ones use encryption libraries provided by Apple, which may (or may not, IANAL) mean that you don’t need a CCATS form for app submission.

However, one major caveat to encrypting attributes individually is that patterns from short, repeated values will naturally rise.  If you are encrypting only a couple different possible values for an attribute (e.g. “superhero” and “evildoer”), simple encryption using the same key will result in only two encrypted values.  That is, for the key “top secret“, the value “Superman” will always encrypt to “?b64JzJ4aC0IhKaf7xeTWaglC6L/3VFxwA5XVrfDRntxebO4rFUSdNNrzfVFIU3y
ZH0F?64b
” (Javascrypt is a handy online tool for encryption).

Enter the initialization vector (IV), which like the salt for a password helps hide patterns by randomizing encryption input.  The IV should be:

  1. a random number, for example the result of arc4random()
  2. different for every attribute, or at least every entity
  3. stored alongside the encrypted value, since the same IV used for encryption is necessary for decryption
  4. public, that is it need not (and should not) be encrypted

Unfortunately, many example code snippets that call CCCrypt (including one linked above) leave the initialization vector parameter as simply:

NULL /* initialization vector (optional) */,

Rather than follow suit, it’s simple to update our EncryptionTransformer to generate a IV and prepend it to the encrypted data:

Now, every time an attribute value is saved, its encrypted version includes an extra stage of randomization that prevents comparisons between different attributes encrypted with the same key.

Thus, with fairly minimal code that ensures resilient encryption, we have an easy way to store private information in Core Data attributes with as many different keys as necessary.

3 thoughts on “Securing Your Core Data with Transformable Attributes”.

  • Briggs says:

    I implemented my solution in the same vain but I ran into a HUGE performance problem. I had too many transformable attributes that needed to be encrypted and it just won’t work. What did you do to get around this problem? I have about 7 transformable attributes on only 70+ records and it’s just way to slow (orders of magnitude slower) . Did you run into any performance problems? If so, what did you do about it?

  • Noah says:

    Sorry for the late reply here.

    The encryption transformation hasn’t caused any significant performance issues. We have about 16 transformable attributes in one model that has thousands or tens of thousands of rows.

    SQL queries are not affected by the transformations, since those transformations occur only when the model objects are loaded or persisted. We don’t query on any of the encrypted values (which would surely be quite slow however it was implemented).

    Our data is typically loaded from the SQL store in batches – either a few dozen at a time when displaying items in a table using NSFetchedResultsController, or a few hundred at a time for a background syncing mechanism.

    Let me know if you’re still having performance issues, and if so under what conditions and functions.

  • Leave a Reply

    Follow Art & Logic on Twitter

    Follow Our Blog via RSS

    RSS

    Connect Socially

    A&L on Facebook

    A&L on Google+

    Home   About   Blog   Careers   Contact

    %d bloggers like this: