Skip to content

Commit

Permalink
Support DB compression using zstd algorithm (restricted to KDBX 4.1)
Browse files Browse the repository at this point in the history
  • Loading branch information
TOCK-Chiu committed Nov 26, 2024
1 parent 1bbe6f8 commit 8f311ae
Show file tree
Hide file tree
Showing 16 changed files with 411 additions and 20 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ option(WITH_XC_BROWSER "Include browser integration with keepassxc-browser." OFF
option(WITH_XC_BROWSER_PASSKEYS "Passkeys support for browser integration." OFF)
option(WITH_XC_YUBIKEY "Include YubiKey support." OFF)
option(WITH_XC_SSHAGENT "Include SSH agent support." OFF)
option(WITH_XC_ZSTD "Include zstd compression support." OFF)
option(WITH_XC_KEESHARE "Sharing integration with KeeShare" OFF)
option(WITH_XC_UPDATECHECK "Include automatic update checks; disable for controlled distributions" ON)
if(UNIX AND NOT APPLE)
Expand Down Expand Up @@ -102,6 +103,7 @@ if(WITH_XC_ALL)
set(WITH_XC_BROWSER_PASSKEYS ON)
set(WITH_XC_YUBIKEY ON)
set(WITH_XC_SSHAGENT ON)
set(WITH_XC_ZSTD ON)
set(WITH_XC_KEESHARE ON)
if(UNIX AND NOT APPLE)
set(WITH_XC_FDOSECRETS ON)
Expand Down Expand Up @@ -575,6 +577,12 @@ if(WITH_XC_YUBIKEY)
endif()
endif()

if(WITH_XC_ZSTD)
find_library(ZSTD_LIBRARIES zstd REQUIRED)
find_path(ZSTD_INCLUDE_DIR zstd.h REQUIRED)
include_directories(SYSTEM ${ZSTD_INCLUDE_DIR})
endif()

if(UNIX)
check_cxx_source_compiles("#include <sys/prctl.h>
int main() { prctl(PR_SET_DUMPABLE, 0); return 0; }"
Expand Down
44 changes: 42 additions & 2 deletions share/translations/keepassxc_en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2068,8 +2068,20 @@ If you keep this number, your database will not be protected from brute force at
<translation>Additional Database Settings</translation>
</message>
<message>
<source>Enable compression (recommended)</source>
<translation>Enable compression (recommended)</translation>
<source>Enable compression:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>None</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>gzip (default)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>zstd</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Delete Recycle Bin</source>
Expand Down Expand Up @@ -4461,6 +4473,10 @@ If this reoccurs, then your database file may be corrupt.</translation>
<extracomment>Translation: variant map = data structure for storing meta data</extracomment>
<translation>Invalid variant map field type size</translation>
</message>
<message>
<source>Unsupported compression algorithm</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Kdbx4Writer</name>
Expand All @@ -4482,6 +4498,10 @@ If this reoccurs, then your database file may be corrupt.</translation>
<extracomment>Translation comment: variant map = data structure for storing meta data</extracomment>
<translation>Failed to serialize KDF parameters variant map</translation>
</message>
<message>
<source>Unsupported compression algorithm</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KdbxReader</name>
Expand Down Expand Up @@ -8252,6 +8272,14 @@ Kernel: %3 %4</translation>
<source>Internal zlib error when decompressing: </source>
<translation>Internal zlib error when decompressing: </translation>
</message>
<message>
<source>Internal zstd error when decompressing: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Internal zstd error when compressing: </source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtIOCompressor::open</name>
Expand All @@ -8263,6 +8291,18 @@ Kernel: %3 %4</translation>
<source>Internal zlib error: </source>
<translation>Internal zlib error: </translation>
</message>
<message>
<source>this build doesn't ship zstd support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Internal zstd error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Internal zstd error: </source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ReportsWidgetBrowserStatistics</name>
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_feature_info(Passkeys WITH_XC_BROWSER_PASSKEYS "Passkeys support for browser
add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent")
add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare")
add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response")
add_feature_info(Zstd WITH_XC_ZSTD "Database compression using zstd")
add_feature_info(UpdateCheck WITH_XC_UPDATECHECK "Automatic update checking")
if(UNIX AND NOT APPLE)
add_feature_info(FdoSecrets WITH_XC_FDOSECRETS "Implement freedesktop.org Secret Storage Spec server side API.")
Expand Down Expand Up @@ -367,6 +368,7 @@ target_link_libraries(keepassxc_core
${PCSC_LIBRARIES}
${ZXCVBN_LIBRARIES}
${ZLIB_LIBRARIES}
${ZSTD_LIBRARIES}
${MINIZIP_LIBRARIES}
${ARGON2_LIBRARIES}
${KEYUTILS_LIBRARIES}
Expand Down
1 change: 1 addition & 0 deletions src/config-keepassx.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#cmakedefine WITH_XC_DOCS
#cmakedefine WITH_XC_X11
#cmakedefine WITH_XC_BOTAN3
#cmakedefine WITH_XC_ZSTD

#cmakedefine KEEPASSXC_BUILD_TYPE "@KEEPASSXC_BUILD_TYPE@"
#cmakedefine KEEPASSXC_BUILD_TYPE_RELEASE
Expand Down
5 changes: 3 additions & 2 deletions src/core/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ class Database : public ModifiableObject
enum CompressionAlgorithm
{
CompressionNone = 0,
CompressionGZip = 1
CompressionGZip = 1,
CompressionZstd = 2,
};
static const quint32 CompressionAlgorithmMax = CompressionGZip;
static const quint32 CompressionAlgorithmMax = CompressionZstd;

enum SaveAction
{
Expand Down
15 changes: 13 additions & 2 deletions src/format/Kdbx4Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,21 @@ bool Kdbx4Reader::readDatabaseImpl(QIODevice* device,
QIODevice* xmlDevice = nullptr;
QScopedPointer<QtIOCompressor> ioCompressor;

if (db->compressionAlgorithm() == Database::CompressionNone) {
switch (db->compressionAlgorithm()) {
case Database::CompressionNone:
xmlDevice = &cipherStream;
} else {
break;
case Database::CompressionGZip:
ioCompressor.reset(new QtIOCompressor(&cipherStream, QtIOCompressor::GzipFormatSpec{}));
break;
case Database::CompressionZstd:
ioCompressor.reset(new QtIOCompressor(&cipherStream, QtIOCompressor::ZstdFormatSpec{}));
break;
default:
raiseError(tr("Unsupported compression algorithm"));
return false;
}
if (ioCompressor) {
if (!ioCompressor->open(QIODevice::ReadOnly)) {
raiseError(ioCompressor->errorString());
return false;
Expand Down
15 changes: 13 additions & 2 deletions src/format/Kdbx4Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,21 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db)
QIODevice* outputDevice = nullptr;
QScopedPointer<QtIOCompressor> ioCompressor;

if (db->compressionAlgorithm() == Database::CompressionNone) {
switch (db->compressionAlgorithm()) {
case Database::CompressionNone:
outputDevice = cipherStream.data();
} else {
break;
case Database::CompressionGZip:
ioCompressor.reset(new QtIOCompressor(cipherStream.data(), QtIOCompressor::GzipFormatSpec{}));
break;
case Database::CompressionZstd:
ioCompressor.reset(new QtIOCompressor(cipherStream.data(), QtIOCompressor::ZstdFormatSpec{}));
break;
default:
raiseError(tr("Unsupported compression algorithm"));
return false;
}
if (ioCompressor) {
if (!ioCompressor->open(QIODevice::WriteOnly)) {
raiseError(ioCompressor->errorString());
return false;
Expand Down
4 changes: 4 additions & 0 deletions src/format/KeePass2Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ quint32 KeePass2Writer::kdbxVersionRequired(Database const* db, bool ignoreCurre
}
}

if (db->compressionAlgorithm() == Database::CompressionZstd) {
VERSION_MAX(version, KeePass2::FILE_VERSION_4_1)
}

return version;
}

Expand Down
15 changes: 12 additions & 3 deletions src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "DatabaseSettingsWidgetGeneral.h"
#include "ui_DatabaseSettingsWidgetGeneral.h"

#include "config-keepassx.h"

#include <QColorDialog>
#include <QDialogButtonBox>
#include <QInputDialog>
Expand Down Expand Up @@ -56,7 +58,15 @@ void DatabaseSettingsWidgetGeneral::initialize()
m_ui->dbDescriptionEdit->setText(meta->description());
m_ui->recycleBinEnabledCheckBox->setChecked(meta->recycleBinEnabled());
m_ui->defaultUsernameEdit->setText(meta->defaultUserName());
m_ui->compressionCheckbox->setChecked(m_db->compressionAlgorithm() != Database::CompressionNone);

m_ui->compressionCombobox->clear();
m_ui->compressionCombobox->addItem(tr("None"), Database::CompressionNone);
m_ui->compressionCombobox->addItem(tr("gzip (default)"), Database::CompressionGZip);
#ifdef WITH_XC_ZSTD
if (m_db->formatVersion() >= KeePass2::FILE_VERSION_4)
m_ui->compressionCombobox->addItem(tr("zstd"), Database::CompressionZstd);
#endif
m_ui->compressionCombobox->setCurrentIndex(m_db->compressionAlgorithm());

m_ui->dbPublicName->setText(m_db->publicName());
setupPublicColorButton(m_db->publicColor());
Expand Down Expand Up @@ -123,8 +133,7 @@ bool DatabaseSettingsWidgetGeneral::saveSettings()
meta->setRecycleBin(nullptr);
}

m_db->setCompressionAlgorithm(m_ui->compressionCheckbox->isChecked() ? Database::CompressionGZip
: Database::CompressionNone);
m_db->setCompressionAlgorithm(static_cast<Database::CompressionAlgorithm>(m_ui->compressionCombobox->currentData().toInt()));

meta->setName(m_ui->dbNameEdit->text());
meta->setDescription(m_ui->dbDescriptionEdit->text());
Expand Down
37 changes: 29 additions & 8 deletions src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,35 @@ add up to the specified amount at most.</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="compressionCheckbox">
<property name="text">
<string>Enable compression (recommended)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="compressionLabel">
<property name="text">
<string>Enable compression:</string>
</property>
<property name="buddy">
<cstring>compressionCombobox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="compressionCombobox">
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
Expand Down
Loading

0 comments on commit 8f311ae

Please sign in to comment.