Key material changes
- For new installs, generate raw key-spec rather than derive it - Adapt to separated concerns of the key derivation migration from the unencrypted header migration - Reduce number of places where we delete/generate keying information - Only store relevant keying material // FREEBIE
This commit is contained in:
parent
938b9c85b8
commit
426c9baa16
10
Podfile.lock
10
Podfile.lock
|
@ -141,7 +141,7 @@ DEPENDENCIES:
|
|||
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
|
||||
- SQLCipher (from `https://github.com/sqlcipher/sqlcipher.git`, commit `d5c2bec`)
|
||||
- SSZipArchive
|
||||
- YapDatabase/SQLCipher (from `../YapDatabase`)
|
||||
- YapDatabase/SQLCipher (from `https://github.com/WhisperSystems/YapDatabase.git`, branch `release/unencryptedHeaders`)
|
||||
- YYImage
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
|
@ -167,7 +167,8 @@ EXTERNAL SOURCES:
|
|||
:commit: d5c2bec
|
||||
:git: https://github.com/sqlcipher/sqlcipher.git
|
||||
YapDatabase:
|
||||
:path: ../YapDatabase
|
||||
:branch: release/unencryptedHeaders
|
||||
:git: https://github.com/WhisperSystems/YapDatabase.git
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
AxolotlKit:
|
||||
|
@ -191,6 +192,9 @@ CHECKOUT OPTIONS:
|
|||
SQLCipher:
|
||||
:commit: d5c2bec
|
||||
:git: https://github.com/sqlcipher/sqlcipher.git
|
||||
YapDatabase:
|
||||
:commit: a88958a8db03a050650a495394e1817e48d99f4b
|
||||
:git: https://github.com/WhisperSystems/YapDatabase.git
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
|
||||
|
@ -217,6 +221,6 @@ SPEC CHECKSUMS:
|
|||
YapDatabase: 299a32de9d350d37a9ac5b0532609d87d5d2a5de
|
||||
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
|
||||
|
||||
PODFILE CHECKSUM: bb32efdc239e2a93d6304d25de33a25dc4cdbab2
|
||||
PODFILE CHECKSUM: 0d804514eb2db34b9874b653e543255d8c2f5751
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
|
|
|
@ -257,7 +257,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
}
|
||||
|
||||
NSError *error;
|
||||
NSData *_Nullable databasePassword = [OWSStorage tryToLoadDatabasePassword:&error];
|
||||
NSData *_Nullable databasePassword = [OWSStorage tryToLoadDatabaseLegacyPassphrase:&error];
|
||||
if (!databasePassword || error) {
|
||||
return (error
|
||||
?: OWSErrorWithCodeDescription(
|
||||
|
@ -266,11 +266,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
YapDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) {
|
||||
DDLogVerbose(@"%@ saltData: %@", self.logTag, saltData.hexadecimalString);
|
||||
[OWSStorage storeDatabaseSalt:saltData];
|
||||
};
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
DDLogVerbose(@"%@ keySpecData: %@", self.logTag, keySpecData.hexadecimalString);
|
||||
[OWSStorage storeDatabaseKeySpec:keySpecData];
|
||||
|
||||
// Derive and store the raw cipher key spec, to avoid the ongoing tax of future KDF
|
||||
NSData *keySpecData =
|
||||
[YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData];
|
||||
[OWSStorage storeDatabaseCipherKeySpec:keySpecData];
|
||||
};
|
||||
|
||||
return [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
|
|
|
@ -298,19 +298,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]);
|
||||
|
||||
__block NSData *_Nullable databaseSalt = nil;
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) {
|
||||
OWSAssert(!databaseSalt);
|
||||
OWSAssert(saltData);
|
||||
|
||||
databaseSalt = saltData;
|
||||
databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData];
|
||||
};
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
OWSAssert(!databaseKeySpec);
|
||||
OWSAssert(keySpecData);
|
||||
|
||||
databaseKeySpec = keySpecData;
|
||||
};
|
||||
NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
recordSaltBlock:recordSaltBlock];
|
||||
|
@ -339,19 +335,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]);
|
||||
|
||||
__block NSData *_Nullable databaseSalt = nil;
|
||||
YapDatabaseSaltBlock saltBlock = ^(NSData *saltData) {
|
||||
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) {
|
||||
OWSAssert(!databaseSalt);
|
||||
OWSAssert(saltData);
|
||||
|
||||
databaseSalt = saltData;
|
||||
databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData];
|
||||
};
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
OWSAssert(!databaseKeySpec);
|
||||
OWSAssert(keySpecData);
|
||||
|
||||
databaseKeySpec = keySpecData;
|
||||
};
|
||||
|
||||
NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
recordSaltBlock:recordSaltBlock];
|
||||
|
@ -398,23 +391,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]);
|
||||
|
||||
__block NSData *_Nullable databaseSalt = nil;
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) {
|
||||
OWSAssert(!databaseSalt);
|
||||
OWSAssert(saltData);
|
||||
|
||||
databaseSalt = saltData;
|
||||
databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData];
|
||||
};
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
OWSAssert(!databaseKeySpec);
|
||||
OWSAssert(keySpecData);
|
||||
|
||||
databaseKeySpec = keySpecData;
|
||||
};
|
||||
|
||||
|
||||
NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
saltBlock:saltBlock
|
||||
keySpecBlock:keySpecBlock];
|
||||
recordSaltBlock:recordSaltBlock];
|
||||
if (error) {
|
||||
DDLogError(@"%s error: %@", __PRETTY_FUNCTION__, error);
|
||||
}
|
||||
|
@ -428,9 +417,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// Verify the contents of the unconverted database.
|
||||
__block BOOL isValid = NO;
|
||||
[self openYapDatabase:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
databasePassword:nil
|
||||
databaseSalt:nil
|
||||
databaseKeySpec:nil
|
||||
databaseKeySpec:databaseKeySpec
|
||||
databaseBlock:^(YapDatabase *database) {
|
||||
YapDatabaseConnection *dbConnection = database.newConnection;
|
||||
isValid = [dbConnection numberOfKeysInCollection:@"test_collection_name"] == kItemCount;
|
||||
|
@ -453,11 +442,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
XCTFail(@"%s No conversion should be necessary", __PRETTY_FUNCTION__);
|
||||
};
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
OWSAssert(keySpecData);
|
||||
|
||||
XCTFail(@"%s No conversion should be necessary", __PRETTY_FUNCTION__);
|
||||
};
|
||||
|
||||
NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
|
@ -490,11 +474,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
XCTFail(@"%s No conversion should be necessary", __PRETTY_FUNCTION__);
|
||||
};
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
OWSAssert(keySpecData);
|
||||
|
||||
XCTFail(@"%s No conversion should be necessary", __PRETTY_FUNCTION__);
|
||||
};
|
||||
|
||||
NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
|
|
|
@ -75,13 +75,10 @@ extern NSString *const StorageIsReadyNotification;
|
|||
*/
|
||||
+ (BOOL)isDatabasePasswordAccessible;
|
||||
|
||||
+ (nullable NSData *)tryToLoadDatabasePassword:(NSError **)errorHandle;
|
||||
+ (nullable NSData *)tryToLoadDatabaseLegacyPassphrase:(NSError **)errorHandle;
|
||||
|
||||
+ (nullable NSData *)tryToLoadDatabaseSalt:(NSError **)errorHandle;
|
||||
+ (void)storeDatabaseSalt:(NSData *)saltData;
|
||||
+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData;
|
||||
|
||||
+ (nullable NSData *)tryToLoadDatabaseKeySpec:(NSError **)errorHandle;
|
||||
+ (void)storeDatabaseKeySpec:(NSData *)keySpecData;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -27,9 +27,8 @@ NSString *const OWSStorageExceptionName_NoDatabase = @"OWSStorageExceptionName_N
|
|||
NSString *const OWSResetStorageNotification = @"OWSResetStorageNotification";
|
||||
|
||||
static NSString *keychainService = @"TSKeyChainService";
|
||||
static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
static NSString *keychainDBSalt = @"OWSDatabaseSalt";
|
||||
static NSString *keychainDBKeySpec = @"OWSDatabaseKeySpec";
|
||||
static NSString *keychainDBLegacyPassphrase = @"TSDatabasePass";
|
||||
static NSString *keychainDBCipherKeySpec = @"OWSDatabaseCipherKeySpec";
|
||||
|
||||
const NSUInteger kDatabasePasswordLength = 30;
|
||||
|
||||
|
@ -381,17 +380,9 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
- (BOOL)tryToLoadDatabase
|
||||
{
|
||||
// We determine the database password, salt and key spec first, since a side effect of
|
||||
// We determine the database key spec first, since a side effect of
|
||||
// this can be deleting any existing database file (if we're recovering
|
||||
// from a corrupt keychain).
|
||||
//
|
||||
// Although we don't use databasePassword or databaseSalt in this method,
|
||||
// we use their accessors to ensure that all three exist in the keychain
|
||||
// and can be loaded or that we reset the database & keychain.
|
||||
// NSData *databasePassword = [self databasePassword];
|
||||
// OWSAssert(databasePassword.length > 0);
|
||||
// NSData *databaseSalt = [self databaseSalt];
|
||||
// OWSAssert(databaseSalt.length > 0);
|
||||
NSData *databaseKeySpec = [self databaseKeySpec];
|
||||
OWSAssert(databaseKeySpec.length == kSQLCipherKeySpecLength);
|
||||
|
||||
|
@ -401,6 +392,11 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
options.cipherKeySpecBlock = ^{
|
||||
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,
|
||||
// and our usage of sqlite's write-ahead logging retains a lock on the database, the OS
|
||||
// would kill the app/share extension as soon as it is backgrounded.
|
||||
options.cipherUnencryptedHeaderLength = kSqliteHeaderLength;
|
||||
|
||||
// If any of these asserts fails, we need to verify and update
|
||||
|
@ -506,7 +502,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
// This might be redundant but in the spirit of thoroughness...
|
||||
[self deleteDatabaseFiles];
|
||||
|
||||
[self deletePasswordFromKeychain];
|
||||
[self deleteDBKeys];
|
||||
|
||||
if (CurrentAppContext().isMainApp) {
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
|
@ -528,116 +524,41 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
+ (BOOL)isDatabasePasswordAccessible
|
||||
{
|
||||
[SAMKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly];
|
||||
NSError *error;
|
||||
NSString *dbPassword = [SAMKeychain passwordForService:keychainService account:keychainDBPassAccount error:&error];
|
||||
NSData *cipherKeySpec = [self tryToLoadDatabaseCipherKeySpec:&error];
|
||||
|
||||
if (dbPassword && !error) {
|
||||
if (cipherKeySpec && !error) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
DDLogWarn(@"Database password couldn't be accessed: %@", error.localizedDescription);
|
||||
DDLogWarn(@"Database key couldn't be accessed: %@", error.localizedDescription);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle
|
||||
+ (nullable NSData *)tryToLoadDatabaseLegacyPassphrase:(NSError **)errorHandle
|
||||
{
|
||||
OWSAssert(keychainKey.length > 0);
|
||||
OWSAssert(errorHandle);
|
||||
|
||||
[SAMKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly];
|
||||
|
||||
return [SAMKeychain passwordDataForService:keychainService account:keychainKey error:errorHandle];
|
||||
return [self tryToLoadKeyChainValue:keychainDBLegacyPassphrase errorHandle:errorHandle];
|
||||
}
|
||||
|
||||
+ (nullable NSData *)tryToLoadDatabasePassword:(NSError **)errorHandle
|
||||
+ (nullable NSData *)tryToLoadDatabaseCipherKeySpec:(NSError **)errorHandle
|
||||
{
|
||||
return [self tryToLoadKeyChainValue:keychainDBPassAccount errorHandle:errorHandle];
|
||||
return [self tryToLoadKeyChainValue:keychainDBCipherKeySpec errorHandle:errorHandle];
|
||||
}
|
||||
|
||||
+ (nullable NSData *)tryToLoadDatabaseSalt:(NSError **)errorHandle
|
||||
+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData
|
||||
{
|
||||
return [self tryToLoadKeyChainValue:keychainDBSalt errorHandle:errorHandle];
|
||||
}
|
||||
OWSAssert(cipherKeySpecData.length == kSQLCipherKeySpecLength);
|
||||
|
||||
+ (nullable NSData *)tryToLoadDatabaseKeySpec:(NSError **)errorHandle
|
||||
{
|
||||
return [self tryToLoadKeyChainValue:keychainDBKeySpec errorHandle:errorHandle];
|
||||
}
|
||||
|
||||
- (NSData *)databasePassword
|
||||
{
|
||||
return [self loadMetadataOrClearDatabase:^(NSError **_Nullable errorHandle) {
|
||||
return [OWSStorage tryToLoadDatabasePassword:errorHandle];
|
||||
}
|
||||
createDataBlock:^{
|
||||
NSData *passwordData = [self createAndSetNewDatabasePassword];
|
||||
NSData *saltData = [self createAndSetNewDatabaseSalt];
|
||||
NSData *keySpecData = [self createAndSetNewDatabaseKeySpec];
|
||||
|
||||
OWSAssert(passwordData.length > 0);
|
||||
OWSAssert(saltData.length == kSQLCipherSaltLength);
|
||||
OWSAssert(keySpecData.length == kSQLCipherKeySpecLength);
|
||||
|
||||
return passwordData;
|
||||
}
|
||||
label:@"Database password"];
|
||||
}
|
||||
|
||||
- (NSData *)databaseSalt
|
||||
{
|
||||
return [self loadMetadataOrClearDatabase:^(NSError **_Nullable errorHandle) {
|
||||
return [OWSStorage tryToLoadDatabaseSalt:errorHandle];
|
||||
}
|
||||
createDataBlock:^{
|
||||
NSData *passwordData = [self createAndSetNewDatabasePassword];
|
||||
NSData *saltData = [self createAndSetNewDatabaseSalt];
|
||||
NSData *keySpecData = [self createAndSetNewDatabaseKeySpec];
|
||||
|
||||
OWSAssert(passwordData.length > 0);
|
||||
OWSAssert(saltData.length == kSQLCipherSaltLength);
|
||||
OWSAssert(keySpecData.length == kSQLCipherKeySpecLength);
|
||||
|
||||
return saltData;
|
||||
}
|
||||
label:@"Database salt"];
|
||||
[self storeKeyChainValue:cipherKeySpecData keychainKey:keychainDBCipherKeySpec];
|
||||
}
|
||||
|
||||
- (NSData *)databaseKeySpec
|
||||
{
|
||||
// Get or generate salt and cipherKeyData
|
||||
|
||||
return [self loadMetadataOrClearDatabase:^(NSError **_Nullable errorHandle) {
|
||||
return [OWSStorage tryToLoadDatabaseKeySpec:errorHandle];
|
||||
}
|
||||
createDataBlock:^{
|
||||
OWSFail(@"%@ It should never be necessary to generate a random key spec.", self.logTag);
|
||||
|
||||
NSData *passwordData = [self createAndSetNewDatabasePassword];
|
||||
NSData *saltData = [self createAndSetNewDatabaseSalt];
|
||||
NSData *keySpecData = [self createAndSetNewDatabaseKeySpec];
|
||||
|
||||
OWSAssert(passwordData.length > 0);
|
||||
OWSAssert(saltData.length == kSQLCipherSaltLength);
|
||||
OWSAssert(keySpecData.length == kSQLCipherKeySpecLength);
|
||||
|
||||
return keySpecData;
|
||||
}
|
||||
label:@"Database key spec"];
|
||||
}
|
||||
|
||||
- (NSData *)loadMetadataOrClearDatabase:(LoadDatabaseMetadataBlock)loadDataBlock
|
||||
createDataBlock:(CreateDatabaseMetadataBlock)createDataBlock
|
||||
label:(NSString *)label
|
||||
{
|
||||
OWSAssert(loadDataBlock);
|
||||
OWSAssert(createDataBlock);
|
||||
|
||||
NSError *error;
|
||||
NSData *_Nullable data = loadDataBlock(&error);
|
||||
NSData *_Nullable data = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
|
||||
|
||||
if (error) {
|
||||
// Because we use kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
|
||||
|
@ -647,7 +568,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
// process that notification, so we should just terminate by throwing
|
||||
// an uncaught exception.
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"%@ inaccessible. No unlock since device restart? Error: %@", label, error];
|
||||
[NSString stringWithFormat:@"CipherKeySpec inaccessible. No unlock since device restart? Error: %@", error];
|
||||
if (CurrentAppContext().isMainApp) {
|
||||
UIApplicationState applicationState = CurrentAppContext().mainApplicationState;
|
||||
errorDescription =
|
||||
|
@ -661,11 +582,10 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
// TODO: Rather than crash here, we should detect the situation earlier
|
||||
// and exit gracefully - (in the app delegate?). See the `
|
||||
// This is a last ditch effort to avoid blowing away the user's database.
|
||||
[self backgroundedAppDatabasePasswordInaccessibleWithErrorDescription:errorDescription];
|
||||
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:errorDescription];
|
||||
}
|
||||
} else {
|
||||
[self backgroundedAppDatabasePasswordInaccessibleWithErrorDescription:
|
||||
[NSString stringWithFormat:@"%@ inaccessible; not main app.", label]];
|
||||
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible; not main app."];
|
||||
}
|
||||
|
||||
// At this point, either this is a new install so there's no existing password to retrieve
|
||||
|
@ -681,47 +601,14 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
// Try to reset app by deleting database.
|
||||
[OWSStorage resetAllStorage];
|
||||
|
||||
data = createDataBlock();
|
||||
data = [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength];
|
||||
[[self class] storeDatabaseCipherKeySpec:data];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSData *)createAndSetNewDatabasePassword
|
||||
{
|
||||
NSData *password = [[[Randomness generateRandomBytes:kDatabasePasswordLength] base64EncodedString]
|
||||
dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
[OWSStorage storeDatabasePassword:password];
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
- (NSData *)createAndSetNewDatabaseSalt
|
||||
{
|
||||
NSData *saltData = [Randomness generateRandomBytes:(int)kSQLCipherSaltLength];
|
||||
|
||||
[OWSStorage storeDatabaseSalt:saltData];
|
||||
|
||||
return saltData;
|
||||
}
|
||||
|
||||
- (NSData *)createAndSetNewDatabaseKeySpec
|
||||
{
|
||||
NSData *databasePassword = [self databasePassword];
|
||||
OWSAssert(databasePassword.length > 0);
|
||||
NSData *databaseSalt = [self databaseSalt];
|
||||
OWSAssert(databaseSalt.length == kSQLCipherSaltLength);
|
||||
|
||||
NSData *keySpecData = [YapDatabaseCryptoUtils databaseKeySpecForPassword:databasePassword saltData:databaseSalt];
|
||||
OWSAssert(keySpecData.length == kSQLCipherKeySpecLength);
|
||||
|
||||
[OWSStorage storeDatabaseKeySpec:keySpecData];
|
||||
|
||||
return keySpecData;
|
||||
}
|
||||
|
||||
- (void)backgroundedAppDatabasePasswordInaccessibleWithErrorDescription:(NSString *)errorDescription
|
||||
- (void)raiseKeySpecInaccessibleExceptionWithErrorDescription:(NSString *)errorDescription
|
||||
{
|
||||
OWSAssert(CurrentAppContext().isMainApp && CurrentAppContext().isInBackground);
|
||||
|
||||
|
@ -734,11 +621,10 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
OWSRaiseException(OWSStorageExceptionName_DatabasePasswordInaccessibleWhileBackgrounded, @"%@", errorDescription);
|
||||
}
|
||||
|
||||
+ (void)deletePasswordFromKeychain
|
||||
+ (void)deleteDBKeys
|
||||
{
|
||||
[SAMKeychain deletePasswordForService:keychainService account:keychainDBPassAccount];
|
||||
[SAMKeychain deletePasswordForService:keychainService account:keychainDBSalt];
|
||||
[SAMKeychain deletePasswordForService:keychainService account:keychainDBKeySpec];
|
||||
[SAMKeychain deletePasswordForService:keychainService account:keychainDBLegacyPassphrase];
|
||||
[SAMKeychain deletePasswordForService:keychainService account:keychainDBCipherKeySpec];
|
||||
}
|
||||
|
||||
- (unsigned long long)databaseFileSize
|
||||
|
@ -746,6 +632,14 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
return [OWSFileSystem fileSizeOfPath:self.databaseFilePath].unsignedLongLongValue;
|
||||
}
|
||||
|
||||
+ (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle
|
||||
{
|
||||
OWSAssert(keychainKey.length > 0);
|
||||
OWSAssert(errorHandle);
|
||||
|
||||
return [SAMKeychain passwordDataForService:keychainService account:keychainKey error:errorHandle];
|
||||
}
|
||||
|
||||
+ (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey
|
||||
{
|
||||
OWSAssert(keychainKey.length > 0);
|
||||
|
@ -758,8 +652,6 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
OWSFail(@"%@ Could not store database metadata", self.logTag);
|
||||
OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotStoreKeychainValue]);
|
||||
|
||||
[OWSStorage deletePasswordFromKeychain];
|
||||
|
||||
// Sleep to give analytics events time to be delivered.
|
||||
[NSThread sleepForTimeInterval:15.0f];
|
||||
|
||||
|
@ -770,25 +662,6 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
}
|
||||
}
|
||||
|
||||
+ (void)storeDatabasePassword:(NSData *)passwordData
|
||||
{
|
||||
[self storeKeyChainValue:passwordData keychainKey:keychainDBPassAccount];
|
||||
}
|
||||
|
||||
+ (void)storeDatabaseSalt:(NSData *)saltData
|
||||
{
|
||||
OWSAssert(saltData.length == kSQLCipherSaltLength);
|
||||
|
||||
[self storeKeyChainValue:saltData keychainKey:keychainDBSalt];
|
||||
}
|
||||
|
||||
+ (void)storeDatabaseKeySpec:(NSData *)keySpecData
|
||||
{
|
||||
OWSAssert(keySpecData.length == kSQLCipherKeySpecLength);
|
||||
|
||||
[self storeKeyChainValue:keySpecData keychainKey:keychainDBKeySpec];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
Loading…
Reference in New Issue