|
|
|
@ -175,7 +175,7 @@ bool RawDatabase::open(const QString& path, const QString& hexKey)
@@ -175,7 +175,7 @@ bool RawDatabase::open(const QString& path, const QString& hexKey)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!hexKey.isEmpty()) { |
|
|
|
|
if (!openEncryptedDatabaseAtLatestVersion(hexKey)) { |
|
|
|
|
if (!openEncryptedDatabaseAtLatestSupportedVersion(hexKey)) { |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -183,33 +183,29 @@ bool RawDatabase::open(const QString& path, const QString& hexKey)
@@ -183,33 +183,29 @@ bool RawDatabase::open(const QString& path, const QString& hexKey)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool RawDatabase::openEncryptedDatabaseAtLatestVersion(const QString& hexKey) |
|
|
|
|
bool RawDatabase::openEncryptedDatabaseAtLatestSupportedVersion(const QString& hexKey) |
|
|
|
|
{ |
|
|
|
|
// old qTox database are saved with SQLCipher 3.x defaults. New qTox (and for a period during 1.16.3 master) are stored
|
|
|
|
|
// with 4.x defaults. We need to support opening both databases saved with 3.x defaults and 4.x defaults
|
|
|
|
|
// so upgrade from 3.x default to 4.x defaults while we're at it
|
|
|
|
|
// old qTox database are saved with SQLCipher 3.x defaults. For a period after 1.16.3 but before 1.17.0, databases
|
|
|
|
|
// could be partially upgraded to SQLCipher 4.0 defaults, since SQLCipher 3.x isn't capable of setitng all the same
|
|
|
|
|
// params. If SQLCipher 4.x happened to be used, they would have been fully upgraded to 4.0 default params.
|
|
|
|
|
// We need to support all three of these cases, so also upgrade to the latest possible params while we're here
|
|
|
|
|
if (!setKey(hexKey)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (setCipherParameters(SqlCipherParams::p4_0)) { |
|
|
|
|
auto highestSupportedVersion = highestSupportedParams(); |
|
|
|
|
if (setCipherParameters(highestSupportedVersion)) { |
|
|
|
|
if (testUsable()) { |
|
|
|
|
qInfo() << "Opened database with SQLCipher 4.x parameters"; |
|
|
|
|
qInfo() << "Opened database with SQLCipher" << toString(highestSupportedVersion) << "parameters"; |
|
|
|
|
return true; |
|
|
|
|
} else { |
|
|
|
|
return updateSavedCipherParameters(hexKey); |
|
|
|
|
return updateSavedCipherParameters(hexKey, highestSupportedVersion); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// setKey again to clear old bad cipher settings
|
|
|
|
|
if (setKey(hexKey) && setCipherParameters(SqlCipherParams::p3_0) && testUsable()) { |
|
|
|
|
qInfo() << "Opened database with SQLCipher 3.x parameters"; |
|
|
|
|
return true; |
|
|
|
|
} else { |
|
|
|
|
qCritical() << "Failed to open database with SQLCipher 3.x parameters"; |
|
|
|
|
qCritical() << "Failed to set latest supported SQLCipher params!"; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool RawDatabase::testUsable() |
|
|
|
|
{ |
|
|
|
@ -220,10 +216,11 @@ bool RawDatabase::testUsable()
@@ -220,10 +216,11 @@ bool RawDatabase::testUsable()
|
|
|
|
|
/**
|
|
|
|
|
* @brief Changes stored db encryption from SQLCipher 3.x defaults to 4.x defaults |
|
|
|
|
*/ |
|
|
|
|
bool RawDatabase::updateSavedCipherParameters(const QString& hexKey) |
|
|
|
|
bool RawDatabase::updateSavedCipherParameters(const QString& hexKey, SqlCipherParams newParams) |
|
|
|
|
{ |
|
|
|
|
auto currentParams = readSavedCipherParams(hexKey, newParams); |
|
|
|
|
setKey(hexKey); // setKey again because a SELECT has already been run, causing crypto settings to take effect
|
|
|
|
|
if (!setCipherParameters(SqlCipherParams::p3_0)) { |
|
|
|
|
if (!setCipherParameters(currentParams)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -231,25 +228,26 @@ bool RawDatabase::updateSavedCipherParameters(const QString& hexKey)
@@ -231,25 +228,26 @@ bool RawDatabase::updateSavedCipherParameters(const QString& hexKey)
|
|
|
|
|
if (user_version < 0) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (!execNow("ATTACH DATABASE '" + path + ".tmp' AS sqlcipher4 KEY \"x'" + hexKey + "'\";")) { |
|
|
|
|
if (!execNow("ATTACH DATABASE '" + path + ".tmp' AS newParams KEY \"x'" + hexKey + "'\";")) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (!setCipherParameters(SqlCipherParams::p4_0, "sqlcipher4")) { |
|
|
|
|
if (!setCipherParameters(newParams, "newParams")) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (!execNow("SELECT sqlcipher_export('sqlcipher4');")) { |
|
|
|
|
if (!execNow("SELECT sqlcipher_export('newParams');")) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (!execNow(QString("PRAGMA sqlcipher4.user_version = %1;").arg(user_version))) { |
|
|
|
|
if (!execNow(QString("PRAGMA newParams.user_version = %1;").arg(user_version))) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (!execNow("DETACH DATABASE sqlcipher4;")) { |
|
|
|
|
if (!execNow("DETACH DATABASE newParams;")) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (!commitDbSwap(hexKey)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
qInfo() << "Upgraded database from SQLCipher 3.x defaults to SQLCipher 4.x defaults"; |
|
|
|
|
qInfo() << "Upgraded database from SQLCipher" << toString(currentParams) << "params to" << |
|
|
|
|
toString(newParams) << "params complete"; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -290,10 +288,60 @@ bool RawDatabase::setCipherParameters(SqlCipherParams params, const QString& dat
@@ -290,10 +288,60 @@ bool RawDatabase::setCipherParameters(SqlCipherParams params, const QString& dat
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
qDebug() << "Setting SQLCipher" << static_cast<int>(params) << "parameters"; |
|
|
|
|
|
|
|
|
|
qDebug() << "Setting SQLCipher" << toString(params) << "parameters"; |
|
|
|
|
return execNow(defaultParams.replace("database.", prefix)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RawDatabase::SqlCipherParams RawDatabase::highestSupportedParams() |
|
|
|
|
{ |
|
|
|
|
// Note: This is just calling into the sqlcipher library, not touching the database.
|
|
|
|
|
QString cipherVersion; |
|
|
|
|
if (!execNow(RawDatabase::Query("PRAGMA cipher_version", [&](const QVector<QVariant>& row) { |
|
|
|
|
cipherVersion = row[0].toString(); |
|
|
|
|
}))) { |
|
|
|
|
qCritical() << "Failed to read cipher_version"; |
|
|
|
|
return SqlCipherParams::p3_0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
auto majorVersion = cipherVersion.split('.')[0].toInt(); |
|
|
|
|
|
|
|
|
|
SqlCipherParams highestSupportedParams; |
|
|
|
|
switch (majorVersion) { |
|
|
|
|
case 3: |
|
|
|
|
highestSupportedParams = SqlCipherParams::halfUpgradedTo4; |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
highestSupportedParams = SqlCipherParams::p4_0; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
qCritical() << "Unsupported SQLCipher version detected!"; |
|
|
|
|
return SqlCipherParams::p3_0; |
|
|
|
|
} |
|
|
|
|
qDebug() << "Highest supported SQLCipher params on this system are" << toString(highestSupportedParams); |
|
|
|
|
return highestSupportedParams; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RawDatabase::SqlCipherParams RawDatabase::readSavedCipherParams(const QString& hexKey, SqlCipherParams newParams) |
|
|
|
|
{ |
|
|
|
|
for (int i = static_cast<int>(SqlCipherParams::p3_0); i < static_cast<int>(newParams); ++i) |
|
|
|
|
{ |
|
|
|
|
if (!setKey(hexKey)) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!setCipherParameters(static_cast<SqlCipherParams>(i))) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (testUsable()) { |
|
|
|
|
return static_cast<SqlCipherParams>(i); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
qCritical() << "Failed to check saved SQLCipher params"; |
|
|
|
|
return SqlCipherParams::p3_0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool RawDatabase::setKey(const QString& hexKey) |
|
|
|
|
{ |
|
|
|
|
// setKey again to clear old bad cipher settings
|
|
|
|
|