AppreciateIt
AppreciateIt

Reputation: 706

Is it possible to use a pre-populated Encrypted Realm file without explicitly stating the key?

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.

Upvotes: 2

Views: 567

Answers (1)

TiM
TiM

Reputation: 15991

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! :)

Upvotes: 2

Related Questions