diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 6ecf5c0c1..ee6035b8f 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -452,8 +452,10 @@ static NSTimeInterval launchStartedAt; return YES; }; + YapDatabaseOptions *dbOptions = [OWSStorage defaultDatabaseOptions]; error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:dbOptions recordSaltBlock:recordSaltBlock]; if (!error) { [OWSStorage removeLegacyPassphrase]; diff --git a/Signal/test/util/OWSDatabaseConverterTest.m b/Signal/test/util/OWSDatabaseConverterTest.m index f44603e46..c55c3589a 100644 --- a/Signal/test/util/OWSDatabaseConverterTest.m +++ b/Signal/test/util/OWSDatabaseConverterTest.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import "SignalBaseTest.h" @@ -107,6 +107,7 @@ NS_ASSUME_NONNULL_BEGIN }; options.cipherUnencryptedHeaderLength = kSqliteHeaderLength; } + options.legacyCipherCompatibilityVersion = 3; OWSAssertDebug(options.cipherDefaultkdfIterNumber == 0); OWSAssertDebug(options.kdfIterNumber == 0); @@ -323,6 +324,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:OWSStorage.defaultDatabaseOptions recordSaltBlock:recordSaltBlock]; if (error) { OWSLogError(@"error: %@", error); @@ -364,6 +366,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:OWSStorage.defaultDatabaseOptions recordSaltBlock:recordSaltBlock]; if (error) { OWSLogError(@"error: %@", error); @@ -404,6 +407,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:OWSStorage.defaultDatabaseOptions recordSaltBlock:recordSaltBlock]; XCTAssertNotNil(error); @@ -456,6 +460,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:OWSStorage.defaultDatabaseOptions recordSaltBlock:recordSaltBlock]; if (error) { OWSLogError(@"error: %@", error); @@ -499,6 +504,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:OWSStorage.defaultDatabaseOptions recordSaltBlock:recordSaltBlock]; if (error) { OWSLogError(@"error: %@", error); @@ -532,6 +538,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath databasePassword:databasePassword + options:OWSStorage.defaultDatabaseOptions recordSaltBlock:recordSaltBlock]; if (error) { OWSLogError(@"error: %@", error); diff --git a/SignalServiceKit/src/Storage/OWSStorage.h b/SignalServiceKit/src/Storage/OWSStorage.h index 199421c05..386794369 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.h +++ b/SignalServiceKit/src/Storage/OWSStorage.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import @@ -69,6 +69,8 @@ typedef void (^OWSStorageMigrationBlock)(void); - (YapDatabaseConnection *)newDatabaseConnection; ++ (YapDatabaseOptions *)defaultDatabaseOptions; + #pragma mark - Extension Registration + (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName; diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index 10ef32f2f..8399bdf28 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -410,27 +410,11 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return OWSPrimaryStorage.sharedManager.areAllRegistrationsComplete; } -- (BOOL)tryToLoadDatabase ++ (YapDatabaseOptions *)defaultDatabaseOptions { - __weak OWSStorage *weakSelf = self; - YapDatabaseOptions *options = [[YapDatabaseOptions alloc] init]; options.corruptAction = YapDatabaseCorruptAction_Fail; options.enableMultiProcessSupport = YES; - options.cipherKeySpecBlock = ^{ - // NOTE: It's critical that we don't capture a reference to self - // (e.g. by using OWSAssertDebug()) or this database will contain a - // circular reference and will leak. - OWSStorage *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); - - // Rather than compute this once and capture the value of the key - // in the closure, we prefer to fetch the key from the keychain multiple times - // in order to keep the key out of application memory. - NSData *databaseKeySpec = [strongSelf databaseKeySpec]; - OWSCAssertDebug(databaseKeySpec.length == kSQLCipherKeySpecLength); - return databaseKeySpec; - }; // We leave a portion of the header decrypted so that iOS will recognize the file // as a SQLite database. Otherwise, because the database lives in a shared data container, @@ -452,6 +436,28 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ OWSAssertDebug(options.pragmaJournalSizeLimit == 0); OWSAssertDebug(options.pragmaMMapSize == 0); + return options; +} + +- (BOOL)tryToLoadDatabase +{ + __weak OWSStorage *weakSelf = self; + YapDatabaseOptions *options = [self.class defaultDatabaseOptions]; + options.cipherKeySpecBlock = ^{ + // NOTE: It's critical that we don't capture a reference to self + // (e.g. by using OWSAssertDebug()) or this database will contain a + // circular reference and will leak. + OWSStorage *strongSelf = weakSelf; + OWSCAssertDebug(strongSelf); + + // Rather than compute this once and capture the value of the key + // in the closure, we prefer to fetch the key from the keychain multiple times + // in order to keep the key out of application memory. + NSData *databaseKeySpec = [strongSelf databaseKeySpec]; + OWSCAssertDebug(databaseKeySpec.length == kSQLCipherKeySpecLength); + return databaseKeySpec; + }; + // Sanity checking elsewhere asserts we should only regenerate key specs when // there is no existing database, so rather than lazily generate in the cipherKeySpecBlock // we must ensure the keyspec exists before we create the database.