2

I want to use an encrypted Realm database that is pre-populated with data. The problem is that I generate and store the key on the device locally, and so as you can imagine, the key doesn't work the moment I bring that realm file to another device. This is how I generate the encryption key.

func getKey() -> NSData {
        // Identifier for our keychain entry - should be unique for your application
        let keychainIdentifier = "io.Realm.Test12345"
        let keychainIdentifierData = keychainIdentifier.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!

        // First check in the keychain for an existing key
        var query: [NSString: AnyObject] = [
            kSecClass: kSecClassKey,
            kSecAttrApplicationTag: keychainIdentifierData,
            kSecAttrKeySizeInBits: 512,
            kSecReturnData: true
        ]

        // To avoid Swift optimization bug, should use withUnsafeMutablePointer() function to retrieve the keychain item
        // See also: http://stackoverflow.com/questions/24145838/querying-ios-keychain-using-swift/27721328#27721328
        var dataTypeRef: AnyObject?
        var status = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query, UnsafeMutablePointer($0)) }
        if status == errSecSuccess {
            return dataTypeRef as! NSData
        }

        // No pre-existing key from this application, so generate a new one
        let keyData = NSMutableData(length: 64)!
        SecRandomCopyBytes(kSecRandomDefault, 64, UnsafeMutablePointer<UInt8>(keyData.mutableBytes))

        // Store the key in the keychain
        query = [
            kSecClass: kSecClassKey,
            kSecAttrApplicationTag: keychainIdentifierData,
            kSecAttrKeySizeInBits: 512,
            kSecValueData: keyData
        ]

        status = SecItemAdd(query, nil)
        assert(status == errSecSuccess, "Failed to insert the new key in the keychain")

        return keyData
    }

Is there any way I could do this without explicitly stating a key that can open the file on all devices? I guess I could generate the database line-by-line in the code, and ensure it is encrypted from the start, however it isn't as convenient.

AppreciateIt
  • 696
  • 2
  • 8
  • 23
  • Did you end up just storing an encryption key in the app? – SimplyLearning Feb 07 '17 at 21:14
  • @SimplyLearning I ended up just using my server to query results, using rate limiting so that not all results can just be fetched so easily. That was what worked in my use case. – AppreciateIt Feb 07 '17 at 21:18
  • Ah so you ended up just going with your server and scraped Realm offline completely? I'm leveraging Realm and wanted to encrypt my DB on app download, so was thinking of just hardcoding the key in a Helper file – SimplyLearning Feb 07 '17 at 21:20
  • @SimplyLearning I still use realm for my app's local data, but I ditched the idea of shipping the database encrypted with the app, since I had to regularly update the content. I think that method is fine, but keep in mind that a tool like cycript could probably get the key if the usr was persistent enough. – AppreciateIt Feb 07 '17 at 21:31
  • Gotcha thank. Looking at it some more, really seems like it's near impossible to keep data safe in iOS. One more question for you though, when you say you ditched encryption because you "had to regularly update the content"...this is in respect to if the user had his/her own key on their own device correct? If using a hardcoded key for all users, then you wouldn't have any issues updating the content? Or am I missing something – SimplyLearning Feb 07 '17 at 21:53
  • 1
    I just mean't that the database had to have specific changes made to it since the data I was shipping with my app would need to be updated from time to time and I would end up doing it with every app update, which was just annoying and its much easier to just add the rows to the database hooked up to my server. Nothing to do with the key, although the whole key situation didn't help keep things simpler. There is basically no way to keep this stuff secure 100%, if you want to protect your data as much as possible, I would just code the server to ensure protections. – AppreciateIt Feb 07 '17 at 21:58

1 Answers1

2

It's not possible to encrypt a Realm without explicitly specifying an encryption key. If you do not supply an encryption key at the time of the Realm file's creation, it will be created un-encrypted, and if you try and use a different key after that, the file will refuse to open.

It's possible to change the encryption key of a Realm file by saving a copy with a new key. Something you could potentially do is provide your encrypted Realm with an obfuscated encryption key along with the app, and on the first time of the app's launch, it creates a local copy of that Realm file, with a device-generated encryption key that becomes the main Realm after that point.

If you want extra security and don't want to bake an initial encryption key into the app, you could also consider including the encrypted Realm file along with the app, but you need to perform a secure web request to download the encryption key to open it.

I hope this gave you some ideas! :)

TiM
  • 15,812
  • 4
  • 51
  • 79