diff --git a/src/CipherDialog.cpp b/src/CipherDialog.cpp index ad00d3d5..b8f35954 100644 --- a/src/CipherDialog.cpp +++ b/src/CipherDialog.cpp @@ -1,5 +1,6 @@ #include "CipherDialog.h" #include "ui_CipherDialog.h" +#include "sqlitedb.h" #include #include @@ -41,6 +42,14 @@ CipherDialog::CipherDialog(QWidget* parent, bool encrypt) : ui->editPassword2->setVisible(false); ui->labelPassword2->setVisible(false); } + + // Set the default encryption settings depending on the SQLCipher version we use + QString sqlite_version, sqlcipher_version; + DBBrowserDB::getSqliteVersion(sqlite_version, sqlcipher_version); + if(sqlcipher_version.startsWith('4')) + ui->radioEncryptionSqlCipher4->setChecked(true); + else + ui->radioEncryptionSqlCipher3->setChecked(true); } CipherDialog::~CipherDialog() @@ -60,6 +69,9 @@ CipherSettings CipherDialog::getCipherSettings() const cipherSettings.setKeyFormat(keyFormat); cipherSettings.setPassword(password); cipherSettings.setPageSize(pageSize); + cipherSettings.setKdfIterations(ui->spinKdfIterations->value()); + cipherSettings.setHmacAlgorithm(ui->comboHmacAlgorithm->currentText()); + cipherSettings.setKdfAlgorithm(ui->comboKdfAlgorithm->currentText()); return cipherSettings; } @@ -91,3 +103,38 @@ void CipherDialog::checkInputFields() ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } + +void CipherDialog::toggleEncryptionSettings() +{ + if(ui->radioEncryptionSqlCipher3->isChecked()) + { + // SQLCipher3 + ui->comboPageSize->setCurrentText(QLocale().toString(1024)); + ui->spinKdfIterations->setValue(64000); + ui->comboHmacAlgorithm->setCurrentText("SHA1"); + ui->comboKdfAlgorithm->setCurrentText("SHA1"); + + ui->comboPageSize->setEnabled(false); + ui->spinKdfIterations->setEnabled(false); + ui->comboHmacAlgorithm->setEnabled(false); + ui->comboKdfAlgorithm->setEnabled(false); + } else if(ui->radioEncryptionSqlCipher4->isChecked()) { + // SQLCipher4 + ui->comboPageSize->setCurrentText(QLocale().toString(4096)); + ui->spinKdfIterations->setValue(256000); + ui->comboHmacAlgorithm->setCurrentText("SHA512"); + ui->comboKdfAlgorithm->setCurrentText("SHA512"); + + ui->comboPageSize->setEnabled(false); + ui->spinKdfIterations->setEnabled(false); + ui->comboHmacAlgorithm->setEnabled(false); + ui->comboKdfAlgorithm->setEnabled(false); + } else if(ui->radioEncryptionCustom->isChecked()) { + // Custom + + ui->comboPageSize->setEnabled(true); + ui->spinKdfIterations->setEnabled(true); + ui->comboHmacAlgorithm->setEnabled(true); + ui->comboKdfAlgorithm->setEnabled(true); + } +} diff --git a/src/CipherDialog.h b/src/CipherDialog.h index b08dc22c..50fccae6 100644 --- a/src/CipherDialog.h +++ b/src/CipherDialog.h @@ -30,6 +30,7 @@ private: private slots: void checkInputFields(); + void toggleEncryptionSettings(); }; #endif diff --git a/src/CipherDialog.ui b/src/CipherDialog.ui index deda2e5f..4a4d18ad 100644 --- a/src/CipherDialog.ui +++ b/src/CipherDialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 183 + 299 @@ -18,7 +18,7 @@ - + @@ -55,19 +55,6 @@ - - - - Page si&ze - - - comboPageSize - - - - - - @@ -103,6 +90,136 @@ + + + + + + Encr&yption settings + + + radioEncryptionSqlCipher3 + + + + + + + + + SQLCipher &3 defaults + + + + + + + SQLCipher &4 defaults + + + + + + + Custo&m + + + + + + + + + Page si&ze + + + comboPageSize + + + + + + + + + + &KDF iterations + + + spinKdfIterations + + + + + + + 1 + + + 1000000 + + + + + + + HMAC algorithm + + + comboHmacAlgorithm + + + + + + + + SHA512 + + + + + SHA256 + + + + + SHA1 + + + + + + + + KDF algorithm + + + comboKdfAlgorithm + + + + + + + + SHA512 + + + + + SHA256 + + + + + SHA1 + + + + + + @@ -117,9 +234,15 @@ editPassword - comboKeyFormat editPassword2 + comboKeyFormat + radioEncryptionSqlCipher3 + radioEncryptionSqlCipher4 + radioEncryptionCustom comboPageSize + spinKdfIterations + comboHmacAlgorithm + comboKdfAlgorithm @@ -130,8 +253,8 @@ accept() - 233 - 174 + 175 + 265 157 @@ -146,8 +269,8 @@ reject() - 301 - 174 + 175 + 265 286 @@ -178,8 +301,8 @@ checkInputFields() - 319 - 96 + 446 + 79 206 @@ -203,8 +326,57 @@ + + radioEncryptionSqlCipher3 + toggled(bool) + CipherDialog + toggleEncryptionSettings() + + + 217 + 114 + + + 231 + 94 + + + + + radioEncryptionSqlCipher4 + toggled(bool) + CipherDialog + toggleEncryptionSettings() + + + 353 + 117 + + + 407 + 97 + + + + + radioEncryptionCustom + toggled(bool) + CipherDialog + toggleEncryptionSettings() + + + 552 + 120 + + + 590 + 99 + + + checkInputFields() + toggleEncryptionSettings() diff --git a/src/CipherSettings.cpp b/src/CipherSettings.cpp index aca2ce98..3fe58b95 100644 --- a/src/CipherSettings.cpp +++ b/src/CipherSettings.cpp @@ -32,9 +32,6 @@ void CipherSettings::setPassword(const QString &value) int CipherSettings::getPageSize() const { - if (pageSize == 0) - return defaultPageSize; - return pageSize; } diff --git a/src/CipherSettings.h b/src/CipherSettings.h index 6817839a..7fe992fd 100644 --- a/src/CipherSettings.h +++ b/src/CipherSettings.h @@ -12,8 +12,6 @@ public: RawKey }; - static const int defaultPageSize = 1024; - KeyFormats getKeyFormat() const; void setKeyFormat(const KeyFormats &value); @@ -23,12 +21,24 @@ public: int getPageSize() const; void setPageSize(int value); + int getKdfIterations() const { return kdfIterations; } + void setKdfIterations(int value) { kdfIterations = value; } + + QString getHmacAlgorithm() const { return hmacAlgorithm; } + void setHmacAlgorithm(const QString &value) { hmacAlgorithm = value; } + + QString getKdfAlgorithm() const { return kdfAlgorithm; } + void setKdfAlgorithm(const QString &value) { kdfAlgorithm = value; } + static KeyFormats getKeyFormat(int rawKeyFormat); private: KeyFormats keyFormat; QString password; int pageSize; + int kdfIterations; + QString hmacAlgorithm; + QString kdfAlgorithm; }; #endif // CIPHERSETTINGS_H diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 8758db5a..a35e5fb4 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -3044,6 +3044,12 @@ void MainWindow::editEncryption() qApp->processEvents(); if(ok) ok = db.executeSQL(QString("PRAGMA sqlitebrowser_edit_encryption.cipher_page_size = %1").arg(cipherSettings.getPageSize()), false, false); + if(ok) + ok = db.executeSQL(QString("PRAGMA sqlitebrowser_edit_encryption.kdf_iter = %1").arg(cipherSettings.getKdfIterations()), false, false); + if(ok) + ok = db.executeSQL(QString("PRAGMA sqlitebrowser_edit_encryption.cipher_hmac_algorithm = %1").arg(cipherSettings.getHmacAlgorithm()), false, false); + if(ok) + ok = db.executeSQL(QString("PRAGMA sqlitebrowser_edit_encryption.cipher_kdf_algorithm = %1").arg(cipherSettings.getKdfAlgorithm()), false, false); // Export the current database to the new one qApp->processEvents(); diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index eb0cf1d0..45966ed2 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -126,8 +126,10 @@ bool DBBrowserDB::open(const QString& db, bool readOnly) if(isEncrypted && cipherSettings) { executeSQL(QString("PRAGMA key = %1").arg(cipherSettings->getPassword()), false, false); - if(cipherSettings->getPageSize() != CipherSettings::defaultPageSize) - executeSQL(QString("PRAGMA cipher_page_size = %1;").arg(cipherSettings->getPageSize()), false, false); + executeSQL(QString("PRAGMA cipher_page_size = %1;").arg(cipherSettings->getPageSize()), false, false); + executeSQL(QString("PRAGMA kdf_iter = %1;").arg(cipherSettings->getKdfIterations()), false, false); + executeSQL(QString("PRAGMA cipher_hmac_algorithm = HMAC_%1;").arg(cipherSettings->getHmacAlgorithm()), false, false); + executeSQL(QString("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_%1;").arg(cipherSettings->getKdfAlgorithm()), false, false); } #endif delete cipherSettings; @@ -233,13 +235,25 @@ bool DBBrowserDB::attach(const QString& filePath, QString attach_as) QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } - if(cipherSettings && cipherSettings->getPageSize() != CipherSettings::defaultPageSize) + if(!executeSQL(QString("PRAGMA %1.cipher_page_size = %2").arg(sqlb::escapeIdentifier(attach_as)).arg(cipherSettings->getPageSize()), false)) { - if(!executeSQL(QString("PRAGMA %1.cipher_page_size = %2").arg(sqlb::escapeIdentifier(attach_as)).arg(cipherSettings->getPageSize()), false)) - { - QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); - return false; - } + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL(QString("PRAGMA %1.kdf_iter = %2").arg(sqlb::escapeIdentifier(attach_as)).arg(cipherSettings->getKdfIterations()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL(QString("PRAGMA %1.cipher_hmac_algorithm = HMAC_%2").arg(sqlb::escapeIdentifier(attach_as)).arg(cipherSettings->getHmacAlgorithm()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL(QString("PRAGMA %1.cipher_kdf_algorithm = PBKDF2_HMAC_%2").arg(sqlb::escapeIdentifier(attach_as)).arg(cipherSettings->getKdfAlgorithm()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; } delete cipherSettings; #else @@ -270,6 +284,24 @@ bool DBBrowserDB::tryEncryptionSettings(const QString& filePath, bool* encrypted #ifdef ENABLE_SQLCIPHER bool isDotenvChecked = false; + + // Determine default encryption settings depending on the SQLCipher version we use + QString sqlite_version, sqlcipher_version; + getSqliteVersion(sqlite_version, sqlcipher_version); + int enc_default_page_size, enc_default_kdf_iter; + QString enc_default_hmac_algorithm, enc_default_kdf_algorithm; + if(sqlcipher_version.startsWith('4')) + { + enc_default_page_size = 4096; + enc_default_kdf_iter = 256000; + enc_default_hmac_algorithm = "SHA512"; + enc_default_kdf_algorithm = "SHA512"; + } else { + enc_default_page_size = 1024; + enc_default_kdf_iter = 64000; + enc_default_hmac_algorithm = "SHA1"; + enc_default_kdf_algorithm = "SHA1"; + } #endif *encrypted = false; @@ -319,8 +351,10 @@ bool DBBrowserDB::tryEncryptionSettings(const QString& filePath, bool* encrypted QVariant keyFormatValue = dotenv.value(databaseFileName + "_keyFormat", QVariant(CipherSettings::KeyFormats::Passphrase)); CipherSettings::KeyFormats keyFormat = CipherSettings::getKeyFormat(keyFormatValue.toInt()); - QVariant pageSizeValue = dotenv.value(databaseFileName + "_pageSize", QVariant(CipherSettings::defaultPageSize)); - int pageSize = pageSizeValue.toInt(); + int pageSize = dotenv.value(databaseFileName + "_pageSize", enc_default_page_size).toInt(); + int kdfIterations = dotenv.value(databaseFileName + "_kdfIter", enc_default_kdf_iter).toInt(); + QString hmacAlgorithm = dotenv.value(databaseFileName + "_hmacAlgorithm", enc_default_hmac_algorithm).toString(); + QString kdfAlgorithm = dotenv.value(databaseFileName + "_kdfAlgorithm", enc_default_kdf_algorithm).toString(); delete cipherSettings; cipherSettings = new CipherSettings(); @@ -328,7 +362,9 @@ bool DBBrowserDB::tryEncryptionSettings(const QString& filePath, bool* encrypted cipherSettings->setKeyFormat(keyFormat); cipherSettings->setPassword(password); cipherSettings->setPageSize(pageSize); - + cipherSettings->setKdfIterations(kdfIterations); + cipherSettings->setHmacAlgorithm(hmacAlgorithm); + cipherSettings->setKdfAlgorithm(kdfAlgorithm); } } @@ -363,8 +399,14 @@ bool DBBrowserDB::tryEncryptionSettings(const QString& filePath, bool* encrypted sqlite3_exec(dbHandle, QString("PRAGMA key = %1").arg(cipherSettings->getPassword()).toUtf8(), nullptr, nullptr, nullptr); // Set the page size if it differs from the default value - if(cipherSettings->getPageSize() != CipherSettings::defaultPageSize) + if(cipherSettings->getPageSize() != enc_default_page_size) sqlite3_exec(dbHandle, QString("PRAGMA cipher_page_size = %1;").arg(cipherSettings->getPageSize()).toUtf8(), nullptr, nullptr, nullptr); + if(cipherSettings->getKdfIterations() != enc_default_kdf_iter) + sqlite3_exec(dbHandle, QString("PRAGMA kdf_iter = %1;").arg(cipherSettings->getKdfIterations()).toUtf8(), nullptr, nullptr, nullptr); + if(cipherSettings->getHmacAlgorithm() != enc_default_hmac_algorithm) + sqlite3_exec(dbHandle, QString("PRAGMA cipher_hmac_algorithm = HMAC_%1;").arg(cipherSettings->getHmacAlgorithm()).toUtf8(), nullptr, nullptr, nullptr); + if(cipherSettings->getKdfAlgorithm() != enc_default_kdf_algorithm) + sqlite3_exec(dbHandle, QString("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_%1;").arg(cipherSettings->getKdfAlgorithm()).toUtf8(), nullptr, nullptr, nullptr); *encrypted = true; #else