2
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
3
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 2 or (at your option)
8
* version 3 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21
#include "config-keepassx.h"
23
#include "crypto/CryptoHash.h"
24
#include "crypto/SymmetricCipher.h"
26
#include <botan/version.h>
30
QString g_cryptoError;
34
if (CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", CryptoHash::Sha256)
35
!= QByteArray::fromHex("248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")) {
36
g_cryptoError = "SHA-256 mismatch.";
45
if (CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", CryptoHash::Sha512)
46
!= QByteArray::fromHex("204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335"
47
"96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445")) {
48
g_cryptoError = "SHA-512 mismatch.";
57
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d7781"
58
"1f352c073b6108d72d9810a30914dff4");
59
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
60
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"
61
"ae2d8a571e03ac9c9eb76fac45af8e51");
62
QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"
63
"9cfc4e967edb808d679f777bc6702c7d");
65
QByteArray data = plainText;
66
SymmetricCipher aes256;
67
if (!aes256.init(SymmetricCipher::Aes256_CBC, SymmetricCipher::Encrypt, key, iv)) {
68
g_cryptoError = aes256.errorString();
71
if (!aes256.process(data)) {
72
g_cryptoError = aes256.errorString();
75
if (data != cipherText) {
76
g_cryptoError = "AES-256 CBC encryption mismatch.";
80
if (!aes256.init(SymmetricCipher::Aes256_CBC, SymmetricCipher::Decrypt, key, iv)) {
81
g_cryptoError = aes256.errorString();
84
if (!aes256.process(data)) {
85
g_cryptoError = aes256.errorString();
88
if (data != plainText) {
89
g_cryptoError = "AES-256 CBC decryption mismatch.";
98
QByteArray key = QByteArray::fromHex("000102030405060708090A0B0C0D0E0F"
99
"101112131415161718191A1B1C1D1E1F");
100
QByteArray plainText = QByteArray::fromHex("00112233445566778899AABBCCDDEEFF");
101
QByteArray cipherText = QByteArray::fromHex("8EA2B7CA516745BFEAFC49904B496089");
103
if (!SymmetricCipher::aesKdf(key, 1, plainText)) {
104
g_cryptoError = "AES KDF Failed.";
107
if (plainText != cipherText) {
108
g_cryptoError = "AES KDF encryption mismatch.";
117
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d7781"
118
"1f352c073b6108d72d9810a30914dff4");
119
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
120
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"
121
"ae2d8a571e03ac9c9eb76fac45af8e51");
122
QByteArray cipherText = QByteArray::fromHex("e0227c3cc80f3cb1b2ed847cc6f57d3c"
123
"657b1e7960b30fb7c8d62e72ae37c3a0");
124
QByteArray data = plainText;
125
SymmetricCipher twofish;
126
if (!twofish.init(SymmetricCipher::Twofish_CBC, SymmetricCipher::Encrypt, key, iv)) {
127
g_cryptoError = twofish.errorString();
130
if (!twofish.process(data)) {
131
g_cryptoError = twofish.errorString();
134
if (data != cipherText) {
135
g_cryptoError = "Twofish encryption mismatch.";
139
if (!twofish.init(SymmetricCipher::Twofish_CBC, SymmetricCipher::Decrypt, key, iv)) {
140
g_cryptoError = twofish.errorString();
143
if (!twofish.process(data)) {
144
g_cryptoError = twofish.errorString();
147
if (data != plainText) {
148
g_cryptoError = "Twofish encryption mismatch.";
157
QByteArray salsa20Key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102"
158
"030405060708090A0B0C0D0E0F101112");
159
QByteArray salsa20iv = QByteArray::fromHex("0000000000000000");
160
QByteArray salsa20Plain = QByteArray::fromHex("00000000000000000000000000000000");
161
QByteArray salsa20Cipher = QByteArray::fromHex("B4C0AFA503BE7FC29A62058166D56F8F");
163
QByteArray data = salsa20Plain;
164
SymmetricCipher salsa20Stream;
165
if (!salsa20Stream.init(SymmetricCipher::Salsa20, SymmetricCipher::Encrypt, salsa20Key, salsa20iv)) {
166
g_cryptoError = salsa20Stream.errorString();
169
if (!salsa20Stream.process(data)) {
170
g_cryptoError = salsa20Stream.errorString();
173
if (data != salsa20Cipher) {
174
g_cryptoError = "Salsa20 stream cipher encrypt mismatch.";
178
if (!salsa20Stream.init(SymmetricCipher::Salsa20, SymmetricCipher::Decrypt, salsa20Key, salsa20iv)) {
179
g_cryptoError = salsa20Stream.errorString();
182
if (!salsa20Stream.process(data)) {
183
g_cryptoError = salsa20Stream.errorString();
186
if (data != salsa20Plain) {
187
g_cryptoError = "Salsa20 stream cipher decrypt mismatch.";
196
QByteArray chacha20Key = QByteArray::fromHex("00000000000000000000000000000000"
197
"00000000000000000000000000000000");
198
QByteArray chacha20iv = QByteArray::fromHex("0000000000000000");
199
QByteArray chacha20Plain =
200
QByteArray::fromHex("0000000000000000000000000000000000000000000000000000000000000000"
201
"0000000000000000000000000000000000000000000000000000000000000000");
202
QByteArray chacha20Cipher =
203
QByteArray::fromHex("76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7"
204
"da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586");
206
QByteArray data = chacha20Plain;
207
SymmetricCipher chacha20Stream;
208
if (!chacha20Stream.init(SymmetricCipher::ChaCha20, SymmetricCipher::Encrypt, chacha20Key, chacha20iv)) {
209
g_cryptoError = chacha20Stream.errorString();
212
if (!chacha20Stream.process(data)) {
213
g_cryptoError = chacha20Stream.errorString();
216
if (data != chacha20Cipher) {
217
g_cryptoError = "ChaCha20 stream cipher encrypt mismatch.";
221
if (!chacha20Stream.init(SymmetricCipher::ChaCha20, SymmetricCipher::Decrypt, chacha20Key, chacha20iv)) {
222
g_cryptoError = chacha20Stream.errorString();
225
if (!chacha20Stream.process(data)) {
226
g_cryptoError = chacha20Stream.errorString();
229
if (data != chacha20Plain) {
230
g_cryptoError = "ChaCha20 stream cipher decrypt mismatch.";
243
unsigned int version_major = 3, min_version_minor = 0;
244
QString versionString = "3.x";
246
unsigned int version_major = 2, min_version_minor = 11;
247
QString versionString = "2.11.x";
249
if (Botan::version_major() != version_major || Botan::version_minor() < min_version_minor) {
250
g_cryptoError = QObject::tr("Botan library must be at least %1, found %2.%3.%4")
252
.arg(Botan::version_major())
253
.arg(Botan::version_minor())
254
.arg(Botan::version_patch());
258
return testSha256() && testSha512() && testAes256Cbc() && testAesKdf() && testTwofish() && testSalsa20()
262
QString errorString()
264
return g_cryptoError;
269
QString debugInfo = QObject::tr("Cryptographic libraries:").append("\n");
270
debugInfo.append(QString("- Botan %1.%2.%3\n")
271
.arg(Botan::version_major())
272
.arg(Botan::version_minor())
273
.arg(Botan::version_patch()));