Skip to content

Commit af15b7e

Browse files
committed
Added memory security so it will not swap
1 parent 2555d35 commit af15b7e

File tree

3 files changed

+54
-48
lines changed

3 files changed

+54
-48
lines changed

src/encryptionengine_crypto.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ bool EncryptionEngine::cryptOperation(const QString& inputPath, const QString& o
5454
QByteArray key = deriveKey(password, salt, keyfilePaths, kdf, iterations);
5555

5656
if (key.isEmpty()) {
57-
qDebug() << "Key derivation failed.";
57+
sodium_munlock(key.data(), key.size());
58+
OPENSSL_cleanse(key.data(), key.size());
5859
return false;
5960
}
6061

@@ -138,8 +139,6 @@ bool EncryptionEngine::performStandardEncryption(EVP_CIPHER_CTX* ctx, const EVP_
138139

139140
bool EncryptionEngine::performStandardDecryption(EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, const QByteArray& key, const QByteArray& iv, QFile& inputFile, QFile& outputFile) {
140141
qDebug() << "Starting decryption process...";
141-
qDebug() << "Key (Hex):" << key.toHex();
142-
qDebug() << "IV (Hex):" << iv.toHex();
143142

144143
// Initialize the decryption operation
145144
if (!EVP_DecryptInit_ex(ctx, cipher, nullptr, reinterpret_cast<const unsigned char*>(key.data()), reinterpret_cast<const unsigned char*>(iv.data()))) {

src/encryptionengine_keyderivation.cpp

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,43 +63,57 @@ QByteArray EncryptionEngine::performKeyDerivation(const QByteArray& passwordWith
6363
// Initialize a QByteArray to hold the derived key
6464
QByteArray key(keySize, 0);
6565

66+
// Attempt to lock the key memory to prevent it from being swapped to disk
67+
if (sodium_mlock(key.data(), key.size()) != 0) {
68+
qDebug() << "Failed to lock key in memory";
69+
return QByteArray(); // Return an empty QByteArray on failure
70+
}
71+
72+
bool success = false;
73+
6674
// Perform key derivation based on the selected KDF
6775
if (kdf == "PBKDF2") {
6876
// PBKDF2 key derivation using SHA-256
69-
if (!PKCS5_PBKDF2_HMAC(passwordWithKeyfile.data(), passwordWithKeyfile.size(),
70-
reinterpret_cast<const unsigned char*>(salt.data()), salt.size(),
71-
iterations, EVP_sha256(), key.size(),
72-
reinterpret_cast<unsigned char*>(key.data()))) {
73-
qDebug() << "PBKDF2 key derivation failed";
74-
return QByteArray(); // Return an empty QByteArray on failure
75-
}
77+
success = PKCS5_PBKDF2_HMAC(passwordWithKeyfile.data(), passwordWithKeyfile.size(),
78+
reinterpret_cast<const unsigned char*>(salt.data()), salt.size(),
79+
iterations, EVP_sha256(), key.size(),
80+
reinterpret_cast<unsigned char*>(key.data())) != 0;
7681
} else if (kdf == "Argon2") {
7782
// Argon2i key derivation
78-
if (argon2i_hash_raw(iterations, 1 << 16, 1,
79-
passwordWithKeyfile.data(), passwordWithKeyfile.size(),
80-
reinterpret_cast<const unsigned char*>(salt.data()), salt.size(),
81-
reinterpret_cast<unsigned char*>(key.data()), key.size()) != ARGON2_OK) {
82-
qDebug() << "Argon2 key derivation failed";
83-
return QByteArray(); // Return an empty QByteArray on failure
84-
}
83+
success = argon2i_hash_raw(iterations, 1 << 16, 1,
84+
passwordWithKeyfile.data(), passwordWithKeyfile.size(),
85+
reinterpret_cast<const unsigned char*>(salt.data()), salt.size(),
86+
reinterpret_cast<unsigned char*>(key.data()), key.size()) == ARGON2_OK;
8587
} else if (kdf == "Scrypt") {
8688
// Scrypt key derivation
8789
unsigned long long opslimit = iterations;
88-
if (crypto_pwhash_scryptsalsa208sha256(reinterpret_cast<unsigned char*>(key.data()),
89-
static_cast<unsigned long long>(key.size()),
90-
passwordWithKeyfile.constData(),
91-
static_cast<unsigned long long>(passwordWithKeyfile.size()),
92-
reinterpret_cast<const unsigned char*>(salt.data()),
93-
opslimit,
94-
crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) {
95-
qDebug() << "Scrypt key derivation failed";
96-
return QByteArray(); // Return an empty QByteArray on failure
97-
}
90+
success = crypto_pwhash_scryptsalsa208sha256(reinterpret_cast<unsigned char*>(key.data()),
91+
static_cast<unsigned long long>(key.size()),
92+
passwordWithKeyfile.constData(),
93+
static_cast<unsigned long long>(passwordWithKeyfile.size()),
94+
reinterpret_cast<const unsigned char*>(salt.data()),
95+
opslimit,
96+
crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) == 0;
9897
} else {
9998
// If an unknown KDF is provided, log an error
10099
qDebug() << "Unknown KDF specified:" << kdf;
100+
}
101+
102+
if (!success) {
103+
qDebug() << kdf << " key derivation failed";
104+
105+
// Unlock and cleanse key before returning
106+
sodium_munlock(key.data(), key.size());
107+
OPENSSL_cleanse(key.data(), key.size());
108+
101109
return QByteArray(); // Return an empty QByteArray on failure
102110
}
103111

112+
// Clear sensitive data in passwordWithKeyfile
113+
OPENSSL_cleanse(const_cast<char*>(passwordWithKeyfile.constData()), passwordWithKeyfile.size());
114+
115+
// Unlock the key memory before returning it
116+
sodium_munlock(key.data(), key.size());
117+
104118
return key;
105-
}
119+
}

tests/test_encryption_app.cpp

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -306,30 +306,23 @@ void TestOpenCryptUI::testAllCiphersAndKDFs()
306306

307307
void TestOpenCryptUI::closeMessageBoxes()
308308
{
309+
// Iterate through all top-level widgets
309310
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
310-
if (widget->isVisible()) {
311-
QMessageBox *msgBox = qobject_cast<QMessageBox*>(widget);
312-
if (msgBox) {
313-
qDebug() << "Found QMessageBox with title:" << msgBox->windowTitle();
314-
if (msgBox->isVisible()) {
315-
qDebug() << "QMessageBox is visible";
316-
317-
QAbstractButton *okButton = msgBox->button(QMessageBox::Ok);
318-
if (okButton) {
319-
qDebug() << "Clicking OK button";
320-
QTest::mouseClick(okButton, Qt::LeftButton);
321-
return;
322-
} else {
323-
qDebug() << "OK button not found in QMessageBox";
324-
}
325-
} else {
326-
qDebug() << "QMessageBox is not visible";
327-
}
311+
// Check if the widget is a visible QMessageBox
312+
QMessageBox *msgBox = qobject_cast<QMessageBox*>(widget);
313+
if (msgBox && msgBox->isVisible()) {
314+
qDebug() << "Found and closing QMessageBox with title:" << msgBox->windowTitle();
315+
316+
// Find the OK button and click it
317+
QAbstractButton *okButton = msgBox->button(QMessageBox::Ok);
318+
if (okButton) {
319+
qDebug() << "Clicking OK button";
320+
QTest::mouseClick(okButton, Qt::LeftButton);
321+
} else {
322+
qDebug() << "OK button not found in QMessageBox";
328323
}
329324
}
330325
}
331-
332-
qDebug() << "No QMessageBox found";
333326
}
334327

335328
QTEST_MAIN(TestOpenCryptUI)

0 commit comments

Comments
 (0)