diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | gpgfrontend.qrc | 1 | ||||
-rw-r--r-- | resource/icons/key_package.png | bin | 0 -> 8815 bytes | |||
-rw-r--r-- | src/gpg/CMakeLists.txt | 18 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyImportExporter.cpp | 25 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyImportExporter.h | 6 | ||||
-rw-r--r-- | src/ui/CMakeLists.txt | 15 | ||||
-rwxr-xr-x | src/ui/KeyMgmt.cpp | 75 | ||||
-rwxr-xr-x | src/ui/KeyMgmt.h | 4 | ||||
-rw-r--r-- | src/ui/MainWindow.cpp | 3 | ||||
-rw-r--r-- | src/ui/aes/qaesencryption.cpp | 626 | ||||
-rw-r--r-- | src/ui/aes/qaesencryption.h | 155 | ||||
-rw-r--r-- | src/ui/keypair_details/KeyUIDSignDialog.cpp | 2 | ||||
-rw-r--r-- | src/ui/smtp/RecipientsPicker.cpp | 2 | ||||
-rw-r--r-- | src/ui/smtp/SenderPicker.cpp | 2 | ||||
-rw-r--r-- | src/ui/widgets/ExportKeyPackageDialog.cpp | 165 | ||||
-rw-r--r-- | src/ui/widgets/ExportKeyPackageDialog.h | 55 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.cpp | 62 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.h | 22 | ||||
-rw-r--r-- | third_party/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ui/ExportKeyPackageDialog.ui | 207 | ||||
-rw-r--r-- | ui/KeyList.ui | 16 |
22 files changed, 1382 insertions, 83 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index eca4a86c..dcdca845 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,7 +231,7 @@ endif () # Basic Envirnoment Configure set(BASIC_ENV_CONFIG 1) set(QT_MOC_CONFIG 1) -set(ESAY_LOGGING_PP 1) +set(EASY_LOGGING_PP 1) if (LINUX_INSTALL_SOFTWARE) include(GNUInstallDirs) diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc index c7ecc963..461c488d 100644 --- a/gpgfrontend.qrc +++ b/gpgfrontend.qrc @@ -45,6 +45,7 @@ <file alias="key_generate.png">resource/icons/key_generate.png</file> <file alias="key_import.png">resource/icons/key_import.png</file> <file alias="kgpg_key2.png">resource/icons/kgpg_key2.png</file> + <file alias="key_package.png">resource/icons/key_package.png</file> <file alias="misc_doc.png">resource/icons/misc_doc.png</file> <file alias="quote.png">resource/icons/quote.png</file> <file alias="signature.png">resource/icons/signature.png</file> diff --git a/resource/icons/key_package.png b/resource/icons/key_package.png Binary files differnew file mode 100644 index 00000000..6464cb9d --- /dev/null +++ b/resource/icons/key_package.png diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt index ac01aa26..0ccc8171 100644 --- a/src/gpg/CMakeLists.txt +++ b/src/gpg/CMakeLists.txt @@ -9,8 +9,8 @@ set(UTILS_DIR ${CMAKE_SOURCE_DIR}/utils) set(GPGME_LIB_DIR ${UTILS_DIR}/gpgme/lib) -if (ESAY_LOGGING_PP) - message(STATUS "Link ESAY_LOGGING_PP") +if (EASY_LOGGING_PP) + message(STATUS "Link EASY_LOGGING_PP") set(THIRD_PARTY_LIBS easy_logging_pp config++) endif () @@ -33,13 +33,13 @@ elseif (APPLE) ${BOOST_LIBS} ${libgpgme} ${libgpg-error} ${libassuan} dl) - if(XCODE_BUILD) - set_target_properties(gpg_core - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}) - endif() + if (XCODE_BUILD) + set_target_properties(gpg_core + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}) + endif () else () find_library(libgpgme NAMES libgpgme.a) find_library(libgpg-error NAMES libgpg-error.a) diff --git a/src/gpg/function/GpgKeyImportExporter.cpp b/src/gpg/function/GpgKeyImportExporter.cpp index ca9b86d1..33f865a7 100644 --- a/src/gpg/function/GpgKeyImportExporter.cpp +++ b/src/gpg/function/GpgKeyImportExporter.cpp @@ -60,24 +60,34 @@ GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExporter::ImportKey( * @param out_buffer output byte array * @return if success */ -bool GpgFrontend::GpgKeyImportExporter::ExportKeys( - KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const { +bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, + ByteArrayPtr& out_buffer, + bool secret) const { if (uid_list->empty()) return false; + std::stringstream ss; + + int _mode = 0; + + if (secret) _mode |= GPGME_EXPORT_MODE_SECRET; + // Alleviate another crash problem caused by an unknown array out-of-bounds // access auto all_success = true; for (size_t i = 0; i < uid_list->size(); i++) { GpgData data_out; - auto err = gpgme_op_export(ctx, (*uid_list)[i].c_str(), 0, data_out); + auto err = gpgme_op_export(ctx, (*uid_list)[i].c_str(), _mode, data_out); if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) all_success = false; DLOG(INFO) << "exportKeys read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END); auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); + + ss << *temp_out_buffer << std::endl; } + out_buffer = std::make_unique<ByteArray>(ss.str()); + return all_success; } @@ -87,11 +97,12 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeys( * @param outBuffer output byte array * @return if success */ -bool GpgFrontend::GpgKeyImportExporter::ExportKeys( - const KeyArgsList& keys, ByteArrayPtr& out_buffer) const { +bool GpgFrontend::GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, + ByteArrayPtr& out_buffer, + bool secret) const { KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>(); for (const auto& key : keys) key_ids->push_back(key.id()); - return ExportKeys(key_ids, out_buffer); + return ExportKeys(key_ids, out_buffer, secret); } /** diff --git a/src/gpg/function/GpgKeyImportExporter.h b/src/gpg/function/GpgKeyImportExporter.h index b6c91303..64b3b8a9 100644 --- a/src/gpg/function/GpgKeyImportExporter.h +++ b/src/gpg/function/GpgKeyImportExporter.h @@ -88,9 +88,11 @@ class GpgKeyImportExporter GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer); - bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const; + bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, + bool secret = false) const; - bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer) const; + bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer, + bool secret = false) const; bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const; diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index dd4973be..d61519d9 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,4 +1,5 @@ aux_source_directory(. UI_SOURCE) +aux_source_directory(./aes UI_SOURCE) aux_source_directory(./keypair_details UI_SOURCE) aux_source_directory(./widgets UI_SOURCE) aux_source_directory(./keygen UI_SOURCE) @@ -19,11 +20,11 @@ target_link_libraries(${GPGFRONTEND_UI_LIB_NAME} target_include_directories(gpgfrontend-ui PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/${GPGFRONTEND_UI_LIB_NAME}_autogen/include) -if(XCODE_BUILD) -set_target_properties(gpgfrontend-ui - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}) -endif() +if (XCODE_BUILD) + set_target_properties(gpgfrontend-ui + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}) +endif () target_compile_features(gpgfrontend-ui PUBLIC cxx_std_17)
\ No newline at end of file diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp index 99647571..bd5c91a9 100755 --- a/src/ui/KeyMgmt.cpp +++ b/src/ui/KeyMgmt.cpp @@ -33,15 +33,16 @@ #include "ui/UserInterfaceUtils.h" #include "ui/keygen/SubkeyGenerateDialog.h" #include "ui/settings/GlobalSettingStation.h" +#include "ui/widgets/ExportKeyPackageDialog.h" namespace GpgFrontend::UI { KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { /* the list of Keys available*/ - mKeyList = new KeyList(true, this); + key_list_ = new KeyList(KeyMenuAbility::ALL, this); - mKeyList->addListGroupTab(_("All"), KeyListRow::SECRET_OR_PUBLIC_KEY); + key_list_->addListGroupTab(_("All"), KeyListRow::SECRET_OR_PUBLIC_KEY); - mKeyList->addListGroupTab( + key_list_->addListGroupTab( _("Only Public Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, @@ -50,7 +51,7 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { !(key.revoked() || key.disabled() || key.expired()); }); - mKeyList->addListGroupTab( + key_list_->addListGroupTab( _("Has Private Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, @@ -59,8 +60,8 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { !(key.revoked() || key.disabled() || key.expired()); }); - mKeyList->addListGroupTab( - _("No Master Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, + key_list_->addListGroupTab( + _("No Primary Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key) -> bool { @@ -68,24 +69,24 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { !(key.revoked() || key.disabled() || key.expired()); }); - mKeyList->addListGroupTab( + key_list_->addListGroupTab( _("Revoked"), KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key) -> bool { return key.revoked(); }); - mKeyList->addListGroupTab( + key_list_->addListGroupTab( _("Expired"), KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key) -> bool { return key.expired(); }); - setCentralWidget(mKeyList); - mKeyList->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) { + setCentralWidget(key_list_); + key_list_->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) { new KeyDetailsDialog(key, parent); }); - mKeyList->slotRefresh(); + key_list_->slotRefresh(); createActions(); createMenus(); @@ -146,8 +147,8 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { this->statusBar()->show(); setWindowTitle(_("KeyPair Management")); - mKeyList->addMenuAction(deleteSelectedKeysAct); - mKeyList->addMenuAction(showKeyDetailsAct); + key_list_->addMenuAction(deleteSelectedKeysAct); + key_list_->addMenuAction(showKeyDetailsAct); connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh())); @@ -210,11 +211,11 @@ void KeyMgmt::createActions() { connect(exportKeyToClipboardAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToClipboard())); - exportKeyToFileAct = new QAction(_("Export To File"), this); - exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png")); - exportKeyToFileAct->setToolTip(_("Export Selected Key(s) To File")); + exportKeyToFileAct = new QAction(_("Export To Key Package"), this); + exportKeyToFileAct->setIcon(QIcon(":key_package.png")); + exportKeyToFileAct->setToolTip(_("Export Checked Key(s) To a Key Package")); connect(exportKeyToFileAct, SIGNAL(triggered()), this, - SLOT(slotExportKeyToFile())); + SLOT(slotExportKeyToKeyPackage())); exportKeyAsOpenSSHFormat = new QAction(_("Export As OpenSSH"), this); exportKeyAsOpenSSHFormat->setIcon(QIcon(":ssh-key.png")); @@ -295,11 +296,11 @@ void KeyMgmt::createToolBars() { } void KeyMgmt::slotDeleteSelectedKeys() { - deleteKeysWithWarning(mKeyList->getSelected()); + deleteKeysWithWarning(key_list_->getSelected()); } void KeyMgmt::slotDeleteCheckedKeys() { - deleteKeysWithWarning(mKeyList->getChecked()); + deleteKeysWithWarning(key_list_->getChecked()); } void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) { @@ -337,7 +338,7 @@ void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) { } void KeyMgmt::slotShowKeyDetails() { - auto keys_selected = mKeyList->getSelected(); + auto keys_selected = key_list_->getSelected(); if (keys_selected->empty()) return; auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front()); @@ -350,34 +351,22 @@ void KeyMgmt::slotShowKeyDetails() { new KeyDetailsDialog(key); } -void KeyMgmt::slotExportKeyToFile() { - ByteArrayPtr key_export_data = nullptr; - auto keys_checked = mKeyList->getChecked(); - if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked, - key_export_data)) { - return; - } - auto key = - GpgKeyGetter::GetInstance().GetKey(mKeyList->getSelected()->front()); - if (!key.good()) { - QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); +void KeyMgmt::slotExportKeyToKeyPackage() { + auto keys_checked = key_list_->getChecked(); + if (keys_checked->empty()) { + QMessageBox::critical( + this, _("Error"), + _("Please check some keys before doing this operation.")); return; } - QString fileString = QString::fromStdString(key.name() + " " + key.email() + - "(" + key.id() + ")_pub.asc"); - - QString file_name = QFileDialog::getSaveFileName( - this, _("Export Key To File"), fileString, - QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)"); - - write_buffer_to_file(file_name.toStdString(), *key_export_data); - + auto dialog = new ExportKeyPackageDialog(std::move(keys_checked), this); + dialog->exec(); emit signalStatusBarChanged(QString(_("key(s) exported"))); } void KeyMgmt::slotExportKeyToClipboard() { ByteArrayPtr key_export_data = nullptr; - auto keys_checked = mKeyList->getChecked(); + auto keys_checked = key_list_->getChecked(); if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked, key_export_data)) { return; @@ -396,7 +385,7 @@ void KeyMgmt::closeEvent(QCloseEvent* event) { } void KeyMgmt::slotGenerateSubKey() { - auto keys_selected = mKeyList->getSelected(); + auto keys_selected = key_list_->getSelected(); if (keys_selected->empty()) { QMessageBox::information( nullptr, _("Invalid Operation"), @@ -467,7 +456,7 @@ void KeyMgmt::slotSaveWindowState() { void KeyMgmt::slotExportAsOpenSSHFormat() { ByteArrayPtr key_export_data = nullptr; - auto keys_checked = mKeyList->getChecked(); + auto keys_checked = key_list_->getChecked(); if (keys_checked->empty()) { QMessageBox::critical(nullptr, _("Error"), _("No Key Checked.")); diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h index 7edb1b5c..ae220481 100755 --- a/src/ui/KeyMgmt.h +++ b/src/ui/KeyMgmt.h @@ -44,7 +44,7 @@ class KeyMgmt : public QMainWindow { void slotGenerateSubKey(); - void slotExportKeyToFile(); + void slotExportKeyToKeyPackage(); void slotExportKeyToClipboard(); @@ -75,7 +75,7 @@ class KeyMgmt : public QMainWindow { void deleteKeysWithWarning(GpgFrontend::KeyIdArgsListPtr uidList); - KeyList* mKeyList; + KeyList* key_list_; QMenu* fileMenu{}; QMenu* keyMenu{}; QMenu* generateKeyMenu{}; diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 422db814..fd3e6820 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -50,7 +50,8 @@ void MainWindow::init() noexcept { setCentralWidget(edit); /* the list of Keys available*/ - mKeyList = new KeyList(true, this); + mKeyList = new KeyList( + KeyMenuAbility::REFRESH | KeyMenuAbility::UNCHECK_ALL, this); infoBoard = new InfoBoardWidget(this); diff --git a/src/ui/aes/qaesencryption.cpp b/src/ui/aes/qaesencryption.cpp new file mode 100644 index 00000000..9103fb8e --- /dev/null +++ b/src/ui/aes/qaesencryption.cpp @@ -0,0 +1,626 @@ +#include "qaesencryption.h" +#include <QDebug> +#include <QVector> + +#ifdef USE_INTEL_AES_IF_AVAILABLE +#include "aesni/aesni-key-exp.h" +#include "aesni/aesni-enc-ecb.h" +#include "aesni/aesni-enc-cbc.h" +#endif + +/* + * Static Functions + * */ +QByteArray QAESEncryption::Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, + const QByteArray &key, const QByteArray &iv, QAESEncryption::Padding padding) +{ + return QAESEncryption(level, mode, padding).encode(rawText, key, iv); +} + +QByteArray QAESEncryption::Decrypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, + const QByteArray &key, const QByteArray &iv, QAESEncryption::Padding padding) +{ + return QAESEncryption(level, mode, padding).decode(rawText, key, iv); +} + +QByteArray QAESEncryption::ExpandKey(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &key) +{ + return QAESEncryption(level, mode).expandKey(key); +} + +QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding) +{ + if (rawText.isEmpty()) + return rawText; + + QByteArray ret(rawText); + switch (padding) + { + case Padding::ZERO: + //Works only if the last byte of the decoded array is not zero + while (ret.at(ret.length()-1) == 0x00) + ret.remove(ret.length()-1, 1); + break; + case Padding::PKCS7: +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + ret.remove(ret.length() - ret.back(), ret.back()); +#else + ret.remove(ret.length() - ret.at(ret.length() - 1), ret.at(ret.length() - 1)); +#endif + break; + case Padding::ISO: + { + // Find the last byte which is not zero + int marker_index = ret.length() - 1; + for (; marker_index >= 0; --marker_index) + { + if (ret.at(marker_index) != 0x00) + { + break; + } + } + + // And check if it's the byte for marking padding + if (ret.at(marker_index) == '\x80') + { + ret.truncate(marker_index); + } + break; + } + default: + //do nothing + break; + } + return ret; +} +/* + * End Static function declarations + * */ + +/* + * Local Functions + * */ + +namespace { + +quint8 xTime(quint8 x) +{ + return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); +} + +quint8 multiply(quint8 x, quint8 y) +{ + return (((y & 1) * x) ^ ((y>>1 & 1) * xTime(x)) ^ ((y>>2 & 1) * xTime(xTime(x))) ^ ((y>>3 & 1) + * xTime(xTime(xTime(x)))) ^ ((y>>4 & 1) * xTime(xTime(xTime(xTime(x)))))); +} + +} + +/* + * End Local functions + * */ + +QAESEncryption::QAESEncryption(Aes level, Mode mode, + Padding padding) + : m_nb(4), m_blocklen(16), m_level(level), m_mode(mode), m_padding(padding) + , m_aesNIAvailable(false), m_state(nullptr) +{ +#ifdef USE_INTEL_AES_IF_AVAILABLE + m_aesNIAvailable = check_aesni_support(); +#endif + + switch (level) + { + case AES_128: { + AES128 aes; + m_nk = aes.nk; + m_keyLen = aes.keylen; + m_nr = aes.nr; + m_expandedKey = aes.expandedKey; + } + break; + case AES_192: { + AES192 aes; + m_nk = aes.nk; + m_keyLen = aes.keylen; + m_nr = aes.nr; + m_expandedKey = aes.expandedKey; + } + break; + case AES_256: { + AES256 aes; + m_nk = aes.nk; + m_keyLen = aes.keylen; + m_nr = aes.nr; + m_expandedKey = aes.expandedKey; + } + break; + default: { + AES128 aes; + m_nk = aes.nk; + m_keyLen = aes.keylen; + m_nr = aes.nr; + m_expandedKey = aes.expandedKey; + } + break; + } + +} +QByteArray QAESEncryption::getPadding(int currSize, int alignment) +{ + int size = (alignment - currSize % alignment) % alignment; + switch(m_padding) + { + case Padding::ZERO: + return QByteArray(size, 0x00); + break; + case Padding::PKCS7: + if (size == 0) + size = alignment; + return QByteArray(size, size); + break; + case Padding::ISO: + if (size > 0) + return QByteArray (size - 1, 0x00).prepend('\x80'); + break; + default: + return QByteArray(size, 0x00); + break; + } + return QByteArray(); +} + +QByteArray QAESEncryption::expandKey(const QByteArray &key) +{ + +#ifdef USE_INTEL_AES_IF_AVAILABLE + if (true){ + switch(m_level) { + case AES_128: { + AES128 aes128; + quint8 ret[aes128.expandedKey]; + memset(ret, 0x00, sizeof(ret)); + quint8 uchar_key[key.size()]; + memcpy(uchar_key, key.data(), key.size()); + AES_128_Key_Expansion(uchar_key, ret); + return QByteArray((char*) ret, aes128.expandedKey); + } + break; + case AES_192: { + AES192 aes192; + quint8 ret[aes192.expandedKey]; + memset(ret, 0x00, sizeof(ret)); + quint8 uchar_key[key.size()]; + memcpy(uchar_key, key.data(), key.size()); + + AES_192_Key_Expansion(uchar_key, ret); + return QByteArray((char*) ret, aes192.expandedKey); + } + break; + case AES_256: { + AES256 aes256; + quint8 ret[aes256.expandedKey]; + memset(ret, 0x00, sizeof(ret)); + quint8 uchar_key[key.size()]; + memcpy(uchar_key, key.data(), key.size()); + + AES_256_Key_Expansion(uchar_key, ret); + return QByteArray((char*) ret, aes256.expandedKey); + } + break; + default: + return QByteArray(); + break; + } + } else +#endif + { + + int i, k; + quint8 tempa[4]; // Used for the column/row operations + QByteArray roundKey(key); // The first round key is the key itself. + + // All other round keys are found from the previous round keys. + //i == Nk + for(i = m_nk; i < m_nb * (m_nr + 1); i++) + { + tempa[0] = (quint8) roundKey.at((i-1) * 4 + 0); + tempa[1] = (quint8) roundKey.at((i-1) * 4 + 1); + tempa[2] = (quint8) roundKey.at((i-1) * 4 + 2); + tempa[3] = (quint8) roundKey.at((i-1) * 4 + 3); + + if (i % m_nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + k = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = k; + + // Function Subword() + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + + tempa[0] = tempa[0] ^ Rcon[i/m_nk]; + } + + if (m_level == AES_256 && i % m_nk == 4) + { + // Function Subword() + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + roundKey.insert(i * 4 + 0, (quint8) roundKey.at((i - m_nk) * 4 + 0) ^ tempa[0]); + roundKey.insert(i * 4 + 1, (quint8) roundKey.at((i - m_nk) * 4 + 1) ^ tempa[1]); + roundKey.insert(i * 4 + 2, (quint8) roundKey.at((i - m_nk) * 4 + 2) ^ tempa[2]); + roundKey.insert(i * 4 + 3, (quint8) roundKey.at((i - m_nk) * 4 + 3) ^ tempa[3]); + } + return roundKey; + } +} + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +void QAESEncryption::addRoundKey(const quint8 round, const QByteArray &expKey) +{ + QByteArray::iterator it = m_state->begin(); + for(int i=0; i < 16; ++i) + it[i] = (quint8) it[i] ^ (quint8) expKey.at(round * m_nb * 4 + (i/4) * m_nb + (i%4)); +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +void QAESEncryption::subBytes() +{ + QByteArray::iterator it = m_state->begin(); + for(int i = 0; i < 16; i++) + it[i] = getSBoxValue((quint8) it[i]); +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +void QAESEncryption::shiftRows() +{ + QByteArray::iterator it = m_state->begin(); + quint8 temp; + //Keep in mind that QByteArray is column-driven!! + + //Shift 1 to left + temp = (quint8)it[1]; + it[1] = (quint8)it[5]; + it[5] = (quint8)it[9]; + it[9] = (quint8)it[13]; + it[13] = (quint8)temp; + + //Shift 2 to left + temp = (quint8)it[2]; + it[2] = (quint8)it[10]; + it[10] = (quint8)temp; + temp = (quint8)it[6]; + it[6] = (quint8)it[14]; + it[14] = (quint8)temp; + + //Shift 3 to left + temp = (quint8)it[3]; + it[3] = (quint8)it[15]; + it[15] = (quint8)it[11]; + it[11] = (quint8)it[7]; + it[7] = (quint8)temp; +} + +// MixColumns function mixes the columns of the state matrix +//optimized!! +void QAESEncryption::mixColumns() +{ + QByteArray::iterator it = m_state->begin(); + quint8 tmp, tm, t; + + for(int i = 0; i < 16; i += 4){ + t = (quint8)it[i]; + tmp = (quint8)it[i] ^ (quint8)it[i+1] ^ (quint8)it[i+2] ^ (quint8)it[i+3] ; + + tm = xTime( (quint8)it[i] ^ (quint8)it[i+1] ); + it[i] = (quint8)it[i] ^ (quint8)tm ^ (quint8)tmp; + + tm = xTime( (quint8)it[i+1] ^ (quint8)it[i+2]); + it[i+1] = (quint8)it[i+1] ^ (quint8)tm ^ (quint8)tmp; + + tm = xTime( (quint8)it[i+2] ^ (quint8)it[i+3]); + it[i+2] =(quint8)it[i+2] ^ (quint8)tm ^ (quint8)tmp; + + tm = xTime((quint8)it[i+3] ^ (quint8)t); + it[i+3] =(quint8)it[i+3] ^ (quint8)tm ^ (quint8)tmp; + } +} + +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +void QAESEncryption::invMixColumns() +{ + QByteArray::iterator it = m_state->begin(); + quint8 a,b,c,d; + for(int i = 0; i < 16; i+=4){ + a = (quint8) it[i]; + b = (quint8) it[i+1]; + c = (quint8) it[i+2]; + d = (quint8) it[i+3]; + + it[i] = (quint8) (multiply(a, 0x0e) ^ multiply(b, 0x0b) ^ multiply(c, 0x0d) ^ multiply(d, 0x09)); + it[i+1] = (quint8) (multiply(a, 0x09) ^ multiply(b, 0x0e) ^ multiply(c, 0x0b) ^ multiply(d, 0x0d)); + it[i+2] = (quint8) (multiply(a, 0x0d) ^ multiply(b, 0x09) ^ multiply(c, 0x0e) ^ multiply(d, 0x0b)); + it[i+3] = (quint8) (multiply(a, 0x0b) ^ multiply(b, 0x0d) ^ multiply(c, 0x09) ^ multiply(d, 0x0e)); + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +void QAESEncryption::invSubBytes() +{ + QByteArray::iterator it = m_state->begin(); + for(int i = 0; i < 16; ++i) + it[i] = getSBoxInvert((quint8) it[i]); +} + +void QAESEncryption::invShiftRows() +{ + QByteArray::iterator it = m_state->begin(); + uint8_t temp; + + //Keep in mind that QByteArray is column-driven!! + + //Shift 1 to right + temp = (quint8)it[13]; + it[13] = (quint8)it[9]; + it[9] = (quint8)it[5]; + it[5] = (quint8)it[1]; + it[1] = (quint8)temp; + + //Shift 2 + temp = (quint8)it[10]; + it[10] = (quint8)it[2]; + it[2] = (quint8)temp; + temp = (quint8)it[14]; + it[14] = (quint8)it[6]; + it[6] = (quint8)temp; + + //Shift 3 + temp = (quint8)it[7]; + it[7] = (quint8)it[11]; + it[11] = (quint8)it[15]; + it[15] = (quint8)it[3]; + it[3] = (quint8)temp; +} + +QByteArray QAESEncryption::byteXor(const QByteArray &a, const QByteArray &b) +{ + QByteArray::const_iterator it_a = a.begin(); + QByteArray::const_iterator it_b = b.begin(); + QByteArray ret; + + //for(int i = 0; i < m_blocklen; i++) + for(int i = 0; i < std::min(a.size(), b.size()); i++) + ret.insert(i,it_a[i] ^ it_b[i]); + + return ret; +} + +// Cipher is the main function that encrypts the PlainText. +QByteArray QAESEncryption::cipher(const QByteArray &expKey, const QByteArray &in) +{ + + //m_state is the input buffer... + QByteArray output(in); + m_state = &output; + + // Add the First round key to the state before starting the rounds. + addRoundKey(0, expKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for(quint8 round = 1; round < m_nr; ++round){ + subBytes(); + shiftRows(); + mixColumns(); + addRoundKey(round, expKey); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + subBytes(); + shiftRows(); + addRoundKey(m_nr, expKey); + + return output; +} + +QByteArray QAESEncryption::invCipher(const QByteArray &expKey, const QByteArray &in) +{ + //m_state is the input buffer.... handle it! + QByteArray output(in); + m_state = &output; + + // Add the First round key to the state before starting the rounds. + addRoundKey(m_nr, expKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for(quint8 round=m_nr-1; round>0 ; round--){ + invShiftRows(); + invSubBytes(); + addRoundKey(round, expKey); + invMixColumns(); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + invShiftRows(); + invSubBytes(); + addRoundKey(0, expKey); + + return output; +} + +QByteArray QAESEncryption::printArray(uchar* arr, int size) +{ + QByteArray print(""); + for(int i=0; i<size; i++) + print.append(arr[i]); + + return print.toHex(); +} + +QByteArray QAESEncryption::encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv) +{ + if (m_mode >= CBC && (iv.isEmpty() || iv.size() != m_blocklen)) + return QByteArray(); + + QByteArray expandedKey = expandKey(key); + QByteArray alignedText(rawText); + + //Fill array with padding + alignedText.append(getPadding(rawText.size(), m_blocklen)); + + switch(m_mode) + { + case ECB: { +#ifdef USE_INTEL_AES_IF_AVAILABLE + if (m_aesNIAvailable){ + unsigned char in[alignedText.size()]; + memcpy(in, alignedText.data(), alignedText.size()); + unsigned char out[alignedText.size()]; + memcpy(out, alignedText.data(), alignedText.size()); + char expKey[expandedKey.size()]; + memcpy(expKey, expandedKey.data(), expandedKey.size()); + AES_ECB_encrypt(in, out, alignedText.size(), + expKey, m_nr); + return QByteArray((char*)out, alignedText.size()); + } +#endif + QByteArray ret; + for(int i=0; i < alignedText.size(); i+= m_blocklen) + ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen))); + return ret; + } + break; + case CBC: { +#ifdef USE_INTEL_AES_IF_AVAILABLE + if (m_aesNIAvailable){ + quint8 in[alignedText.size()]; + memcpy(in, alignedText.constData(), alignedText.size()); + quint8 ivec[iv.size()]; + memcpy(ivec, iv.data(), iv.size()); + char out[alignedText.size()]; + memset(out, 0x00, alignedText.size()); + char expKey[expandedKey.size()]; + memcpy(expKey, expandedKey.data(), expandedKey.size()); + AES_CBC_encrypt(in, + (unsigned char*) out, + ivec, + alignedText.size(), + expKey, + m_nr); + return QByteArray(out, alignedText.size()); + } +#endif + QByteArray ret; + QByteArray ivTemp(iv); + for(int i=0; i < alignedText.size(); i+= m_blocklen) { + alignedText.replace(i, m_blocklen, byteXor(alignedText.mid(i, m_blocklen),ivTemp)); + ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen))); + ivTemp = ret.mid(i, m_blocklen); + } + return ret; + } + break; + case CFB: { + QByteArray ret; + ret.append(byteXor(alignedText.left(m_blocklen), cipher(expandedKey, iv))); + for(int i=0; i < alignedText.size(); i+= m_blocklen) { + if (i+m_blocklen < alignedText.size()) + ret.append(byteXor(alignedText.mid(i+m_blocklen, m_blocklen), + cipher(expandedKey, ret.mid(i, m_blocklen)))); + } + return ret; + } + break; + case OFB: { + QByteArray ret; + QByteArray ofbTemp; + ofbTemp.append(cipher(expandedKey, iv)); + for (int i=m_blocklen; i < alignedText.size(); i += m_blocklen){ + ofbTemp.append(cipher(expandedKey, ofbTemp.right(m_blocklen))); + } + ret.append(byteXor(alignedText, ofbTemp)); + return ret; + } + break; + default: break; + } + return QByteArray(); +} + +QByteArray QAESEncryption::decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv) +{ + if (m_mode >= CBC && (iv.isEmpty() || iv.size() != m_blocklen)) + return QByteArray(); + + QByteArray ret; + QByteArray expandedKey = expandKey(key); + + switch(m_mode) + { + case ECB: + for(int i=0; i < rawText.size(); i+= m_blocklen) + ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen))); + break; + case CBC: { + QByteArray ivTemp(iv); + for(int i=0; i < rawText.size(); i+= m_blocklen){ + ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen))); + ret.replace(i, m_blocklen, byteXor(ret.mid(i, m_blocklen),ivTemp)); + ivTemp = rawText.mid(i, m_blocklen); + } + } + break; + case CFB: { + ret.append(byteXor(rawText.mid(0, m_blocklen), cipher(expandedKey, iv))); + for(int i=0; i < rawText.size(); i+= m_blocklen){ + if (i+m_blocklen < rawText.size()) { + ret.append(byteXor(rawText.mid(i+m_blocklen, m_blocklen), + cipher(expandedKey, rawText.mid(i, m_blocklen)))); + } + } + } + break; + case OFB: { + QByteArray ofbTemp; + ofbTemp.append(cipher(expandedKey, iv)); + for (int i=m_blocklen; i < rawText.size(); i += m_blocklen){ + ofbTemp.append(cipher(expandedKey, ofbTemp.right(m_blocklen))); + } + ret.append(byteXor(rawText, ofbTemp)); + } + break; + default: + //do nothing + break; + } + return ret; +} + +QByteArray QAESEncryption::removePadding(const QByteArray &rawText) +{ + return RemovePadding(rawText, (Padding) m_padding); +} diff --git a/src/ui/aes/qaesencryption.h b/src/ui/aes/qaesencryption.h new file mode 100644 index 00000000..cee70606 --- /dev/null +++ b/src/ui/aes/qaesencryption.h @@ -0,0 +1,155 @@ +#ifndef QAESENCRYPTION_H +#define QAESENCRYPTION_H + +#ifdef QtAES_EXPORTS +#include "qtaes_export.h" +#else +#define QTAESSHARED_EXPORT +#endif + +#include <QObject> +#include <QByteArray> + +#ifdef __linux__ +#ifndef __LP64__ +#define do_rdtsc _do_rdtsc +#endif +#endif + +class QTAESSHARED_EXPORT QAESEncryption : public QObject +{ + Q_OBJECT +public: + enum Aes { + AES_128, + AES_192, + AES_256 + }; + + enum Mode { + ECB, + CBC, + CFB, + OFB + }; + + enum Padding { + ZERO, + PKCS7, + ISO + }; + + static QByteArray Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key, + const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO); + static QByteArray Decrypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key, + const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO); + static QByteArray ExpandKey(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &key); + static QByteArray RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding = QAESEncryption::ISO); + + QAESEncryption(QAESEncryption::Aes level, QAESEncryption::Mode mode, + QAESEncryption::Padding padding = QAESEncryption::ISO); + + QByteArray encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray()); + QByteArray decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray()); + QByteArray removePadding(const QByteArray &rawText); + QByteArray expandKey(const QByteArray &key); + + QByteArray printArray(uchar *arr, int size); +Q_SIGNALS: + +public Q_SLOTS: + +private: + int m_nb; + int m_blocklen; + int m_level; + int m_mode; + int m_nk; + int m_keyLen; + int m_nr; + int m_expandedKey; + int m_padding; + bool m_aesNIAvailable; + QByteArray* m_state; + + struct AES256{ + int nk = 8; + int keylen = 32; + int nr = 14; + int expandedKey = 240; + }; + + struct AES192{ + int nk = 6; + int keylen = 24; + int nr = 12; + int expandedKey = 209; + }; + + struct AES128{ + int nk = 4; + int keylen = 16; + int nr = 10; + int expandedKey = 176; + }; + + quint8 getSBoxValue(quint8 num){return sbox[num];} + quint8 getSBoxInvert(quint8 num){return rsbox[num];} + + void addRoundKey(const quint8 round, const QByteArray &expKey); + void subBytes(); + void shiftRows(); + void mixColumns(); + void invMixColumns(); + void invSubBytes(); + void invShiftRows(); + QByteArray getPadding(int currSize, int alignment); + QByteArray cipher(const QByteArray &expKey, const QByteArray &in); + QByteArray invCipher(const QByteArray &expKey, const QByteArray &in); + QByteArray byteXor(const QByteArray &a, const QByteArray &b); + + const quint8 sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + + const quint8 rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; + + // The round constant word array, Rcon[i], contains the values given by + // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) + // Only the first 14 elements are needed + const quint8 Rcon[14] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab}; +}; + +#endif // QAESENCRYPTION_H diff --git a/src/ui/keypair_details/KeyUIDSignDialog.cpp b/src/ui/keypair_details/KeyUIDSignDialog.cpp index eb459701..b43a119e 100644 --- a/src/ui/keypair_details/KeyUIDSignDialog.cpp +++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp @@ -34,7 +34,7 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, QWidget* parent) : QDialog(parent), mUids(std::move(uid)), mKey(key) { const auto key_id = mKey.id(); - mKeyList = new KeyList(false, this); + mKeyList = new KeyList(KeyMenuAbility::NONE, this); mKeyList->addListGroupTab(_("Signers"), KeyListRow::ONLY_SECRET_KEY, KeyListColumn::NAME | KeyListColumn::EmailAddress, [key_id](const GpgKey& key) -> bool { diff --git a/src/ui/smtp/RecipientsPicker.cpp b/src/ui/smtp/RecipientsPicker.cpp index ee6ac673..eaaa683a 100644 --- a/src/ui/smtp/RecipientsPicker.cpp +++ b/src/ui/smtp/RecipientsPicker.cpp @@ -33,7 +33,7 @@ GpgFrontend::UI::RecipientsPicker::RecipientsPicker( connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept())); // Setup KeyList - key_list_ = new KeyList(false, this); + key_list_ = new KeyList(KeyMenuAbility::NONE, this); key_list_->addListGroupTab( _("Recipient(s)"), KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::NAME | KeyListColumn::EmailAddress, diff --git a/src/ui/smtp/SenderPicker.cpp b/src/ui/smtp/SenderPicker.cpp index 1cbd409f..fcd3ba61 100644 --- a/src/ui/smtp/SenderPicker.cpp +++ b/src/ui/smtp/SenderPicker.cpp @@ -33,7 +33,7 @@ GpgFrontend::UI::SenderPicker::SenderPicker(const KeyId& current_key_id, connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept())); // Setup KeyList - key_list_ = new KeyList(false, this); + key_list_ = new KeyList(KeyMenuAbility::NONE, this); key_list_->addListGroupTab( _("Sender"), KeyListRow::ONLY_SECRET_KEY, KeyListColumn::NAME | KeyListColumn::EmailAddress, diff --git a/src/ui/widgets/ExportKeyPackageDialog.cpp b/src/ui/widgets/ExportKeyPackageDialog.cpp new file mode 100644 index 00000000..b5eea82d --- /dev/null +++ b/src/ui/widgets/ExportKeyPackageDialog.cpp @@ -0,0 +1,165 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "ExportKeyPackageDialog.h" + +#include <boost/format.hpp> + +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExporter.h" +#include "ui/aes/qaesencryption.h" +#include "ui_ExportKeyPackageDialog.h" + +GpgFrontend::UI::ExportKeyPackageDialog::ExportKeyPackageDialog( + KeyIdArgsListPtr key_ids, QWidget* parent) + : QDialog(parent), + ui(std::make_shared<Ui_exportKeyPackageDialog>()), + key_ids_(std::move(key_ids)), + mt(rd()) { + ui->setupUi(this); + + generate_key_package_name(); + + connect(ui->gnerateNameButton, &QPushButton::clicked, this, + [=]() { generate_key_package_name(); }); + + connect(ui->setOutputPathButton, &QPushButton::clicked, this, [=]() { + auto file_name = QFileDialog::getSaveFileName( + this, _("Export Key Package"), ui->nameValueLabel->text() + ".gfepack", + QString(_("Key Package")) + " (*.gfepack);;All Files (*)"); + ui->outputPathLabel->setText(file_name); + }); + + connect(ui->generatePassphraseButton, &QPushButton::clicked, this, [=]() { + passphrase_ = generate_passphrase(32); + auto file_name = QFileDialog::getSaveFileName( + this, _("Export Key Package Passphrase"), + ui->nameValueLabel->text() + ".key", + QString(_("Key File")) + " (*.key);;All Files (*)"); + ui->passphraseValueLabel->setText(file_name); + write_buffer_to_file(file_name.toStdString(), passphrase_); + }); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, [=]() { + if (ui->outputPathLabel->text().isEmpty()) { + QMessageBox::critical( + nullptr, _("Forbidden"), + _("Please select an output path before exporting.")); + return; + } + + if (ui->passphraseValueLabel->text().isEmpty()) { + QMessageBox::critical( + nullptr, _("Forbidden"), + _("Please generate a password to protect your key before exporting, " + "it is very important. Don't forget to back up your password in a " + "safe place.")); + return; + } + auto key_id_exported = std::make_unique<KeyIdArgsList>(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids_); + for (const auto& key : *keys) { + if (ui->noPublicKeyCheckBox->isChecked() && !key.is_private_key()) { + continue; + } + key_id_exported->push_back(key.id()); + } + + ByteArrayPtr key_export_data = nullptr; + if (!GpgKeyImportExporter::GetInstance().ExportKeys( + key_ids_, key_export_data, + ui->includeSecretKeyCheckBox->isChecked())) { + QMessageBox::critical(nullptr, _("Error"), _("Export Key(s) Failed.")); + this->close(); + return; + } + + auto key = passphrase_; + + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB); + auto encoded = encryption.encode(key_export_data->data(), key.data()); + + write_buffer_to_file(ui->outputPathLabel->text().toStdString(), + encoded.toStdString()); + + QMessageBox::information( + this, _("Success"), + QString(_( + "The Key Package has been successfully generated and has been " + "protected by encryption algorithms. You can safely transfer your " + "Key Package.")) + + "<b>" + + _("But the key file cannot be leaked under any " + "circumstances. Please delete the Key Package and key file as " + "soon " + "as possible after completing the transfer operation") + + "</b>"); + }); + + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, + [=]() { this->close(); }); + + ui->nameLabel->setText(_("Key Package Name")); + ui->selectOutputPathLabel->setText(_("Output Path")); + ui->passphraseLabel->setText(_("Passphrase")); + ui->tipsLabel->setText( + _("Tips: You can use Key Package to safely and conveniently transfer " + "your public and private keys between devices.")); + ui->generatePassphraseButton->setText(_("Generate and Save Passphrase")); + ui->gnerateNameButton->setText(_("Generate Key Package Name")); + ui->setOutputPathButton->setText(_("Select Output Path")); + + ui->includeSecretKeyCheckBox->setText( + _("Include secret key (Think twice before acting)")); + ui->noPublicKeyCheckBox->setText( + _("Exclude keys that do not have a private key")); + + setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(_("exportKeyPackageDialog")); +} + +std::string GpgFrontend::UI::ExportKeyPackageDialog::generate_passphrase( + const int len) { + std::uniform_int_distribution<int> dist(999, 99999); + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + std::string tmp_str; + tmp_str.reserve(len); + + for (int i = 0; i < len; ++i) { + tmp_str += alphanum[dist(mt) % (sizeof(alphanum) - 1)]; + } + + return tmp_str; +} + +void GpgFrontend::UI::ExportKeyPackageDialog::generate_key_package_name() { + std::uniform_int_distribution<int> dist(999, 99999); + auto file_string = boost::format("KeyPackage_%1%") % dist(mt); + ui->nameValueLabel->setText(file_string.str().c_str()); + ui->outputPathLabel->clear(); + ui->passphraseValueLabel->clear(); +} diff --git a/src/ui/widgets/ExportKeyPackageDialog.h b/src/ui/widgets/ExportKeyPackageDialog.h new file mode 100644 index 00000000..a254b453 --- /dev/null +++ b/src/ui/widgets/ExportKeyPackageDialog.h @@ -0,0 +1,55 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H +#define GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H + +#include "GpgFrontendUI.h" + +class Ui_exportKeyPackageDialog; + +namespace GpgFrontend::UI { + +class ExportKeyPackageDialog : public QDialog { + Q_OBJECT + + public: + explicit ExportKeyPackageDialog(KeyIdArgsListPtr key_ids, QWidget* parent); + + std::string generate_passphrase(const int len); + + private: + std::shared_ptr<Ui_exportKeyPackageDialog> ui; + KeyIdArgsListPtr key_ids_; + + std::random_device rd; + std::mt19937 mt; + + std::string passphrase_; + + void generate_key_package_name(); +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index 6dec19e7..02a8dd92 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -38,11 +38,11 @@ namespace GpgFrontend::UI { int KeyList::key_list_id = 2048; -KeyList::KeyList(bool menu, QWidget* parent) +KeyList::KeyList(KeyMenuAbility::AbilityType menu_ability, QWidget* parent) : QWidget(parent), _m_key_list_id(key_list_id++), ui(std::make_shared<Ui_KeyList>()), - menu_status(menu) { + menu_ability_(menu_ability) { init(); } @@ -62,7 +62,11 @@ void KeyList::init() { ui->setupUi(this); - ui->menuWidget->setHidden(!menu_status); + ui->menuWidget->setHidden(!menu_ability_); + ui->refreshKeyListButton->setHidden(~menu_ability_ & KeyMenuAbility::REFRESH); + ui->syncButton->setHidden(~menu_ability_ & KeyMenuAbility::SYNC_PUBLIC_KEY); + ui->uncheckButton->setHidden(~menu_ability_ & KeyMenuAbility::UNCHECK_ALL); + ui->keyGroupTab->clear(); popupMenu = new QMenu(this); @@ -73,6 +77,10 @@ void KeyList::init() { SLOT(slotRefresh())); connect(ui->refreshKeyListButton, &QPushButton::clicked, this, &KeyList::slotRefresh); + connect(ui->uncheckButton, &QPushButton::clicked, this, + &KeyList::slotUncheckALL); + connect(ui->checkALLButton, &QPushButton::clicked, this, + &KeyList::slotCheckALL); connect(ui->syncButton, &QPushButton::clicked, this, &KeyList::slotSyncWithKeyServer); connect(this, &KeyList::signalRefreshStatusBar, SignalStation::GetInstance(), @@ -81,8 +89,16 @@ void KeyList::init() { setAcceptDrops(true); ui->refreshKeyListButton->setText(_("Refresh")); + ui->refreshKeyListButton->setToolTip( + _("Refresh the key list to synchronize changes.")); ui->syncButton->setText(_("Sync Public Key")); - ui->syncButton->setToolTip(_("Sync public key with your default keyserver")); + ui->syncButton->setToolTip(_("Sync public key with your default keyserver.")); + ui->uncheckButton->setText(_("Uncheck ALL")); + ui->uncheckButton->setToolTip( + _("Cancel all checked items in the current tab at once.")); + ui->checkALLButton->setText(_("Check ALL")); + ui->checkALLButton->setToolTip( + _("Check all items in the current tab at once")); } void KeyList::addListGroupTab( @@ -457,6 +473,32 @@ void KeyList::slotSyncWithKeyServer() { }); } +void KeyList::slotUncheckALL() { + auto key_list = qobject_cast<QTableWidget*>(ui->keyGroupTab->currentWidget()); + if (key_list == nullptr) return; + if (!mKeyTables.empty()) { + for (auto& key_table : mKeyTables) { + if (key_table.key_list == key_list) { + key_table.UncheckALL(); + break; + } + } + } +} + +void KeyList::slotCheckALL() { + auto key_list = qobject_cast<QTableWidget*>(ui->keyGroupTab->currentWidget()); + if (key_list == nullptr) return; + if (!mKeyTables.empty()) { + for (auto& key_table : mKeyTables) { + if (key_table.key_list == key_list) { + key_table.CheckALL(); + break; + } + } + } +} + KeyIdArgsListPtr& KeyTable::GetChecked() { LOG(INFO) << "called"; if (checked_key_ids_ == nullptr) @@ -597,4 +639,16 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { LOG(INFO) << "End"; } + +void KeyTable::UncheckALL() const { + for (int i = 0; i < key_list->rowCount(); i++) { + key_list->item(i, 0)->setCheckState(Qt::Unchecked); + } +} + +void KeyTable::CheckALL() const { + for (int i = 0; i < key_list->rowCount(); i++) { + key_list->item(i, 0)->setCheckState(Qt::Checked); + } +} } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h index 8d6fb600..4b41decd 100644 --- a/src/ui/widgets/KeyList.h +++ b/src/ui/widgets/KeyList.h @@ -53,6 +53,17 @@ struct KeyListColumn { static constexpr InfoType FingerPrint = 1 << 5; }; +struct KeyMenuAbility { + using AbilityType = unsigned int; + + static constexpr AbilityType ALL = ~0; + static constexpr AbilityType NONE = 0; + static constexpr AbilityType REFRESH = 1 << 0; + static constexpr AbilityType SYNC_PUBLIC_KEY = 1 << 1; + static constexpr AbilityType UNCHECK_ALL = 1 << 3; + static constexpr AbilityType CHECK_ALL = 1 << 5; +}; + struct KeyTable { QTableWidget* key_list; KeyListRow::KeyType select_type; @@ -76,6 +87,10 @@ struct KeyTable { KeyIdArgsListPtr& GetChecked(); + void UncheckALL() const; + + void CheckALL() const; + void SetChecked(KeyIdArgsListPtr key_ids); }; @@ -83,7 +98,8 @@ class KeyList : public QWidget { Q_OBJECT public: - explicit KeyList(bool menu, QWidget* parent = nullptr); + explicit KeyList(KeyMenuAbility::AbilityType menu_ability, + QWidget* parent = nullptr); void addListGroupTab( const QString& name, @@ -124,6 +140,8 @@ class KeyList : public QWidget { private: void init(); void importKeys(const QByteArray& inBuffer); + void slotUncheckALL(); + void slotCheckALL(); static int key_list_id; int _m_key_list_id; @@ -135,7 +153,7 @@ class KeyList : public QWidget { QMenu* popupMenu{}; GpgFrontend::KeyLinkListPtr _buffered_keys_list; std::function<void(const GpgKey&, QWidget*)> mAction = nullptr; - bool menu_status = false; + KeyMenuAbility::AbilityType menu_ability_ = KeyMenuAbility::ALL; private slots: diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index f7c031b7..01e8c2ca 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -1,4 +1,4 @@ -if (ESAY_LOGGING_PP) +if (EASY_LOGGING_PP) message(STATUS "Build easyloggingpp") add_subdirectory(easyloggingpp) endif () diff --git a/ui/ExportKeyPackageDialog.ui b/ui/ExportKeyPackageDialog.ui new file mode 100644 index 00000000..a40d0154 --- /dev/null +++ b/ui/ExportKeyPackageDialog.ui @@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>exportKeyPackageDialog</class> + <widget class="QDialog" name="exportKeyPackageDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>527</width> + <height>385</height> + </rect> + </property> + <property name="windowTitle"> + <string>Export As Key Package</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="nameLabel"> + <property name="text"> + <string>Key Package Name</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="gnerateNameButton"> + <property name="text"> + <string>Generate Key Package Name</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="nameValueLabel"> + <property name="text"> + <string>KeyPackage_0000</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="selectOutputPathLabel"> + <property name="text"> + <string>Output Path</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="setOutputPathButton"> + <property name="text"> + <string>Select Output Path</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="outputPathLabel"> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="passphraseLabel"> + <property name="text"> + <string>Passphrase</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="generatePassphraseButton"> + <property name="text"> + <string>Generate and Save Passphrase</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="passphraseValueLabel"> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="includeSecretKeyCheckBox"> + <property name="text"> + <string>Include secret key (Think twice before acting)</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="noPublicKeyCheckBox"> + <property name="text"> + <string>Exclude keys that do not have a private key</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="tipsLabel"> + <property name="text"> + <string>Tips: You can use Key Package to safely and conveniently transfer your public and private keys between devices.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>exportKeyPackageDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>exportKeyPackageDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/ui/KeyList.ui b/ui/KeyList.ui index 9e41a0d1..d24a2825 100644 --- a/ui/KeyList.ui +++ b/ui/KeyList.ui @@ -46,7 +46,21 @@ <item> <widget class="QPushButton" name="syncButton"> <property name="text"> - <string>Sync With Key Server</string> + <string>Sync Public Key</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="uncheckButton"> + <property name="text"> + <string>Uncheck ALL</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="checkALLButton"> + <property name="text"> + <string>Check ALL</string> </property> </widget> </item> |