diff options
-rw-r--r-- | src/crypto/Crypto.cpp | 105 | ||||
-rw-r--r-- | src/crypto/Crypto.h | 11 | ||||
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | tests/TestAutoType.cpp | 2 | ||||
-rw-r--r-- | tests/TestCryptoHash.cpp | 4 | ||||
-rw-r--r-- | tests/TestDeletedObjects.cpp | 2 | ||||
-rw-r--r-- | tests/TestEntry.cpp | 2 | ||||
-rw-r--r-- | tests/TestEntryModel.cpp | 2 | ||||
-rw-r--r-- | tests/TestExporter.cpp | 2 | ||||
-rw-r--r-- | tests/TestGroup.cpp | 2 | ||||
-rw-r--r-- | tests/TestGroupModel.cpp | 2 | ||||
-rw-r--r-- | tests/TestHashedBlockStream.cpp | 2 | ||||
-rw-r--r-- | tests/TestKeePass1Reader.cpp | 2 | ||||
-rw-r--r-- | tests/TestKeePass2RandomStream.cpp | 2 | ||||
-rw-r--r-- | tests/TestKeePass2Reader.cpp | 2 | ||||
-rw-r--r-- | tests/TestKeePass2Writer.cpp | 2 | ||||
-rw-r--r-- | tests/TestKeePass2XmlReader.cpp | 2 | ||||
-rw-r--r-- | tests/TestKeys.cpp | 2 | ||||
-rw-r--r-- | tests/TestModified.cpp | 2 | ||||
-rw-r--r-- | tests/TestSymmetricCipher.cpp | 2 | ||||
-rw-r--r-- | tests/gui/TestGui.cpp | 2 | ||||
-rw-r--r-- | tests/gui/TestGuiPixmaps.cpp | 2 | ||||
-rw-r--r-- | utils/kdbx-extract.cpp | 4 |
23 files changed, 143 insertions, 27 deletions
diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index 1e28002b6..13c3c20ee 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -21,7 +21,12 @@ #include <gcrypt.h> +#include "config-keepassx.h" +#include "crypto/CryptoHash.h" +#include "crypto/SymmetricCipher.h" + bool Crypto::m_initalized(false); +QString Crypto::m_errorStr; #if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) static int gcry_qt_mutex_init(void** p_sys) @@ -64,11 +69,11 @@ Crypto::Crypto() { } -void Crypto::init() +bool Crypto::init() { if (m_initalized) { qWarning("Crypto::init: already initalized"); - return; + return true; } // libgcrypt >= 1.6 doesn't allow custom thread callbacks anymore. @@ -78,7 +83,19 @@ void Crypto::init() gcry_check_version(0); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + if (!checkAlgorithms()) { + return false; + } + + // has to be set before testing Crypto classes m_initalized = true; + + if (!selfTest()) { + m_initalized = false; + return false; + } + + return true; } bool Crypto::initalized() @@ -86,7 +103,89 @@ bool Crypto::initalized() return m_initalized; } -bool Crypto::selfTest() +QString Crypto::errorString() +{ + return m_errorStr; +} + +bool Crypto::backendSelfTest() { return (gcry_control(GCRYCTL_SELFTEST) == 0); } + +bool Crypto::checkAlgorithms() +{ + if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) { + m_errorStr = "GCRY_CIPHER_AES256 not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } + if (gcry_cipher_algo_info(GCRY_CIPHER_TWOFISH, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) { + m_errorStr = "GCRY_CIPHER_TWOFISH not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } +#ifdef GCRYPT_HAS_SALSA20 + if (gcry_cipher_algo_info(GCRY_CIPHER_SALSA20, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) { + m_errorStr = "GCRY_CIPHER_SALSA20 not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } +#endif + if (gcry_md_test_algo(GCRY_MD_SHA256) != 0) { + m_errorStr = "GCRY_MD_SHA256 not found."; + qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); + return false; + } + + return true; +} + +bool Crypto::selfTest() +{ + QByteArray sha256Test = CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + CryptoHash::Sha256); + + if (sha256Test != QByteArray::fromHex("248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")) { + m_errorStr = "SHA-256 mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f"); + QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"); + plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51")); + QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"); + cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d")); + + SymmetricCipher aes256Encrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, key, iv); + if (aes256Encrypt.process(plainText) != cipherText) { + m_errorStr = "AES-256 encryption mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + SymmetricCipher aes256Descrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, key, iv); + if (aes256Descrypt.process(cipherText) != plainText) { + m_errorStr = "AES-256 decryption mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + QByteArray salsa20Key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112"); + QByteArray salsa20iv = QByteArray::fromHex("0000000000000000"); + QByteArray salsa20Plain = QByteArray::fromHex("00000000000000000000000000000000"); + QByteArray salsa20Cipher = QByteArray::fromHex("B4C0AFA503BE7FC29A62058166D56F8F"); + + SymmetricCipher salsa20Stream(SymmetricCipher::Salsa20, SymmetricCipher::Stream, + SymmetricCipher::Encrypt, salsa20Key, salsa20iv); + + if (salsa20Stream.process(salsa20Plain) != salsa20Cipher) { + m_errorStr = "Salsa20 stream cipher mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + return true; +} diff --git a/src/crypto/Crypto.h b/src/crypto/Crypto.h index 63f117771..9926f14b2 100644 --- a/src/crypto/Crypto.h +++ b/src/crypto/Crypto.h @@ -18,18 +18,25 @@ #ifndef KEEPASSX_CRYPTO_H #define KEEPASSX_CRYPTO_H +#include <QString> + #include "core/Global.h" class Crypto { public: - static void init(); + static bool init(); static bool initalized(); - static bool selfTest(); + static bool backendSelfTest(); + static QString errorString(); private: Crypto(); + static bool checkAlgorithms(); + static bool selfTest(); + static bool m_initalized; + static QString m_errorStr; }; #endif // KEEPASSX_CRYPTO_H diff --git a/src/main.cpp b/src/main.cpp index d5e64b92c..b9659e45d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,7 @@ #include "crypto/Crypto.h" #include "gui/Application.h" #include "gui/MainWindow.h" +#include "gui/MessageBox.h" int main(int argc, char** argv) { @@ -38,7 +39,14 @@ int main(int argc, char** argv) // don't set organizationName as that changes the return value of // QDesktopServices::storageLocation(QDesktopServices::DataLocation) - Crypto::init(); + if (!Crypto::init()) { + QString error = QCoreApplication::translate("Main", + "Fatal error while testing the cryptographic functions."); + error.append("\n"); + error.append(Crypto::errorString()); + MessageBox::critical(Q_NULLPTR, QCoreApplication::translate("Main", "KeePassX - Error"), error); + return 1; + } QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "KeePassX - cross-platform password manager")); diff --git a/tests/TestAutoType.cpp b/tests/TestAutoType.cpp index 4f4350e71..818f57c96 100644 --- a/tests/TestAutoType.cpp +++ b/tests/TestAutoType.cpp @@ -35,7 +35,7 @@ QTEST_GUILESS_MAIN(TestAutoType) void TestAutoType::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); Config::createTempFileInstance(); AutoType::createTestInstance(); config()->set("AutoTypeEntryTitleMatch", false); diff --git a/tests/TestCryptoHash.cpp b/tests/TestCryptoHash.cpp index d189d456c..eb26ca83f 100644 --- a/tests/TestCryptoHash.cpp +++ b/tests/TestCryptoHash.cpp @@ -27,13 +27,13 @@ QTEST_GUILESS_MAIN(TestCryptoHash) void TestCryptoHash::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestCryptoHash::test() { // TODO: move somewhere else - QVERIFY(Crypto::selfTest()); + QVERIFY(Crypto::backendSelfTest()); CryptoHash cryptoHash1(CryptoHash::Sha256); QCOMPARE(cryptoHash1.result(), diff --git a/tests/TestDeletedObjects.cpp b/tests/TestDeletedObjects.cpp index 5967e58ee..277dbcb6b 100644 --- a/tests/TestDeletedObjects.cpp +++ b/tests/TestDeletedObjects.cpp @@ -30,7 +30,7 @@ QTEST_GUILESS_MAIN(TestDeletedObjects) void TestDeletedObjects::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestDeletedObjects::createAndDelete(Database* db, int delObjectsSize) diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 481250a20..477e83b86 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -27,7 +27,7 @@ QTEST_GUILESS_MAIN(TestEntry) void TestEntry::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestEntry::testHistoryItemDeletion() diff --git a/tests/TestEntryModel.cpp b/tests/TestEntryModel.cpp index 5347a3c52..7ba886bc2 100644 --- a/tests/TestEntryModel.cpp +++ b/tests/TestEntryModel.cpp @@ -38,7 +38,7 @@ QTEST_GUILESS_MAIN(TestEntryModel) void TestEntryModel::initTestCase() { qRegisterMetaType<QModelIndex>("QModelIndex"); - Crypto::init(); + QVERIFY(Crypto::init()); } void TestEntryModel::test() diff --git a/tests/TestExporter.cpp b/tests/TestExporter.cpp index 16b4b23cb..d703e02f1 100644 --- a/tests/TestExporter.cpp +++ b/tests/TestExporter.cpp @@ -30,7 +30,7 @@ QTEST_GUILESS_MAIN(TestExporter) void TestExporter::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestExporter::testToDbExporter() diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 32398f01f..507cf155d 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -33,7 +33,7 @@ void TestGroup::initTestCase() { qRegisterMetaType<Entry*>("Entry*"); qRegisterMetaType<Group*>("Group*"); - Crypto::init(); + QVERIFY(Crypto::init()); } void TestGroup::testParenting() diff --git a/tests/TestGroupModel.cpp b/tests/TestGroupModel.cpp index fe7018e84..32a4b8e9b 100644 --- a/tests/TestGroupModel.cpp +++ b/tests/TestGroupModel.cpp @@ -32,7 +32,7 @@ QTEST_GUILESS_MAIN(TestGroupModel) void TestGroupModel::initTestCase() { qRegisterMetaType<QModelIndex>("QModelIndex"); - Crypto::init(); + QVERIFY(Crypto::init()); } void TestGroupModel::test() diff --git a/tests/TestHashedBlockStream.cpp b/tests/TestHashedBlockStream.cpp index b062908f7..09179fef2 100644 --- a/tests/TestHashedBlockStream.cpp +++ b/tests/TestHashedBlockStream.cpp @@ -28,7 +28,7 @@ QTEST_GUILESS_MAIN(TestHashedBlockStream) void TestHashedBlockStream::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestHashedBlockStream::testWriteRead() diff --git a/tests/TestKeePass1Reader.cpp b/tests/TestKeePass1Reader.cpp index 423087c91..249a3657b 100644 --- a/tests/TestKeePass1Reader.cpp +++ b/tests/TestKeePass1Reader.cpp @@ -37,7 +37,7 @@ QTEST_GUILESS_MAIN(TestKeePass1Reader) void TestKeePass1Reader::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/basic.kdb"); diff --git a/tests/TestKeePass2RandomStream.cpp b/tests/TestKeePass2RandomStream.cpp index 328decb30..7963e9af8 100644 --- a/tests/TestKeePass2RandomStream.cpp +++ b/tests/TestKeePass2RandomStream.cpp @@ -30,7 +30,7 @@ QTEST_GUILESS_MAIN(TestKeePass2RandomStream) void TestKeePass2RandomStream::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestKeePass2RandomStream::test() diff --git a/tests/TestKeePass2Reader.cpp b/tests/TestKeePass2Reader.cpp index 3dd87c4f4..d6cb70c78 100644 --- a/tests/TestKeePass2Reader.cpp +++ b/tests/TestKeePass2Reader.cpp @@ -32,7 +32,7 @@ QTEST_GUILESS_MAIN(TestKeePass2Reader) void TestKeePass2Reader::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestKeePass2Reader::testNonAscii() diff --git a/tests/TestKeePass2Writer.cpp b/tests/TestKeePass2Writer.cpp index f00b38e86..cf4ab1c56 100644 --- a/tests/TestKeePass2Writer.cpp +++ b/tests/TestKeePass2Writer.cpp @@ -33,7 +33,7 @@ QTEST_GUILESS_MAIN(TestKeePass2Writer) void TestKeePass2Writer::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); CompositeKey key; key.addKey(PasswordKey("test")); diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index d9935804d..8e87d6744 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -68,7 +68,7 @@ QDateTime TestKeePass2XmlReader::genDT(int year, int month, int day, int hour, i void TestKeePass2XmlReader::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); KeePass2XmlReader reader; QString xmlFile = QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml"); diff --git a/tests/TestKeys.cpp b/tests/TestKeys.cpp index d5cba4abc..d6758d655 100644 --- a/tests/TestKeys.cpp +++ b/tests/TestKeys.cpp @@ -35,7 +35,7 @@ QTEST_GUILESS_MAIN(TestKeys) void TestKeys::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestKeys::testComposite() diff --git a/tests/TestModified.cpp b/tests/TestModified.cpp index 85a6bf23e..e275e837b 100644 --- a/tests/TestModified.cpp +++ b/tests/TestModified.cpp @@ -31,7 +31,7 @@ QTEST_GUILESS_MAIN(TestModified) void TestModified::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestModified::testSignals() diff --git a/tests/TestSymmetricCipher.cpp b/tests/TestSymmetricCipher.cpp index 9f05db1bd..6d4e94f6f 100644 --- a/tests/TestSymmetricCipher.cpp +++ b/tests/TestSymmetricCipher.cpp @@ -29,7 +29,7 @@ QTEST_GUILESS_MAIN(TestSymmetricCipher) void TestSymmetricCipher::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestSymmetricCipher::testAes256CbcEncryption() diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 51dc39e5d..326c3497b 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -51,7 +51,7 @@ void TestGui::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); Config::createTempFileInstance(); m_mainWindow = new MainWindow(); m_tabWidget = m_mainWindow->findChild<DatabaseTabWidget*>("tabWidget"); diff --git a/tests/gui/TestGuiPixmaps.cpp b/tests/gui/TestGuiPixmaps.cpp index 401f68bc3..87e3f2488 100644 --- a/tests/gui/TestGuiPixmaps.cpp +++ b/tests/gui/TestGuiPixmaps.cpp @@ -29,7 +29,7 @@ void TestGuiPixmaps::initTestCase() { - Crypto::init(); + QVERIFY(Crypto::init()); } void TestGuiPixmaps::testDatabaseIcons() diff --git a/utils/kdbx-extract.cpp b/utils/kdbx-extract.cpp index beee71dc3..f5d2a19a6 100644 --- a/utils/kdbx-extract.cpp +++ b/utils/kdbx-extract.cpp @@ -38,7 +38,9 @@ int main(int argc, char **argv) return 1; } - Crypto::init(); + if (!Crypto::init()) { + qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); + } CompositeKey key; if (QFile::exists(app.arguments().at(1))) { |