Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to open a realm at path [...] Invalid mnemonic #6047

Closed
Fab1n opened this issue Dec 21, 2018 · 4 comments
Closed

Unable to open a realm at path [...] Invalid mnemonic #6047

Fab1n opened this issue Dec 21, 2018 · 4 comments
Assignees

Comments

@Fab1n
Copy link

Fab1n commented Dec 21, 2018

Recently we noticed an unknown realm error when trying to read schemaVersionAtURL with a wrong key on an encrypted database that was previously copied with writeCopy.

After writeCopy and accessing that Realm either through schemaVersionAtURL or through Realm(config...) we get an error with error code 2 and in the description you read Invalid mnemonic [...].

We currently don't know any other scenario in which this error pops up, but we noticed it kind of luckily because schemaVersionAtURL with a wrong password now throws with an error code 2 instead of code 1.

My questions are:

  • after writeCopy and connecting to the new copy but with a wrong key what should be the expected error?
  • can you reproduce the issue yourself and then also with my code snippets below?

How should we check for a wrong password in the future?
Currently for normal unlocking scenarios we do it with
case let e as NSError where e.code == RLMError.fileAccess.rawValue:
which is in fact error code 2.

But up until now we used catch let e as NSError where e.domain == "io.realm" && e.code == 1 when calling schemaVersionAtURL.

What are your suggestions? I am open to adapt our code to be consistent with your API.

Thank you very much in advance for your help!

Goals

With schemaVersionAtURL up until now we checked a DB if the password the user entered was valid. If not we expected to return an error with domain == "io.realm" and code == 1.
In that case we knew, the entered password was wrong.

All other errors are handled differently. We just wanted to know if the entered password was wrong.

Now the error code is 2, which should be fine also, we just have to update our code checking to check for code 2.
The problem is the error description, the message does say that there is a problem, but I cannot relate it to being a 'wrong password' error.

Expected Results

When trying to read the schema version with a wrong encryption key we expect, like it was previously the case, the error domain == "io.realm" and code == 1 (I guess it must have been Error Domain=io.realm Code=1 "Encryption key mismatch").

I looked it up, it came from realm-core

Actual Results

Got the following error:

Error Domain=io.realm Code=2 "Unable to open a realm at path '/var/folders/hx/xhr6l9d91y19cmp2gkd_85200000gn/T/888E677E-444D-451F-B8FC-014237B3E47F-5549-00029BB66432BE4E/DF3E1D3A-F415-4A0B-B3FF-F9FB2DC76A0A/db.realm': Invalid mnemonic. top_ref[0]: 0, top_ref[1]: 0, mnemonic: 0 0 0 0, fmt[0]: 0, fmt[1]: 0, flags: 0." UserInfo={Error Code=2, NSFilePath=/var/folders/hx/xhr6l9d91y19cmp2gkd_85200000gn/T/888E677E-444D-451F-B8FC-014237B3E47F-5549-00029BB66432BE4E/DF3E1D3A-F415-4A0B-B3FF-F9FB2DC76A0A/db.realm, Underlying=Invalid mnemonic. top_ref[0]: 0, top_ref[1]: 0, mnemonic: 0 0 0 0, fmt[0]: 0, fmt[1]: 0, flags: 0, NSLocalizedDescription=Unable to open a realm at path '/var/folders/hx/xhr6l9d91y19cmp2gkd_85200000gn/T/888E677E-444D-451F-B8FC-014237B3E47F-5549-00029BB66432BE4E/DF3E1D3A-F415-4A0B-B3FF-F9FB2DC76A0A/db.realm': Invalid mnemonic. top_ref[0]: 0, top_ref[1]: 0, mnemonic: 0 0 0 0, fmt[0]: 0, fmt[1]: 0, flags: 0.}

This also comes from realm-core.

Steps to Reproduce

Run the code samples below.

Code Sample

do {
    var tempUniqueFolder: URL {
        return URL(fileURLWithPath: NSTemporaryDirectory())
            .appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString, isDirectory: true)
            .appendingPathComponent(UUID().uuidString, isDirectory: true)
    }

    let folderURL = tempUniqueFolder
    try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
    let dbURL = folderURL.appendingPathComponent("db.realm")

    let copyFolderURL = tempUniqueFolder
    try FileManager.default.createDirectory(at: copyFolderURL, withIntermediateDirectories: true, attributes: nil)
    let copyDbURL = copyFolderURL.appendingPathComponent("db.realm")


    // Generate a random encryption key
    var key: Data {
        var data = Data(count: 64)
        _ = data.withUnsafeMutableBytes { bytes in
            SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
        }
        return data
    }

    let correctKey = key
    let wrongKey = key

    let config = Realm.Configuration(fileURL: dbURL, encryptionKey: correctKey)
    let realm = try Realm(configuration: config)

    try realm.writeCopy(toFile: copyDbURL, encryptionKey: correctKey)

    // let's check the schema version with the wrong key on the copied db
    let copyVersion = try schemaVersionAtURL(copyDbURL, encryptionKey: wrongKey)
    precondition(copyVersion == 0, "not the expected version")
} catch {
    fatalError("\(error)")
}

But that not only is true for schemaVersionAtURL! Here is a more generalized version, which also throws this error (delete the created temp folder each time you want to run that code else the first Realm(configuration already throws because next time you run the code the key is different):

do {
    var tempUniqueFolder: URL {
        return URL(fileURLWithPath: NSTemporaryDirectory())
            .appendingPathComponent("realmTest", isDirectory: true)
    }

    let folderURL = tempUniqueFolder
    try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
    let dbURL = folderURL.appendingPathComponent("db.realm")

    try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
    let copyDbURL = folderURL.appendingPathComponent("copydb.realm")


    // Generate a random encryption key
    var key: Data {
        var data = Data(count: 64)
        _ = data.withUnsafeMutableBytes { bytes in
            SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
        }
        return data
    }

    let correctKey = key
    let wrongKey = key

    let config = Realm.Configuration(fileURL: dbURL, encryptionKey: correctKey)
    let realm = try Realm(configuration: config)

    try realm.writeCopy(toFile: copyDbURL, encryptionKey: correctKey)

    // let's check the schema version with the wrong key on the copied db
    _ = try Realm(configuration: Realm.Configuration(fileURL: copyDbURL, encryptionKey: wrongKey))
} catch {
    fatalError("\(error)")
}

Version of Realm and Tooling

Realm framework version: 3.12.0

Realm Object Server version: The one that comes with 3.12.0 (we don't use sync)

Xcode version: 10.1 (10B61)

iOS/OSX version: 10.14.1 (18B75)

Dependency manager + version: Cocoapods 1.5.3

@Fab1n
Copy link
Author

Fab1n commented Dec 21, 2018

I found the following tickets that could relate to this issue:
realm-cocoa: #5896
realm-core: realm/realm-core#3134
realm-java: realm/realm-java#6257

@leemaguire
Copy link
Contributor

Could you upgrade to the latest version of Realm and see if this solves your issue? Thanks.

@Fab1n
Copy link
Author

Fab1n commented Jul 3, 2020

Did you test it with the provided code with the new version?
In production currently we cannot upgrade so I'd need to test it with the code above, too.

@leemaguire
Copy link
Contributor

Closing because recent Core versions give a more descriptive error when decrypting a copy with the wrong key. You should now expect:

Error Domain=io.realm Code=2 "Unable to open a realm at path '/.../db.realm': Realm file decryption failed Path

@sync-by-unito sync-by-unito bot closed this as completed Oct 18, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants