2010-09-11 17:49:30 +00:00
|
|
|
/*
|
2021-04-04 12:56:00 +00:00
|
|
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
2010-09-11 17:49:30 +00:00
|
|
|
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2 or (at your option)
|
|
|
|
|
* version 3 of the License.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Crypto.h"
|
|
|
|
|
|
2023-05-08 02:41:38 +00:00
|
|
|
#include "config-keepassx.h"
|
|
|
|
|
|
2014-06-15 09:17:40 +00:00
|
|
|
#include "crypto/CryptoHash.h"
|
|
|
|
|
#include "crypto/SymmetricCipher.h"
|
|
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
#include <botan/version.h>
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
namespace
|
2015-10-10 15:02:43 +00:00
|
|
|
{
|
2021-04-04 12:56:00 +00:00
|
|
|
QString g_cryptoError;
|
2019-02-19 01:17:28 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testSha256()
|
|
|
|
|
{
|
|
|
|
|
if (CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", CryptoHash::Sha256)
|
|
|
|
|
!= QByteArray::fromHex("248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")) {
|
|
|
|
|
g_cryptoError = "SHA-256 mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-10-10 15:02:43 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2017-11-12 18:23:01 +00:00
|
|
|
}
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testSha512()
|
|
|
|
|
{
|
|
|
|
|
if (CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", CryptoHash::Sha512)
|
|
|
|
|
!= QByteArray::fromHex("204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335"
|
|
|
|
|
"96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445")) {
|
|
|
|
|
g_cryptoError = "SHA-512 mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2014-06-15 09:17:40 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testAes256Cbc()
|
|
|
|
|
{
|
|
|
|
|
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d7781"
|
|
|
|
|
"1f352c073b6108d72d9810a30914dff4");
|
|
|
|
|
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
|
|
|
|
|
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"
|
|
|
|
|
"ae2d8a571e03ac9c9eb76fac45af8e51");
|
|
|
|
|
QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"
|
|
|
|
|
"9cfc4e967edb808d679f777bc6702c7d");
|
|
|
|
|
|
|
|
|
|
QByteArray data = plainText;
|
|
|
|
|
SymmetricCipher aes256;
|
|
|
|
|
if (!aes256.init(SymmetricCipher::Aes256_CBC, SymmetricCipher::Encrypt, key, iv)) {
|
|
|
|
|
g_cryptoError = aes256.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!aes256.process(data)) {
|
|
|
|
|
g_cryptoError = aes256.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != cipherText) {
|
|
|
|
|
g_cryptoError = "AES-256 CBC encryption mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!aes256.init(SymmetricCipher::Aes256_CBC, SymmetricCipher::Decrypt, key, iv)) {
|
|
|
|
|
g_cryptoError = aes256.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!aes256.process(data)) {
|
|
|
|
|
g_cryptoError = aes256.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != plainText) {
|
|
|
|
|
g_cryptoError = "AES-256 CBC decryption mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-12 18:23:01 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2017-11-12 18:23:01 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testAesKdf()
|
|
|
|
|
{
|
|
|
|
|
QByteArray key = QByteArray::fromHex("000102030405060708090A0B0C0D0E0F"
|
|
|
|
|
"101112131415161718191A1B1C1D1E1F");
|
|
|
|
|
QByteArray plainText = QByteArray::fromHex("00112233445566778899AABBCCDDEEFF");
|
|
|
|
|
QByteArray cipherText = QByteArray::fromHex("8EA2B7CA516745BFEAFC49904B496089");
|
2017-11-12 18:23:01 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
if (!SymmetricCipher::aesKdf(key, 1, plainText)) {
|
|
|
|
|
g_cryptoError = "AES KDF Failed.";
|
|
|
|
|
}
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
if (plainText != cipherText) {
|
|
|
|
|
g_cryptoError = "AES KDF encryption mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2015-05-09 22:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testTwofish()
|
|
|
|
|
{
|
|
|
|
|
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d7781"
|
|
|
|
|
"1f352c073b6108d72d9810a30914dff4");
|
|
|
|
|
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
|
|
|
|
|
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"
|
|
|
|
|
"ae2d8a571e03ac9c9eb76fac45af8e51");
|
|
|
|
|
QByteArray cipherText = QByteArray::fromHex("e0227c3cc80f3cb1b2ed847cc6f57d3c"
|
|
|
|
|
"657b1e7960b30fb7c8d62e72ae37c3a0");
|
|
|
|
|
QByteArray data = plainText;
|
|
|
|
|
SymmetricCipher twofish;
|
|
|
|
|
if (!twofish.init(SymmetricCipher::Twofish_CBC, SymmetricCipher::Encrypt, key, iv)) {
|
|
|
|
|
g_cryptoError = twofish.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!twofish.process(data)) {
|
|
|
|
|
g_cryptoError = twofish.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != cipherText) {
|
|
|
|
|
g_cryptoError = "Twofish encryption mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!twofish.init(SymmetricCipher::Twofish_CBC, SymmetricCipher::Decrypt, key, iv)) {
|
|
|
|
|
g_cryptoError = twofish.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!twofish.process(data)) {
|
|
|
|
|
g_cryptoError = twofish.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != plainText) {
|
|
|
|
|
g_cryptoError = "Twofish encryption mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-09 22:02:08 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2014-06-15 09:17:40 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testSalsa20()
|
|
|
|
|
{
|
|
|
|
|
QByteArray salsa20Key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102"
|
|
|
|
|
"030405060708090A0B0C0D0E0F101112");
|
|
|
|
|
QByteArray salsa20iv = QByteArray::fromHex("0000000000000000");
|
|
|
|
|
QByteArray salsa20Plain = QByteArray::fromHex("00000000000000000000000000000000");
|
|
|
|
|
QByteArray salsa20Cipher = QByteArray::fromHex("B4C0AFA503BE7FC29A62058166D56F8F");
|
|
|
|
|
|
|
|
|
|
QByteArray data = salsa20Plain;
|
|
|
|
|
SymmetricCipher salsa20Stream;
|
|
|
|
|
if (!salsa20Stream.init(SymmetricCipher::Salsa20, SymmetricCipher::Encrypt, salsa20Key, salsa20iv)) {
|
|
|
|
|
g_cryptoError = salsa20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!salsa20Stream.process(data)) {
|
|
|
|
|
g_cryptoError = salsa20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != salsa20Cipher) {
|
|
|
|
|
g_cryptoError = "Salsa20 stream cipher encrypt mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!salsa20Stream.init(SymmetricCipher::Salsa20, SymmetricCipher::Decrypt, salsa20Key, salsa20iv)) {
|
|
|
|
|
g_cryptoError = salsa20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!salsa20Stream.process(data)) {
|
|
|
|
|
g_cryptoError = salsa20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != salsa20Plain) {
|
|
|
|
|
g_cryptoError = "Salsa20 stream cipher decrypt mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-09 17:47:53 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2015-05-09 17:47:53 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
bool testChaCha20()
|
|
|
|
|
{
|
|
|
|
|
QByteArray chacha20Key = QByteArray::fromHex("00000000000000000000000000000000"
|
|
|
|
|
"00000000000000000000000000000000");
|
|
|
|
|
QByteArray chacha20iv = QByteArray::fromHex("0000000000000000");
|
|
|
|
|
QByteArray chacha20Plain =
|
|
|
|
|
QByteArray::fromHex("0000000000000000000000000000000000000000000000000000000000000000"
|
|
|
|
|
"0000000000000000000000000000000000000000000000000000000000000000");
|
|
|
|
|
QByteArray chacha20Cipher =
|
|
|
|
|
QByteArray::fromHex("76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7"
|
|
|
|
|
"da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586");
|
|
|
|
|
|
|
|
|
|
QByteArray data = chacha20Plain;
|
|
|
|
|
SymmetricCipher chacha20Stream;
|
|
|
|
|
if (!chacha20Stream.init(SymmetricCipher::ChaCha20, SymmetricCipher::Encrypt, chacha20Key, chacha20iv)) {
|
|
|
|
|
g_cryptoError = chacha20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!chacha20Stream.process(data)) {
|
|
|
|
|
g_cryptoError = chacha20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != chacha20Cipher) {
|
|
|
|
|
g_cryptoError = "ChaCha20 stream cipher encrypt mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!chacha20Stream.init(SymmetricCipher::ChaCha20, SymmetricCipher::Decrypt, chacha20Key, chacha20iv)) {
|
|
|
|
|
g_cryptoError = chacha20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!chacha20Stream.process(data)) {
|
|
|
|
|
g_cryptoError = chacha20Stream.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data != chacha20Plain) {
|
|
|
|
|
g_cryptoError = "ChaCha20 stream cipher decrypt mismatch.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
return true;
|
2014-06-15 09:17:40 +00:00
|
|
|
}
|
2021-04-04 12:56:00 +00:00
|
|
|
} // namespace
|
2014-06-15 09:17:40 +00:00
|
|
|
|
2021-04-04 12:56:00 +00:00
|
|
|
namespace Crypto
|
2018-03-31 20:01:30 +00:00
|
|
|
{
|
2021-04-04 12:56:00 +00:00
|
|
|
bool init()
|
|
|
|
|
{
|
2023-05-08 02:41:38 +00:00
|
|
|
#ifdef WITH_XC_BOTAN3
|
|
|
|
|
unsigned int version_major = 3, min_version_minor = 0;
|
|
|
|
|
QString versionString = "3.x";
|
|
|
|
|
#else
|
|
|
|
|
unsigned int version_major = 2, min_version_minor = 11;
|
|
|
|
|
QString versionString = "2.11.x";
|
|
|
|
|
#endif
|
|
|
|
|
if (Botan::version_major() != version_major || Botan::version_minor() < min_version_minor) {
|
|
|
|
|
g_cryptoError = QObject::tr("Botan library must be at least %1, found %2.%3.%4")
|
|
|
|
|
.arg(versionString)
|
2021-04-04 12:56:00 +00:00
|
|
|
.arg(Botan::version_major())
|
|
|
|
|
.arg(Botan::version_minor())
|
|
|
|
|
.arg(Botan::version_patch());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return testSha256() && testSha512() && testAes256Cbc() && testAesKdf() && testTwofish() && testSalsa20()
|
|
|
|
|
&& testChaCha20();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString errorString()
|
|
|
|
|
{
|
|
|
|
|
return g_cryptoError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString debugInfo()
|
|
|
|
|
{
|
|
|
|
|
QString debugInfo = QObject::tr("Cryptographic libraries:").append("\n");
|
|
|
|
|
debugInfo.append(QString("- Botan %1.%2.%3\n")
|
|
|
|
|
.arg(Botan::version_major())
|
|
|
|
|
.arg(Botan::version_minor())
|
|
|
|
|
.arg(Botan::version_patch()));
|
|
|
|
|
return debugInfo;
|
|
|
|
|
}
|
|
|
|
|
} // namespace Crypto
|