<feature, refactor>(core, ui): Key package generate.

1. refactor GpgKeyImportExporter to meet with key package generation.
2. add ExportKeyPackageDialog.
3. add Qt AES ability.
4. refactor Key List to provide menu ability control.
5. add check all and uncheck all ability to key list menu.
This commit is contained in:
Saturneric 2022-01-04 01:25:59 +08:00
parent efabb4fa3d
commit c20c7b9bb8
22 changed files with 1382 additions and 83 deletions

View File

@ -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)

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -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)

View File

@ -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);
}
/**

View File

@ -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;

View File

@ -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)

View File

@ -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)) {
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;
}
auto key =
GpgKeyGetter::GetInstance().GetKey(mKeyList->getSelected()->front());
if (!key.good()) {
QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
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."));

View File

@ -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{};

View File

@ -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);

View File

@ -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);
}

155
src/ui/aes/qaesencryption.h Normal file
View File

@ -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

View File

@ -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 {

View File

@ -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,

View File

@ -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,

View File

@ -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<eric@bktus.com> 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();
}

View File

@ -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<eric@bktus.com> 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

View File

@ -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

View File

@ -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:

View File

@ -1,4 +1,4 @@
if (ESAY_LOGGING_PP)
if (EASY_LOGGING_PP)
message(STATUS "Build easyloggingpp")
add_subdirectory(easyloggingpp)
endif ()

View File

@ -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>

View File

@ -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>