From 6cc259e9d623f35c8ee6fec3332370d6a78f2625 Mon Sep 17 00:00:00 2001 From: FireFish <54362633+FishCMD@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:23:58 +0800 Subject: [PATCH] Add files via upload --- PasswordManager.cpp | 267 +++++++++++++ PasswordManager.h | 58 +++ PasswordManager.qrc | 4 + PasswordManager.sln | 25 ++ PasswordManager.ui | 633 +++++++++++++++++++++++++++++ PasswordManager.vcxproj | 115 ++++++ PasswordManager.vcxproj.filters | 60 +++ PasswordManager.vcxproj.user | 12 + data.cpp | 62 +++ data.h | 12 + main.cpp | 13 + qaesencryption.cpp | 688 ++++++++++++++++++++++++++++++++ qaesencryption.h | 225 +++++++++++ 13 files changed, 2174 insertions(+) create mode 100644 PasswordManager.cpp create mode 100644 PasswordManager.h create mode 100644 PasswordManager.qrc create mode 100644 PasswordManager.sln create mode 100644 PasswordManager.ui create mode 100644 PasswordManager.vcxproj create mode 100644 PasswordManager.vcxproj.filters create mode 100644 PasswordManager.vcxproj.user create mode 100644 data.cpp create mode 100644 data.h create mode 100644 main.cpp create mode 100644 qaesencryption.cpp create mode 100644 qaesencryption.h diff --git a/PasswordManager.cpp b/PasswordManager.cpp new file mode 100644 index 0000000..78b7c51 --- /dev/null +++ b/PasswordManager.cpp @@ -0,0 +1,267 @@ +#pragma execution_character_set("utf-8") + +#include "PasswordManager.h" +#include "data.h" +#include + +#define t(str) QString::fromUtf8(str) + +PasswordManager::PasswordManager(QWidget* parent) + : QMainWindow(parent) +{ + ui.setupUi(this); + ui.password_entry->setEchoMode(QLineEdit::Password); + isSaved = true; + + item = new QStandardItem(); + + model=new QStandardItemModel(); + ui.tableView->setModel(model); + + clear_data(); + + ui.statusBar->addPermanentWidget(new QLabel(t("PasswordManager 0.0.1"))); + + update_state(none); +} +void PasswordManager::update_state(enum STATE new_state) { + state = new_state; + switch (state) { + case none:{ + ui.actionSave->setEnabled(false); + ui.actionSaveAs->setEnabled(false); + + ui.save_file->setEnabled(false); + ui.password_entry->setEnabled(false); + ui.view_button->setEnabled(false); + ui.confirm_password->setEnabled(false); + ui.reset_password->setEnabled(false); + ui.tableView->setEnabled(false); + ui.copy_username->setEnabled(false); + ui.copy_password->setEnabled(false); + ui.push_button->setEnabled(false); + ui.delete_button->setEnabled(false); + + ui.statusBar->showMessage(t("打开或创建一个文件")); + break; + } + case newFile: { + ui.actionSave->setEnabled(false); + ui.actionSaveAs->setEnabled(false); + + ui.save_file->setEnabled(false); + ui.password_entry->setEnabled(false); + ui.view_button->setEnabled(false); + ui.confirm_password->setEnabled(false); + ui.reset_password->setEnabled(true); + ui.tableView->setEnabled(false); + ui.copy_username->setEnabled(false); + ui.copy_password->setEnabled(false); + ui.push_button->setEnabled(false); + ui.delete_button->setEnabled(false); + + ui.statusBar->showMessage(t("创建密码本 请设置密码")); + break; + } + case openFile: { + ui.actionSave->setEnabled(false); + ui.actionSaveAs->setEnabled(false); + + ui.save_file->setEnabled(false); + ui.password_entry->setEnabled(true); + ui.view_button->setEnabled(true); + ui.confirm_password->setEnabled(true); + ui.reset_password->setEnabled(false); + ui.tableView->setEnabled(false); + ui.copy_username->setEnabled(false); + ui.copy_password->setEnabled(false); + ui.push_button->setEnabled(false); + ui.delete_button->setEnabled(false); + + ui.statusBar->showMessage(t("打开密码本 请输入密码")); + break; + } + case unlocked: { + ui.actionSave->setEnabled(true); + ui.actionSaveAs->setEnabled(true); + + ui.save_file->setEnabled(true); + ui.password_entry->setEnabled(false); + ui.view_button->setEnabled(false); + ui.confirm_password->setEnabled(false); + ui.reset_password->setEnabled(true); + ui.tableView->setEnabled(true); + ui.copy_username->setEnabled(true); + ui.copy_password->setEnabled(true); + ui.push_button->setEnabled(true); + ui.delete_button->setEnabled(true); + + ui.statusBar->showMessage(t("双击以编辑 单击显示密码")); + break; + } + } +} + +void PasswordManager::clear_data() { + QString2QModel(QString(), model); + ui.tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + ui.tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); + ui.tableView->setColumnWidth(0, 150); + ui.password_entry->clear(); + key = QString(); + item = new QStandardItem(); +} + +void PasswordManager::on_set_password() { + bool confirm1 = false; + bool confirm2 = false; + QString first_key=QInputDialog::getText(this, t("设置密码"), t("输入新密码:"), QLineEdit::Password, "", &confirm1); + if (!confirm1)return; + if (first_key.isEmpty()) { + if (QMessageBox::critical(this, t("设置密码"), t("密码不能为空!"), QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Retry) on_set_password(); + return; + } + QString second_key= QInputDialog::getText(this, t("设置密码"), t("确认密码:"), QLineEdit::Password, "", &confirm2); + if (!confirm2)return; + if (first_key == second_key) { + key = first_key; + ui.password_entry->setText(key); + update_state(unlocked); + isSaved = false; + ui.statusBar->showMessage(t("成功设置密码"), 3000); + } + else { + if (QMessageBox::critical(this, t("设置密码"), t("两次输入密码不一致"), QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Retry) on_set_password(); + return; + } +} + +void PasswordManager::on_select_file() { + if (!ask_save_file())return; + path = QFileDialog::getOpenFileName(this, t("打开密码本文件"), "", t("密码本文件(*.password);;所有文件(*.*)")); + if (path.isEmpty()) return; + ui.file_path->setText(path); + clear_data(); + update_state(openFile); +} + +void PasswordManager::on_new_file() { + if (!ask_save_file())return; + path = QFileDialog::getSaveFileName(this, t("打开密码本文件"), "", t("密码本文件(*.password)")); + if (path.isEmpty()) return; + ui.file_path->setText(path); + clear_data(); + update_state(newFile); + on_set_password(); +} + +void PasswordManager::on_save_file(){ + item->setData(item->text(), Qt::UserRole); + item = new QStandardItem(); + if (saveData(path, model, key)) { + ui.statusBar->showMessage(t("保存成功"), 3000); + isSaved = true; + } + else { + ui.statusBar->showMessage(t("保存失败"), 3000); + } +} + +void PasswordManager::on_save_as_file() { + QString _path = QFileDialog::getSaveFileName(this, t("打开密码本文件"), "", t("密码本文件(*.password)")); + if (_path.isEmpty()) return; + path = _path; + ui.file_path->setText(path); + on_save_file(); +} + +void PasswordManager::on_show_password() { + ui.password_entry->setEchoMode(QLineEdit::Normal); +} + +void PasswordManager::on_hide_password() { + ui.password_entry->setEchoMode(QLineEdit::Password); +} + +void PasswordManager::on_confirm_password() { + key = ui.password_entry->text(); + if (key.isEmpty()) { + QMessageBox::critical(this, t("输入密码"), t("请输入密码!"), QMessageBox::Ok); + return; + } + if (readData(path, model, key))update_state(unlocked); + else ui.statusBar->showMessage(t("密码错误 请重试")); +} + +void PasswordManager::add_data(QString platform,QString username,QString password){ + model->appendRow({ new QStandardItem(platform),new QStandardItem(username),new QStandardItem(password) }); +} + +void PasswordManager::on_push_new() { + PasswordManager::add_data("", "", ""); + isSaved = false; +} + +void PasswordManager::on_remove_row() { + QModelIndexList item = ui.tableView->selectionModel()->selectedIndexes(); + if (item.length() == 1) model->removeRow(item.at(0).row()); + else ui.statusBar->showMessage(t("请选中项目"), 2000); + isSaved = false; +} + +void PasswordManager::on_view(QModelIndex index) { + item->setData(item->text(), Qt::UserRole); + item = new QStandardItem(); + if (index.column() != 2)return; + QStandardItem *_item = model->item(index.row(), index.column()); + if (_item->text() == _item->data(Qt::UserRole))_item->setText(_item->data(Qt::UserRole).toString().fill('*')); + else _item->setText(_item->data(Qt::UserRole).toString()); +} + +void PasswordManager::on_edit(QModelIndex index) { + isSaved = false; + if (index.column() != 2)return; + item = model->item(index.row(), index.column()); + item->setText(item->data(Qt::UserRole).toString()); +} + +void PasswordManager::on_menu(QAction* action) { + if (action->objectName() == "actionNew")PasswordManager::on_new_file(); + if (action->objectName() == "actionOpen")PasswordManager::on_select_file(); + if (action->objectName() == "actionSave")PasswordManager::on_save_file(); + if (action->objectName() == "actionSaveAs")PasswordManager::on_save_as_file(); +} + +void PasswordManager::on_copy_username(){ + QModelIndexList item = ui.tableView->selectionModel()->selectedIndexes(); + if (item.length() == 1) { + clipboard->setText(model->item(item.at(0).row(), 1)->text()); + ui.statusBar->showMessage(t("复制用户名成功"),2000); + } + else ui.statusBar->showMessage(t("请选中项目"), 2000); +} + +void PasswordManager::on_copy_password() { + QModelIndexList item = ui.tableView->selectionModel()->selectedIndexes(); + if (item.length() == 1) { + clipboard->setText(model->item(item.at(0).row(), 2)->data(Qt::UserRole).toString()); + ui.statusBar->showMessage(t("复制密码成功"), 2000); + } + else ui.statusBar->showMessage(t("请选中项目"), 2000); +} + +bool PasswordManager::ask_save_file() { + if (isSaved)return true; + switch (QMessageBox::question(this, t("保存文件"), t("文件未保存,是否保存?"), QMessageBox::Save|QMessageBox::No|QMessageBox::Cancel,QMessageBox::Save)) { + case QMessageBox::Save:on_save_file();isSaved=true; return true; + case QMessageBox::No:isSaved = true; return true; + default:return false; + } +} + +void PasswordManager::closeEvent(QCloseEvent* event) { + if (!ask_save_file())event->ignore(); +} + +PasswordManager::~PasswordManager() +{} diff --git a/PasswordManager.h b/PasswordManager.h new file mode 100644 index 0000000..4f6a56d --- /dev/null +++ b/PasswordManager.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "ui_PasswordManager.h" +#include + +class PasswordManager : public QMainWindow +{ + Q_OBJECT + +public: + PasswordManager(QWidget* parent = nullptr); + ~PasswordManager(); + void closeEvent(QCloseEvent* event); + +private: + enum STATE { + none, + newFile, + openFile, + unlocked + } state; + +private slots: + void on_select_file(); + void on_new_file(); + void on_save_file(); + void on_save_as_file(); + void on_show_password(); + void on_hide_password(); + void on_confirm_password(); + void add_data(QString platform, QString username, QString password); + void on_push_new(); + void on_remove_row(); + void on_menu(QAction* action); + void on_set_password(); + void update_state(enum STATE new_state); + void clear_data(); + void on_view(QModelIndex index); + void on_edit(QModelIndex index); + void on_copy_username(); + void on_copy_password(); + +private: + Ui::PasswordManagerClass ui; + QClipboard* clipboard=QApplication::clipboard(); + QStandardItemModel *model; + QString path; + QString key; + QStandardItem *item; + bool isSaved; + bool ask_save_file(); +}; diff --git a/PasswordManager.qrc b/PasswordManager.qrc new file mode 100644 index 0000000..cf46f1a --- /dev/null +++ b/PasswordManager.qrc @@ -0,0 +1,4 @@ + + + + diff --git a/PasswordManager.sln b/PasswordManager.sln new file mode 100644 index 0000000..29c290e --- /dev/null +++ b/PasswordManager.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33723.286 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PasswordManager", "PasswordManager.vcxproj", "{F1077C8C-16FF-4890-A625-F35C76ABC156}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F1077C8C-16FF-4890-A625-F35C76ABC156}.Debug|x64.ActiveCfg = Debug|x64 + {F1077C8C-16FF-4890-A625-F35C76ABC156}.Debug|x64.Build.0 = Debug|x64 + {F1077C8C-16FF-4890-A625-F35C76ABC156}.Release|x64.ActiveCfg = Release|x64 + {F1077C8C-16FF-4890-A625-F35C76ABC156}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {41E4EABC-9043-4544-A413-681241D25FC9} + EndGlobalSection +EndGlobal diff --git a/PasswordManager.ui b/PasswordManager.ui new file mode 100644 index 0000000..a0d9e4f --- /dev/null +++ b/PasswordManager.ui @@ -0,0 +1,633 @@ + + + PasswordManagerClass + + + + 0 + 0 + 700 + 400 + + + + PasswordManager + + + + + + + + + + + + 11 + + + + 选择文件: + + + + + + + true + + + + 11 + + + + QLineEdit::EchoMode::Normal + + + true + + + + + + + + 11 + + + + 打开 + + + + + + + + 11 + + + + 新建 + + + + + + + + 11 + + + + 保存 + + + + + + + + + + + + 11 + + + + 输入密码: + + + + + + + + 11 + + + + + + + + + 11 + + + + 显示 + + + + + + + + 11 + + + + 确定 + + + + + + + + 11 + + + + 设置密码 + + + + + + + + + true + + + + 11 + + + + false + + + Qt::ScrollBarPolicy::ScrollBarAsNeeded + + + QAbstractItemView::EditTrigger::DoubleClicked + + + QAbstractItemView::SelectionMode::SingleSelection + + + QAbstractItemView::ScrollMode::ScrollPerPixel + + + QAbstractItemView::ScrollMode::ScrollPerPixel + + + + + + + + + + + + 100 + 0 + + + + + 11 + + + + 复制用户名 + + + + + + + + 100 + 0 + + + + + 11 + + + + 复制密码 + + + + + + + + + Qt::Orientation::Horizontal + + + + 298 + 20 + + + + + + + + + + + 11 + + + + 添加 + + + + + + + + 11 + + + + 删除 + + + + + + + + + + + + + + + 10 + + + + + + + + + + 0 + 0 + 700 + 33 + + + + + 文件 + + + + + + + + + + + + + + 新建 + + + 新建 + + + Ctrl+N + + + + + + + + 打开 + + + 打开 + + + Ctrl+O + + + + + + + + 保存 + + + 保存 + + + Ctrl+S + + + + + + + + 另存为 + + + 另存为 + + + + + + + + + + select_file + clicked() + PasswordManagerClass + on_select_file() + + + 478 + 57 + + + 544 + 34 + + + + + new_file + clicked() + PasswordManagerClass + on_new_file() + + + 570 + 51 + + + 636 + 37 + + + + + confirm_password + clicked() + PasswordManagerClass + on_confirm_password() + + + 579 + 93 + + + 579 + 111 + + + + + view_button + pressed() + PasswordManagerClass + on_show_password() + + + 454 + 82 + + + 529 + 76 + + + + + view_button + released() + PasswordManagerClass + on_hide_password() + + + 467 + 98 + + + 543 + 76 + + + + + push_button + clicked() + PasswordManagerClass + on_push_new() + + + 551 + 351 + + + 466 + 369 + + + + + delete_button + clicked() + PasswordManagerClass + on_remove_row() + + + 642 + 361 + + + 643 + 371 + + + + + menuBar + triggered(QAction*) + PasswordManagerClass + on_menu(QAction*) + + + 21 + 12 + + + 25 + 39 + + + + + save_file + clicked() + PasswordManagerClass + on_save_file() + + + 678 + 56 + + + 690 + 78 + + + + + reset_password + clicked() + PasswordManagerClass + on_set_password() + + + 677 + 100 + + + 697 + 107 + + + + + tableView + activated(QModelIndex) + PasswordManagerClass + on_view(QModelIndex) + + + 240 + 237 + + + 240 + 343 + + + + + tableView + pressed(QModelIndex) + PasswordManagerClass + on_view(QModelIndex) + + + 312 + 304 + + + 311 + 356 + + + + + tableView + doubleClicked(QModelIndex) + PasswordManagerClass + on_edit(QModelIndex) + + + 402 + 313 + + + 405 + 341 + + + + + copy_username + clicked() + PasswordManagerClass + on_copy_username() + + + 67 + 353 + + + 63 + 371 + + + + + copy_password + clicked() + PasswordManagerClass + on_copy_password() + + + 154 + 353 + + + 158 + 373 + + + + + password_entry + returnPressed() + PasswordManagerClass + on_confirm_password() + + + 246 + 96 + + + 252 + 109 + + + + + + on_select_file() + on_new_file() + on_confirm_password() + on_show_password() + on_hide_password() + on_add_data(QString,QString,QString) + on_push_new() + on_remove_row() + on_menu(QAction*) + on_save_file() + on_set_password() + on_view(QModelIndex) + on_edit(QModelIndex) + on_copy_username() + on_copy_password() + + diff --git a/PasswordManager.vcxproj b/PasswordManager.vcxproj new file mode 100644 index 0000000..936584d --- /dev/null +++ b/PasswordManager.vcxproj @@ -0,0 +1,115 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {F1077C8C-16FF-4890-A625-F35C76ABC156} + QtVS_v304 + 10.0 + 10.0 + $(MSBuildProjectDirectory)\QtMsBuild + + + + Application + v143 + true + Unicode + + + Application + v143 + false + true + Unicode + + + + + + + 6.7.2_msvc2019_64 + core;gui;widgets + debug + + + 6.7.2_msvc2019_64 + core;gui;widgets + release + + + + + + + + + + + + + + + + + + + + + + true + Level3 + true + true + + + Windows + true + + + + + true + Level3 + true + true + true + true + + + Windows + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PasswordManager.vcxproj.filters b/PasswordManager.vcxproj.filters new file mode 100644 index 0000000..5e3fbb7 --- /dev/null +++ b/PasswordManager.vcxproj.filters @@ -0,0 +1,60 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + + + {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} + ts + + + + + Resource Files + + + Form Files + + + Header Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + + + Header Files + + + \ No newline at end of file diff --git a/PasswordManager.vcxproj.user b/PasswordManager.vcxproj.user new file mode 100644 index 0000000..5a4d7e1 --- /dev/null +++ b/PasswordManager.vcxproj.user @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/data.cpp b/data.cpp new file mode 100644 index 0000000..aceaa59 --- /dev/null +++ b/data.cpp @@ -0,0 +1,62 @@ +#include +#include + +#define t(str) QString::fromLocal8Bit(str) + +QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::CBC, QAESEncryption::ISO); +QByteArray AESEncrypt(QString content, QString key) { + QByteArray hashKey=QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha256); + QByteArray hashIV = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Md5); + return encryption.encode(content.toUtf8(), hashKey,hashIV); +} + +QString AESDecrypt(QByteArray content, QString key) { + QByteArray hashKey = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha256); + QByteArray hashIV = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Md5); + return QString::fromUtf8(encryption.removePadding(encryption.decode(content, hashKey, hashIV))); +} + +QString QModel2QString(QStandardItemModel* model) { + QString result; + for (int y = 0; y < model->rowCount(); y++) { + result.append(model->item(y, 0)->text()); + result.append("\t"); + result.append(model->item(y, 1)->text()); + result.append("\t"); + result.append(model->item(y, 2)->data(Qt::UserRole).toString()); + + result.append("\n"); + } + result.chop(1); + return result; +} + +void QString2QModel(QString content,QStandardItemModel *model) { + model->clear(); + model->setColumnCount(3); + model->setHorizontalHeaderLabels({ t("ƽ̨"),t("û"),t("") }); + if (content.isEmpty())return; + foreach(QString column, content.split("\n")) { + QStringList items = column.split("\t"); + QStandardItem* password = new QStandardItem(QString(items.at(2)).fill('*')); + password->setData(items.at(2), Qt::UserRole); + model->appendRow({new QStandardItem(items.at(0)),new QStandardItem(items.at(1)), password}); + } +} + + +bool saveData(QString path,QStandardItemModel* model,QString key) { + QFile file(path); + if(!file.open(QIODevice::WriteOnly|QIODevice::Truncate))return false; + file.write(AESEncrypt(QModel2QString(model).append("EOF"), key)); + return true; +} + +bool readData(QString path, QStandardItemModel* model,QString key) { + QFile file(path); + if(!file.open(QIODevice::ReadOnly))return false; + QString table = AESDecrypt(file.readAll(), key); + if (!table.endsWith("EOF"))return false; + QString2QModel(table.chopped(3), model); + return true; +} \ No newline at end of file diff --git a/data.h b/data.h new file mode 100644 index 0000000..e1d2867 --- /dev/null +++ b/data.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include +#include + +QByteArray AESEncrypt(QString content, QString key); +QString AESDecrypt(QByteArray content, QString key); +QString QModel2QString(QStandardItemModel *model); +void QString2QModel(QString content,QStandardItemModel *model); +bool saveData(QString path, QStandardItemModel *model, QString key); +bool readData(QString path, QStandardItemModel *model, QString key); \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1668d05 --- /dev/null +++ b/main.cpp @@ -0,0 +1,13 @@ +#pragma execution_character_set("utf-8") + +#include "PasswordManager.h" +#include +using namespace std; + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PasswordManager w; + w.show(); + return a.exec(); +} diff --git a/qaesencryption.cpp b/qaesencryption.cpp new file mode 100644 index 0000000..f0dcb1c --- /dev/null +++ b/qaesencryption.cpp @@ -0,0 +1,688 @@ +#include "qaesencryption.h" + +#ifdef USE_INTEL_AES_IF_AVAILABLE +#include "aesni/aesni-key-exp.h" +#include "aesni/aesni-key-init.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, bool isEncryptionKey) +{ + return QAESEncryption(level, mode).expandKey(key, isEncryptionKey); +} + +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, bool isEncryptionKey) +{ + +#ifdef USE_INTEL_AES_IF_AVAILABLE + if (m_aesNIAvailable){ + switch(m_level) { + case AES_128: { + AES128 aes128; + AES_KEY aesKey; + if(isEncryptionKey){ + AES_set_encrypt_key((unsigned char*) key.constData(), aes128.userKeySize, &aesKey); + }else{ + AES_set_decrypt_key((unsigned char*) key.constData(), aes128.userKeySize, &aesKey); + } + + QByteArray expKey; + expKey.resize(aes128.expandedKey); + memcpy(expKey.data(), (char*) aesKey.KEY, aes128.expandedKey); + memset(aesKey.KEY, 0, 240); + return expKey; + } + break; + case AES_192: { + AES192 aes192; + AES_KEY aesKey; + if(isEncryptionKey){ + AES_set_encrypt_key((unsigned char*) key.constData(), aes192.userKeySize, &aesKey); + }else{ + AES_set_decrypt_key((unsigned char*) key.constData(), aes192.userKeySize, &aesKey); + } + + QByteArray expKey; + expKey.resize(aes192.expandedKey); + memcpy(expKey.data(), (char*) aesKey.KEY, aes192.expandedKey); + memset(aesKey.KEY, 0, 240); + return expKey; + } + break; + case AES_256: { + AES256 aes256; + AES_KEY aesKey; + if(isEncryptionKey){ + AES_set_encrypt_key((unsigned char*) key.constData(), aes256.userKeySize, &aesKey); + }else{ + AES_set_decrypt_key((unsigned char*) key.constData(), aes256.userKeySize, &aesKey); + } + + QByteArray expKey; + expKey.resize(aes256.expandedKey); + memcpy(expKey.data(), (char*) aesKey.KEY, aes256.expandedKey); + memset(aesKey.KEY, 0, 240); + return expKey; + } + 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= CBC && (iv.isEmpty() || iv.size() != m_blocklen)) || key.size() != m_keyLen) + return QByteArray(); + + QByteArray expandedKey = expandKey(key, true); + 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){ + char expKey[expandedKey.size()]; + memcpy(expKey, expandedKey.data(), expandedKey.size()); + + QByteArray outText; + outText.resize(alignedText.size()); + AES_ECB_encrypt((unsigned char*) alignedText.constData(), + (unsigned char*) outText.data(), + alignedText.size(), + expKey, + m_nr); + return outText; + } +#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 ivec[iv.size()]; + memcpy(ivec, iv.data(), iv.size()); + char expKey[expandedKey.size()]; + memcpy(expKey, expandedKey.data(), expandedKey.size()); + + QByteArray outText; + outText.resize(alignedText.size()); + AES_CBC_encrypt((unsigned char*) alignedText.constData(), + (unsigned char*) outText.data(), + ivec, + alignedText.size(), + expKey, + m_nr); + return outText; + } +#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)) || key.size() != m_keyLen || rawText.size() % m_blocklen != 0) + return QByteArray(); + + QByteArray ret; + QByteArray expandedKey; + + #ifdef USE_INTEL_AES_IF_AVAILABLE + if(m_aesNIAvailable && m_mode <= CBC){ + expandedKey = expandKey(key, false); + }else{ + expandedKey = expandKey(key, true); + } + #else + expandedKey = expandKey(key, true); + #endif + //false or true here is very important + //the expandedKeys aren't the same for !aes-ni! ENcryption and DEcryption (only CBC and EBC) + //but if you are !NOT! using aes-ni then the expandedKeys for encryption and decryption are the SAME!!! + + + switch(m_mode) + { + case ECB: +#ifdef USE_INTEL_AES_IF_AVAILABLE + if (m_aesNIAvailable){ + char expKey[expandedKey.size()]; //expandedKey + memcpy(expKey, expandedKey.data(), expandedKey.size()); + ret.resize(rawText.size()); + + AES_ECB_decrypt((unsigned char*) rawText.constData(), + (unsigned char*) ret.data(), + rawText.size(), + expKey, + m_nr); + break; + } +#endif + for(int i=0; i < rawText.size(); i+= m_blocklen) + ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen))); + break; + case CBC: +#ifdef USE_INTEL_AES_IF_AVAILABLE + if (m_aesNIAvailable){ + quint8 ivec[iv.size()]; //IV + memcpy(ivec, iv.constData(), iv.size()); + char expKey[expandedKey.size()]; //expandedKey + memcpy(expKey, expandedKey.data(), expandedKey.size()); + ret.resize(rawText.size()); + + AES_CBC_decrypt((unsigned char*) rawText.constData(), + (unsigned char*) ret.data(), + ivec, + rawText.size(), + expKey, + m_nr); + break; + } +#endif + { + 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/qaesencryption.h b/qaesencryption.h new file mode 100644 index 0000000..e76eeb8 --- /dev/null +++ b/qaesencryption.h @@ -0,0 +1,225 @@ +#ifndef QAESENCRYPTION_H +#define QAESENCRYPTION_H + +#ifdef QtAES_EXPORTS +#include "qtaes_export.h" +#else +#define QTAESSHARED_EXPORT +#endif + +#include +#include + +#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 + }; + + /*! + * \brief static method call to encrypt data given by rawText + * \param level: AES::Aes level + * \param mode: AES::Mode mode + * \param rawText: input text + * \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes) + * \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes)) + * \param padding: AES::Padding standard + * \return encrypted cipher + */ + static QByteArray Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key, + const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO); + /*! + * \brief static method call to decrypt data given by rawText + * \param level: AES::Aes level + * \param mode: AES::Mode mode + * \param rawText: input text + * \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes) + * \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes)) + * \param padding: AES::Padding standard + * \return decrypted cipher with padding + */ + static QByteArray Decrypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key, + const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO); + /*! + * \brief static method call to expand the user key to fit the encrypting/decrypting algorithm + * \param level: AES::Aes level + * \param mode: AES::Mode mode + * \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes) + * \param expKey: output expanded key + * \param isEncryptionKey: always 'true' || only 'false' when DECRYPTING in CBC or EBC mode with aesni (check if supported) + * \return AES-ready key + */ + static QByteArray ExpandKey(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &key, bool isEncryptionKey); + + /*! + * \brief static method call to remove padding from decrypted cipher given by rawText + * \param rawText: inputText + * \param padding: AES::Padding standard + * \return decrypted cipher with padding removed + */ + static QByteArray RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding = QAESEncryption::ISO); + + QAESEncryption(QAESEncryption::Aes level, QAESEncryption::Mode mode, + QAESEncryption::Padding padding = QAESEncryption::ISO); + + + + /*! + * \brief object method call to encrypt data given by rawText + * \param rawText: input text + * \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes) + * \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes)) + * \return encrypted cipher + */ + QByteArray encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray()); + + /*! + * \brief object method call to decrypt data given by rawText + * \param rawText: input text + * \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes) + * \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes)) + * \param padding: AES::Padding standard + * \return decrypted cipher with padding + */ + QByteArray decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray()); + + /*! + * \brief object method call to expand the user key to fit the encrypting/decrypting algorithm + * \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes) + * \param isEncryptionKey: always 'true' || only 'false' when DECRYPTING in CBC or EBC mode with aesni (check if supported) + * \return AES-ready key + */ + QByteArray expandKey(const QByteArray &key, bool isEncryptionKey); + + /*! + * \brief object method call to remove padding from decrypted cipher given by rawText + * \param rawText: inputText + * \return decrypted cipher with padding removed + */ + QByteArray removePadding(const QByteArray &rawText); + + 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; + int userKeySize = 256; + }; + + struct AES192{ + int nk = 6; + int keylen = 24; + int nr = 12; + int expandedKey = 209; + int userKeySize = 192; + }; + + struct AES128{ + int nk = 4; + int keylen = 16; + int nr = 10; + int expandedKey = 176; + int userKeySize = 128; + }; + + 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