|
|
@ -124,14 +124,14 @@ const NSUInteger kSqliteHeaderLength = 32;
|
|
|
|
OWSAssert(headerData.length >= kSQLCipherSaltLength);
|
|
|
|
OWSAssert(headerData.length >= kSQLCipherSaltLength);
|
|
|
|
sqlCipherSaltData = [headerData subdataWithRange:NSMakeRange(0, kSQLCipherSaltLength)];
|
|
|
|
sqlCipherSaltData = [headerData subdataWithRange:NSMakeRange(0, kSQLCipherSaltLength)];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ sqlCipherSaltData: %@", self.logTag, sqlCipherSaltData.hexadecimalString);
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure we successfully persist the salt (persumably in the keychain) before
|
|
|
|
// Make sure we successfully persist the salt (persumably in the keychain) before
|
|
|
|
// proceeding with the database conversion or we could leave the app in an
|
|
|
|
// proceeding with the database conversion or we could leave the app in an
|
|
|
|
// unrecoverable state.
|
|
|
|
// unrecoverable state.
|
|
|
|
saltBlock(sqlCipherSaltData);
|
|
|
|
saltBlock(sqlCipherSaltData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Write salt to keychain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Hello Matthew,
|
|
|
|
// Hello Matthew,
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// I hope you're doing well. We've just pushed some changes out to the SQLCipher prerelease branch on GitHub that
|
|
|
|
// I hope you're doing well. We've just pushed some changes out to the SQLCipher prerelease branch on GitHub that
|
|
|
@ -283,6 +283,43 @@ const NSUInteger kSqliteHeaderLength = 32;
|
|
|
|
// BEGIN SQLCipher migration
|
|
|
|
// BEGIN SQLCipher migration
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
// We can obtain the database salt in two ways: by reading the first 16 bytes of the encrypted
|
|
|
|
|
|
|
|
// header OR by using "PRAGMA cipher_salt". In DEBUG builds, we verify that these two values
|
|
|
|
|
|
|
|
// match.
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sqlite3_stmt *statement;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *stmt = "PRAGMA cipher_salt;";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status = sqlite3_prepare_v2(db, stmt, (int)strlen(stmt) + 1, &statement, NULL);
|
|
|
|
|
|
|
|
if (status != SQLITE_OK) {
|
|
|
|
|
|
|
|
DDLogError(@"%@ Error extracting database salt: %d, error: %s", self.logTag, status, sqlite3_errmsg(db));
|
|
|
|
|
|
|
|
return OWSErrorWithCodeDescription(
|
|
|
|
|
|
|
|
OWSErrorCodeDatabaseConversionFatalError, @"Error extracting database salt");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status = sqlite3_step(statement);
|
|
|
|
|
|
|
|
if (status != SQLITE_ROW) {
|
|
|
|
|
|
|
|
DDLogError(@"%@ Missing database salt: %d, error: %s", self.logTag, status, sqlite3_errmsg(db));
|
|
|
|
|
|
|
|
return OWSErrorWithCodeDescription(OWSErrorCodeDatabaseConversionFatalError, @"Missing database salt");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const unsigned char *valueBytes = sqlite3_column_text(statement, 0);
|
|
|
|
|
|
|
|
int valueLength = sqlite3_column_bytes(statement, 0);
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ value: %d %d", self.logTag, valueLength, valueBytes != NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NSString *saltString =
|
|
|
|
|
|
|
|
[[NSString alloc] initWithBytes:valueBytes length:valueLength encoding:NSUTF8StringEncoding];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sqlite3_finalize(statement);
|
|
|
|
|
|
|
|
statement = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ saltString: %@", self.logTag, saltString);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OWSAssert([sqlCipherSaltData.hexadecimalString isEqualToString:saltString]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|