mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-28 08:49:42 -05:00
Merge pull request #167 from keepassxreboot/migrate/122-twofish
KeePassX PR Migration: #122 Twofish cypher support
This commit is contained in:
commit
2afd21c7ba
@ -83,3 +83,23 @@ QString SymmetricCipher::errorString() const
|
||||
{
|
||||
return m_backend->errorString();
|
||||
}
|
||||
|
||||
SymmetricCipher::Algorithm SymmetricCipher::cipherToAlgorithm(Uuid cipher)
|
||||
{
|
||||
if (cipher == KeePass2::CIPHER_AES) {
|
||||
return SymmetricCipher::Aes256;
|
||||
}
|
||||
else {
|
||||
return SymmetricCipher::Twofish;
|
||||
}
|
||||
}
|
||||
|
||||
Uuid SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm algo)
|
||||
{
|
||||
switch (algo) {
|
||||
case SymmetricCipher::Aes256:
|
||||
return KeePass2::CIPHER_AES;
|
||||
default:
|
||||
return KeePass2::CIPHER_TWOFISH;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <QString>
|
||||
|
||||
#include "crypto/SymmetricCipherBackend.h"
|
||||
#include "format/KeePass2.h"
|
||||
|
||||
class SymmetricCipher
|
||||
{
|
||||
@ -71,6 +72,9 @@ public:
|
||||
int blockSize() const;
|
||||
QString errorString() const;
|
||||
|
||||
static SymmetricCipher::Algorithm cipherToAlgorithm(Uuid cipher);
|
||||
static Uuid algorithmToCipher(SymmetricCipher::Algorithm algo);
|
||||
|
||||
private:
|
||||
static SymmetricCipherBackend* createBackend(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
||||
SymmetricCipher::Direction direction);
|
||||
|
@ -33,6 +33,7 @@ namespace KeePass2
|
||||
const QSysInfo::Endian BYTEORDER = QSysInfo::LittleEndian;
|
||||
|
||||
const Uuid CIPHER_AES = Uuid(QByteArray::fromHex("31c1f2e6bf714350be5805216afc5aff"));
|
||||
const Uuid CIPHER_TWOFISH = Uuid(QByteArray::fromHex("ad68f29f576f4bb9a36ad47af965346c"));
|
||||
|
||||
const QByteArray INNER_STREAM_SALSA20_IV("\xE8\x30\x09\x4B\x97\x20\x5D\x2A");
|
||||
|
||||
|
@ -118,7 +118,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
||||
hash.addData(m_db->transformedMasterKey());
|
||||
QByteArray finalKey = hash.result();
|
||||
|
||||
SymmetricCipherStream cipherStream(m_device, SymmetricCipher::Aes256,
|
||||
SymmetricCipherStream cipherStream(m_device, SymmetricCipher::cipherToAlgorithm(m_db->cipher()),
|
||||
SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
|
||||
if (!cipherStream.init(finalKey, m_encryptionIV)) {
|
||||
raiseError(cipherStream.errorString());
|
||||
@ -330,7 +330,7 @@ void KeePass2Reader::setCipher(const QByteArray& data)
|
||||
else {
|
||||
Uuid uuid(data);
|
||||
|
||||
if (uuid != KeePass2::CIPHER_AES) {
|
||||
if (uuid != KeePass2::CIPHER_AES && uuid != KeePass2::CIPHER_TWOFISH) {
|
||||
raiseError("Unsupported cipher");
|
||||
}
|
||||
else {
|
||||
|
@ -87,8 +87,8 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db)
|
||||
QByteArray headerHash = CryptoHash::hash(header.data(), CryptoHash::Sha256);
|
||||
CHECK_RETURN(writeData(header.data()));
|
||||
|
||||
SymmetricCipherStream cipherStream(device, SymmetricCipher::Aes256, SymmetricCipher::Cbc,
|
||||
SymmetricCipher::Encrypt);
|
||||
SymmetricCipherStream cipherStream(device, SymmetricCipher::cipherToAlgorithm(db->cipher()),
|
||||
SymmetricCipher::Cbc, SymmetricCipher::Encrypt);
|
||||
cipherStream.init(finalKey, encryptionIV);
|
||||
if (!cipherStream.open(QIODevice::WriteOnly)) {
|
||||
raiseError(cipherStream.errorString());
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "core/Database.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "crypto/SymmetricCipher.h"
|
||||
#include "format/KeePass2.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
|
||||
DatabaseSettingsWidget::DatabaseSettingsWidget(QWidget* parent)
|
||||
@ -53,6 +55,7 @@ void DatabaseSettingsWidget::load(Database* db)
|
||||
m_ui->dbDescriptionEdit->setText(meta->description());
|
||||
m_ui->recycleBinEnabledCheckBox->setChecked(meta->recycleBinEnabled());
|
||||
m_ui->defaultUsernameEdit->setText(meta->defaultUserName());
|
||||
m_ui->AlgorithmComboBox->setCurrentIndex(SymmetricCipher::cipherToAlgorithm(m_db->cipher()));
|
||||
m_ui->transformRoundsSpinBox->setValue(m_db->transformRounds());
|
||||
if (meta->historyMaxItems() > -1) {
|
||||
m_ui->historyMaxItemsSpinBox->setValue(meta->historyMaxItems());
|
||||
@ -82,6 +85,8 @@ void DatabaseSettingsWidget::save()
|
||||
meta->setName(m_ui->dbNameEdit->text());
|
||||
meta->setDescription(m_ui->dbDescriptionEdit->text());
|
||||
meta->setDefaultUserName(m_ui->defaultUsernameEdit->text());
|
||||
m_db->setCipher(SymmetricCipher::algorithmToCipher(static_cast<SymmetricCipher::Algorithm>
|
||||
(m_ui->AlgorithmComboBox->currentIndex())));
|
||||
meta->setRecycleBinEnabled(m_ui->recycleBinEnabledCheckBox->isChecked());
|
||||
if (static_cast<quint64>(m_ui->transformRoundsSpinBox->value()) != m_db->transformRounds()) {
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
|
@ -49,35 +49,7 @@
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="dbDescriptionEdit"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="transformRoundsLabel">
|
||||
<property name="text">
|
||||
<string>Transform rounds:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="defaultUsernameLabel">
|
||||
<property name="text">
|
||||
<string>Default username:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="defaultUsernameEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Use recycle bin:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="9" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="historyMaxSizeSpinBox">
|
||||
@ -100,7 +72,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="8" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="historyMaxItemsSpinBox">
|
||||
@ -117,7 +89,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="transformRoundsSpinBox">
|
||||
@ -144,23 +116,72 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QCheckBox" name="historyMaxItemsCheckBox">
|
||||
<property name="text">
|
||||
<string>Max. history items:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="historyMaxSizeCheckBox">
|
||||
<property name="text">
|
||||
<string>Max. history size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="transformRoundsLabel">
|
||||
<property name="text">
|
||||
<string>Transform rounds:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="recycleBinEnabledCheckBox"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="defaultUsernameLabel">
|
||||
<property name="text">
|
||||
<string>Default username:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Use recycle bin:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="defaultUsernameEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="AlgorithmLabel">
|
||||
<property name="text">
|
||||
<string>Algorithm:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="AlgorithmComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AES: 256 Bit (default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Twofish: 256 Bit</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -123,6 +123,127 @@ void TestSymmetricCipher::testAes256CbcDecryption()
|
||||
plainText);
|
||||
}
|
||||
|
||||
void TestSymmetricCipher::testTwofish256CbcEncryption()
|
||||
{
|
||||
// NIST MCT Known-Answer Tests (cbc_e_m.txt)
|
||||
// https://www.schneier.com/code/twofish-kat.zip
|
||||
|
||||
QVector<QByteArray> keys {
|
||||
QByteArray::fromHex("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
QByteArray::fromHex("D0A260EB41755B19374BABF259A79DB3EA7162E65490B03B1AE4871FB35EF23B"),
|
||||
QByteArray::fromHex("8D55E4849A4DED08D89881E6708EDD26BEEE942073DFB3790B2798B240ACD74A"),
|
||||
QByteArray::fromHex("606EFDC2066A837AF0430EBE4CF1F21071CCB236C33B4B9D82404FDB05C74621"),
|
||||
QByteArray::fromHex("B119AA9485CEEEB4CC778AF21121E54DE4BDBA3498C61C8FD9004AA0C71909C3")
|
||||
};
|
||||
QVector<QByteArray> ivs {
|
||||
QByteArray::fromHex("00000000000000000000000000000000"),
|
||||
QByteArray::fromHex("EA7162E65490B03B1AE4871FB35EF23B"),
|
||||
QByteArray::fromHex("549FF6C6274F034211C31FADF3F22571"),
|
||||
QByteArray::fromHex("CF222616B0E4F8E48967D769456B916B"),
|
||||
QByteArray::fromHex("957108025BFD57125B40057BC2DE4FE2")
|
||||
};
|
||||
QVector<QByteArray> plainTexts {
|
||||
QByteArray::fromHex("00000000000000000000000000000000"),
|
||||
QByteArray::fromHex("D0A260EB41755B19374BABF259A79DB3"),
|
||||
QByteArray::fromHex("5DF7846FDB38B611EFD32A1429294095"),
|
||||
QByteArray::fromHex("ED3B19469C276E7228DB8F583C7F2F36"),
|
||||
QByteArray::fromHex("D177575683A46DCE3C34844C5DD0175D")
|
||||
};
|
||||
QVector<QByteArray> cipherTexts {
|
||||
QByteArray::fromHex("EA7162E65490B03B1AE4871FB35EF23B"),
|
||||
QByteArray::fromHex("549FF6C6274F034211C31FADF3F22571"),
|
||||
QByteArray::fromHex("CF222616B0E4F8E48967D769456B916B"),
|
||||
QByteArray::fromHex("957108025BFD57125B40057BC2DE4FE2"),
|
||||
QByteArray::fromHex("6F725C5950133F82EF021A94CADC8508")
|
||||
};
|
||||
|
||||
SymmetricCipher cipher(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Encrypt);
|
||||
bool ok;
|
||||
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
cipher.init(keys[i], ivs[i]);
|
||||
QByteArray ptNext = plainTexts[i];
|
||||
QByteArray ctPrev = ivs[i];
|
||||
QByteArray ctCur;
|
||||
QCOMPARE(cipher.blockSize(), 16);
|
||||
for (int j = 0; j < 5000; ++j) {
|
||||
ctCur = cipher.process(ptNext, &ok);
|
||||
if (!ok)
|
||||
break;
|
||||
ptNext = ctPrev;
|
||||
ctPrev = ctCur;
|
||||
|
||||
ctCur = cipher.process(ptNext, &ok);
|
||||
if (!ok)
|
||||
break;
|
||||
ptNext = ctPrev;
|
||||
ctPrev = ctCur;
|
||||
}
|
||||
|
||||
QVERIFY(ok);
|
||||
QCOMPARE(ctCur, cipherTexts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSymmetricCipher::testTwofish256CbcDecryption()
|
||||
{
|
||||
// NIST MCT Known-Answer Tests (cbc_d_m.txt)
|
||||
// https://www.schneier.com/code/twofish-kat.zip
|
||||
|
||||
QVector<QByteArray> keys {
|
||||
QByteArray::fromHex("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
QByteArray::fromHex("1B1FE8F5A911CD4C0D800EDCE8ED0A942CBA6271A1044F90C30BA8FE91E1C163"),
|
||||
QByteArray::fromHex("EBA31FF8D2A24FDD769A937353E23257294A33394E4D17A668060AD8230811A1"),
|
||||
QByteArray::fromHex("1DCF1915C389AB273F80F897BF008F058ED89F58A95C1BE523C4B11295ED2D0F"),
|
||||
QByteArray::fromHex("491B9A66D3ED4EF19F02180289D5B1A1C2596AE568540A95DC5244198A9B8869")
|
||||
};
|
||||
QVector<QByteArray> ivs {
|
||||
QByteArray::fromHex("00000000000000000000000000000000"),
|
||||
QByteArray::fromHex("1B1FE8F5A911CD4C0D800EDCE8ED0A94"),
|
||||
QByteArray::fromHex("F0BCF70D7BB382917B1A9DAFBB0F38C3"),
|
||||
QByteArray::fromHex("F66C06ED112BE4FA491A6BE4ECE2BD52"),
|
||||
QByteArray::fromHex("54D483731064E5D6A082E09536D53EA4")
|
||||
};
|
||||
QVector<QByteArray> plainTexts {
|
||||
QByteArray::fromHex("2CBA6271A1044F90C30BA8FE91E1C163"),
|
||||
QByteArray::fromHex("05F05148EF495836AB0DA226B2E9D0C2"),
|
||||
QByteArray::fromHex("A792AC61E7110C434BC2BBCAB6E53CAE"),
|
||||
QByteArray::fromHex("4C81F5BDC1081170FF96F50B1F76A566"),
|
||||
QByteArray::fromHex("BD959F5B787037631A37051EA5F369F8")
|
||||
};
|
||||
QVector<QByteArray> cipherTexts {
|
||||
QByteArray::fromHex("00000000000000000000000000000000"),
|
||||
QByteArray::fromHex("2CBA6271A1044F90C30BA8FE91E1C163"),
|
||||
QByteArray::fromHex("05F05148EF495836AB0DA226B2E9D0C2"),
|
||||
QByteArray::fromHex("A792AC61E7110C434BC2BBCAB6E53CAE"),
|
||||
QByteArray::fromHex("4C81F5BDC1081170FF96F50B1F76A566")
|
||||
};
|
||||
|
||||
SymmetricCipher cipher(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
|
||||
bool ok;
|
||||
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
cipher.init(keys[i], ivs[i]);
|
||||
QByteArray ctNext = cipherTexts[i];
|
||||
QByteArray ptCur;
|
||||
QCOMPARE(cipher.blockSize(), 16);
|
||||
for (int j = 0; j < 5000; ++j) {
|
||||
ptCur = cipher.process(ctNext, &ok);
|
||||
if (!ok)
|
||||
break;
|
||||
ctNext = ptCur;
|
||||
|
||||
ptCur = cipher.process(ctNext, &ok);
|
||||
if (!ok)
|
||||
break;
|
||||
ctNext = ptCur;
|
||||
}
|
||||
|
||||
QVERIFY(ok);
|
||||
QCOMPARE(ptCur, plainTexts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSymmetricCipher::testSalsa20()
|
||||
{
|
||||
// http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?logsort=rev&rev=210&view=markup
|
||||
|
@ -28,6 +28,8 @@ private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void testAes256CbcEncryption();
|
||||
void testAes256CbcDecryption();
|
||||
void testTwofish256CbcEncryption();
|
||||
void testTwofish256CbcDecryption();
|
||||
void testSalsa20();
|
||||
void testPadding();
|
||||
void testStreamReset();
|
||||
|
Loading…
Reference in New Issue
Block a user