diff options
Diffstat (limited to 'src/core/function')
40 files changed, 4799 insertions, 0 deletions
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp new file mode 100644 index 00000000..6315dcd5 --- /dev/null +++ b/src/core/function/ArchiveFileOperator.cpp @@ -0,0 +1,238 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "ArchiveFileOperator.h" + +int copy_data(struct archive *ar, struct archive *aw) { + int r; + const void *buff; + size_t size; + int64_t offset; + + for (;;) { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + return (ARCHIVE_OK); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_data_block() failed: " << archive_error_string(ar); + return (r); + } + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_write_data_block() failed: " << archive_error_string(aw); + return (r); + } + } +} + +void GpgFrontend::ArchiveFileOperator::CreateArchive( + const std::filesystem::path &base_path, + const std::filesystem::path &archive_path, int compress, + const std::vector<std::filesystem::path> &files) { + LOG(INFO) << "CreateArchive: " << archive_path.string(); + + auto current_base_path_backup = QDir::currentPath(); + QDir::setCurrent(base_path.string().c_str()); + + auto relative_archive_path = std::filesystem::relative(archive_path, base_path); + + std::vector<std::filesystem::path> relative_files; + relative_files.reserve(files.size()); + for(const auto& file : files) { + relative_files.push_back(std::filesystem::relative(file, base_path)); + } + + struct archive *a; + struct archive_entry *entry; + ssize_t len; + int fd; + + LOG(INFO) << "compress: " << compress; + + a = archive_write_new(); + switch (compress) { +#ifndef NO_BZIP2_CREATE + case 'j': + case 'y': + archive_write_add_filter_bzip2(a); + break; +#endif +#ifndef NO_COMPRESS_CREATE + case 'Z': + archive_write_add_filter_compress(a); + break; +#endif +#ifndef NO_GZIP_CREATE + case 'z': + archive_write_add_filter_gzip(a); + break; +#endif + default: + archive_write_add_filter_none(a); + break; + } + archive_write_set_format_ustar(a); + archive_write_set_format_pax_restricted(a); + + auto filename = relative_archive_path.string(); + if (!filename.empty() && filename == "-") + throw std::runtime_error("cannot write to stdout"); + + archive_write_open_filename(a, filename.c_str()); + + for (const auto &file : relative_files) { + struct archive *disk = archive_read_disk_new(); +#ifndef NO_LOOKUP + archive_read_disk_set_standard_lookup(disk); +#endif + int r; + + LOG(INFO) << "ReadFile: " << file.string(); + + r = archive_read_disk_open(disk, file.string().c_str()); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_disk_open() failed: " + << archive_error_string(disk); + throw std::runtime_error("archive_read_disk_open() failed"); + } + + for (;;) { + bool needcr = false; + + entry = archive_entry_new(); + r = archive_read_next_header2(disk, entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_next_header2() failed: " + << archive_error_string(disk); + throw std::runtime_error("archive_read_next_header2() failed"); + } + archive_read_disk_descend(disk); + LOG(INFO) << "Adding: " << archive_entry_pathname(entry) << "size" + << archive_entry_size(entry) << " bytes" + << "file type" << archive_entry_filetype(entry); + r = archive_write_header(a, entry); + if (r < ARCHIVE_OK) { + LOG(ERROR) << "archive_write_header() failed: " + << archive_error_string(a); + throw std::runtime_error("archive_write_header() failed"); + } + if (r == ARCHIVE_FATAL) throw std::runtime_error("archive fatal"); + if (r > ARCHIVE_FAILED) { + ByteArray buff; + FileOperator::ReadFileStd(archive_entry_sourcepath(entry), buff); + archive_write_data(a, buff.c_str(), buff.size()); + } + archive_entry_free(entry); + } + archive_read_close(disk); + archive_read_free(disk); + } + archive_write_close(a); + archive_write_free(a); + + QDir::setCurrent(current_base_path_backup); +} + +void GpgFrontend::ArchiveFileOperator::ExtractArchive( + const std::filesystem::path &archive_path, + const std::filesystem::path &base_path) { + + LOG(INFO) << "ExtractArchive: " << archive_path.string(); + + auto current_base_path_backup = QDir::currentPath(); + QDir::setCurrent(base_path.string().c_str()); + + struct archive *a; + struct archive *ext; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, 0); +#ifndef NO_BZIP2_EXTRACT + archive_read_support_filter_bzip2(a); +#endif +#ifndef NO_GZIP_EXTRACT + archive_read_support_filter_gzip(a); +#endif +#ifndef NO_COMPRESS_EXTRACT + archive_read_support_filter_compress(a); +#endif +#ifndef NO_TAR_EXTRACT + archive_read_support_format_tar(a); +#endif +#ifndef NO_CPIO_EXTRACT + archive_read_support_format_cpio(a); +#endif +#ifndef NO_LOOKUP + archive_write_disk_set_standard_lookup(ext); +#endif + + auto filename = archive_path.string(); + + if (!filename.empty() && filename == "-") { + LOG(ERROR) << "cannot read from stdin"; + } + if ((r = archive_read_open_filename(a, filename.c_str(), 10240))) { + LOG(ERROR) << "archive_read_open_filename() failed: " + << archive_error_string(a); + throw std::runtime_error("archive_read_open_filename() failed"); + } + for (;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_next_header() failed: " + << archive_error_string(a); + throw std::runtime_error("archive_read_next_header() failed"); + } + LOG(INFO) << "Extracting: " << archive_entry_pathname(entry) + << "size" << archive_entry_size(entry) << " bytes" + << "file type" << archive_entry_filetype(entry); + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_write_header() failed: " + << archive_error_string(ext); + } else { + r = copy_data(a, ext); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "copy_data() failed: " << archive_error_string(ext); + } + } + } + archive_read_close(a); + archive_read_free(a); + + archive_write_close(ext); + archive_write_free(ext); + + QDir::setCurrent(current_base_path_backup); +} diff --git a/src/core/function/ArchiveFileOperator.h b/src/core/function/ArchiveFileOperator.h new file mode 100644 index 00000000..8e1d9c44 --- /dev/null +++ b/src/core/function/ArchiveFileOperator.h @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_ARCHIVEFILEOPERATOR_H +#define GPGFRONTEND_ARCHIVEFILEOPERATOR_H + +#include "core/GpgFrontendCore.h" +#include "core/function/FileOperator.h" + +namespace GpgFrontend { + +struct ArchiveStruct { + struct archive *archive; + struct archive_entry *entry; + int fd; + bool is_open; + std::string name; +}; + +class ArchiveFileOperator { + public: + static void ListArchive(const std::filesystem::path &archive_path) { + struct archive *a; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + archive_read_support_filter_all(a); + archive_read_support_format_all(a); + r = archive_read_open_filename(a, archive_path.string().c_str(), + 10240); // Note 1 + if (r != ARCHIVE_OK) return; + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + LOG(INFO) << "File: " << archive_entry_pathname(entry); + LOG(INFO) << "File Path: " << archive_entry_pathname(entry); + archive_read_data_skip(a); // Note 2 + } + r = archive_read_free(a); // Note 3 + if (r != ARCHIVE_OK) return; + } + + static void CreateArchive( + const std::filesystem::path &base_path, + const std::filesystem::path &archive_path, + int compress, + const std::vector<std::filesystem::path> &files); + + static void ExtractArchive( + const std::filesystem::path &archive_path, + const std::filesystem::path &base_path); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ARCHIVEFILEOPERATOR_H diff --git a/src/core/function/DataObjectOperator.cpp b/src/core/function/DataObjectOperator.cpp new file mode 100644 index 00000000..a3f7fc70 --- /dev/null +++ b/src/core/function/DataObjectOperator.cpp @@ -0,0 +1,169 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "DataObjectOperator.h" + +#include <qt-aes/qaesencryption.h> + +#include "core/function/FileOperator.h" +#include "core/function/PassphraseGenerator.h" + +void GpgFrontend::DataObjectOperator::init_app_secure_key() { + LOG(INFO) << "Initializing application secure key"; + FileOperator::WriteFileStd(app_secure_key_path_, + PassphraseGenerator::GetInstance().Generate(256)); + std::filesystem::permissions( + app_secure_key_path_, + std::filesystem::perms::owner_read | std::filesystem::perms::owner_write); +} + +GpgFrontend::DataObjectOperator::DataObjectOperator(int channel) + : SingletonFunctionObject<DataObjectOperator>(channel) { + if (!is_directory(app_secure_path_)) create_directory(app_secure_path_); + + if (!exists(app_secure_key_path_)) { + init_app_secure_key(); + } + + std::string key; + if (!FileOperator::ReadFileStd(app_secure_key_path_.string(), key)) { + LOG(FATAL) << _("Failed to read app secure key file") + << app_secure_key_path_; + throw std::runtime_error(_("Failed to read app secure key file")); + } + hash_key_ = QCryptographicHash::hash(QByteArray::fromStdString(key), + QCryptographicHash::Sha256); + LOG(INFO) << "App secure key loaded" << hash_key_.size() << "bytes"; + + if (!exists(app_data_objs_path_)) create_directory(app_data_objs_path_); +} + +std::string GpgFrontend::DataObjectOperator::SaveDataObj( + const std::string& _key, const nlohmann::json& value) { + + std::string _hash_obj_key = {}; + if (_key.empty()) { + _hash_obj_key = + QCryptographicHash::hash( + hash_key_ + QByteArray::fromStdString( + PassphraseGenerator::GetInstance().Generate(32) + + to_iso_extended_string( + boost::posix_time::second_clock::local_time())), + QCryptographicHash::Sha256) + .toHex() + .toStdString(); + } else { + _hash_obj_key = + QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), + QCryptographicHash::Sha256) + .toHex() + .toStdString(); + } + + const auto obj_path = app_data_objs_path_ / _hash_obj_key; + + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + auto encoded = + encryption.encode(QByteArray::fromStdString(to_string(value)), hash_key_); + + LOG(INFO) << _("Saving data object") << _hash_obj_key << "to" << obj_path << encoded.size() << "bytes"; + + FileOperator::WriteFileStd(obj_path.string(), encoded.toStdString()); + + return _key.empty() ? _hash_obj_key : std::string(); +} + +std::optional<nlohmann::json> GpgFrontend::DataObjectOperator::GetDataObject( + const std::string& _key) { + try { + LOG(INFO) << _("Get data object") << _key; + auto _hash_obj_key = + QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), + QCryptographicHash::Sha256) + .toHex() + .toStdString(); + + const auto obj_path = app_data_objs_path_ / _hash_obj_key; + + if (!std::filesystem::exists(obj_path)) { + LOG(ERROR) << _("Data object not found") << _key; + return {}; + } + + std::string buffer; + if (!FileOperator::ReadFileStd(obj_path.string(), buffer)) { + LOG(ERROR) << _("Failed to read data object") << _key; + return {}; + } + + LOG(INFO) << _("Data object found") << _key; + + auto encoded = QByteArray::fromStdString(buffer); + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + + LOG(INFO) << _("Decrypting data object") << encoded.size() << hash_key_.size(); + + auto decoded = + encryption.removePadding(encryption.decode(encoded, hash_key_)); + + LOG(INFO) << _("Data object decoded") << _key; + + return nlohmann::json::parse(decoded.toStdString()); + } catch (...) { + LOG(ERROR) << _("Failed to get data object") << _key; + return {}; + } +} + +std::optional<nlohmann::json> +GpgFrontend::DataObjectOperator::GetDataObjectByRef(const std::string& _ref) { + if (_ref.size() != 64) return {}; + + try { + const auto& _hash_obj_key = _ref; + const auto obj_path = app_data_objs_path_ / _hash_obj_key; + + if (!std::filesystem::exists(obj_path)) return {}; + + std::string buffer; + if (!FileOperator::ReadFileStd(obj_path.string(), buffer)) return {}; + auto encoded = QByteArray::fromStdString(buffer); + + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + + auto decoded = + encryption.removePadding(encryption.decode(encoded, hash_key_)); + + return nlohmann::json::parse(decoded.toStdString()); + } catch (...) { + return {}; + } +} diff --git a/src/core/function/DataObjectOperator.h b/src/core/function/DataObjectOperator.h new file mode 100644 index 00000000..0ce4e313 --- /dev/null +++ b/src/core/function/DataObjectOperator.h @@ -0,0 +1,82 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_DATAOBJECTOPERATOR_H +#define GPGFRONTEND_DATAOBJECTOPERATOR_H + +#include <json/single_include/nlohmann/json.hpp> + +#include "core/GpgFrontendCore.h" +#include "core/GpgFunctionObject.h" +#include "core/function/GlobalSettingStation.h" + +namespace GpgFrontend { + +class DataObjectOperator : public SingletonFunctionObject<DataObjectOperator> { + public: + /** + * @brief DataObjectOperator constructor + * + * @param channel channel + */ + explicit DataObjectOperator( + int channel = SingletonFunctionObject::GetDefaultChannel()); + + std::string SaveDataObj(const std::string &_key, const nlohmann::json &value); + + std::optional<nlohmann::json> GetDataObject(const std::string &_key); + + std::optional<nlohmann::json> GetDataObjectByRef(const std::string &_ref); + + private: + /** + * @brief init the secure key of application data object + * + */ + void init_app_secure_key(); + + GlobalSettingStation &global_setting_station_ = + GlobalSettingStation::GetInstance(); ///< GlobalSettingStation + std::filesystem::path app_secure_path_ = + global_setting_station_.GetAppConfigPath() / + "secure"; ///< Where sensitive information is stored + std::filesystem::path app_secure_key_path_ = + app_secure_path_ / "app.key"; ///< Where the key of data object is stored + std::filesystem::path app_data_objs_path_ = + global_setting_station_.GetAppDataPath() / "data_objs"; ///< Where data + ///< object is + ///< stored + + std::random_device rd_; ///< Random device + std::mt19937 mt_ = std::mt19937(rd_()); ///< Mersenne twister + QByteArray hash_key_; ///< Hash key +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_DATAOBJECTOPERATOR_H diff --git a/src/core/function/FileOperator.cpp b/src/core/function/FileOperator.cpp new file mode 100644 index 00000000..d0a3df23 --- /dev/null +++ b/src/core/function/FileOperator.cpp @@ -0,0 +1,119 @@ +/** +* Copyright (C) 2021 Saturneric +* +* 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. +* +* GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +* +* The initial version of the source code is inherited from +* the gpg4usb project, which is under GPL-3.0-or-later. +* +* All the source code of GpgFrontend was modified and released by +* Saturneric<[email protected]> starting on May 12, 2021. +* +* SPDX-License-Identifier: GPL-3.0-or-later +* +*/ + +#include "FileOperator.h" + +bool GpgFrontend::FileOperator::ReadFile(const QString& file_name, + QByteArray& data) { + QFile file(file_name); + if (!file.open(QIODevice::ReadOnly)) { + LOG(ERROR) << "failed to open file" << file_name.toStdString(); + return false; + } + data = file.readAll(); + file.close(); + return true; +} + +bool GpgFrontend::FileOperator::WriteFile(const QString& file_name, + const QByteArray& data) { + QFile file(file_name); + if (!file.open(QIODevice::WriteOnly)) { + LOG(ERROR) << "failed to open file" << file_name.toStdString(); + return false; + } + file.write(data); + file.close(); + return true; +} + +bool GpgFrontend::FileOperator::ReadFileStd( + const std::filesystem::path& file_name, std::string& data) { + QByteArray byte_data; + bool res = ReadFile(QString::fromStdString(file_name.string()), byte_data); + data = byte_data.toStdString(); + return res; +} + +bool GpgFrontend::FileOperator::WriteFileStd( + const std::filesystem::path& file_name, const std::string& data) { + return WriteFile(QString::fromStdString(file_name.string()), + QByteArray::fromStdString(data)); +} + +std::string GpgFrontend::FileOperator::CalculateHash( + const std::filesystem::path& file_path) { + // Returns empty QByteArray() on failure. + QFileInfo info(QString::fromStdString(file_path.string())); + std::stringstream ss; + + if (info.isFile() && info.isReadable()) { + ss << "[#] " << _("File Hash Information") << std::endl; + ss << " " << _("filename") << _(": ") + << file_path.filename().string().c_str() << std::endl; + + + QFile f(info.filePath()); + f.open(QFile::ReadOnly); + auto buffer = f.readAll(); + ss << " " << _("file size(bytes)") << _(": ") + << buffer.size() << std::endl; + f.close(); + if (f.open(QFile::ReadOnly)) { + auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); + // md5 + hash_md5.addData(buffer); + auto md5 = hash_md5.result().toHex().toStdString(); + LOG(INFO) << "md5" << md5; + ss << " " + << "md5" << _(": ") << md5 << std::endl; + + auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); + // sha1 + hash_sha1.addData(buffer); + auto sha1 = hash_sha1.result().toHex().toStdString(); + LOG(INFO) << "sha1" << sha1; + ss << " " + << "sha1" << _(": ") << sha1 << std::endl; + + auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); + // sha1 + hash_sha256.addData(buffer); + auto sha256 = hash_sha256.result().toHex().toStdString(); + LOG(INFO) << "sha256" << sha256; + ss << " " + << "sha256" << _(": ") << sha256 << std::endl; + + ss << std::endl; + } + } else { + ss << "[#] " << _("Error in Calculating File Hash ") << std::endl; + } + + return ss.str(); +} diff --git a/src/core/function/FileOperator.h b/src/core/function/FileOperator.h new file mode 100644 index 00000000..aa2c3b73 --- /dev/null +++ b/src/core/function/FileOperator.h @@ -0,0 +1,92 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_FILEOPERATOR_H +#define GPGFRONTEND_FILEOPERATOR_H + +#include "core/GpgFrontendCore.h" + +namespace GpgFrontend { + +/** + * @brief provides file operations + * + */ +class FileOperator { + public: + /** + * @brief read file content using std struct + * + * + * @param file_name file name + * @param data data read from file + * @return + */ + static bool ReadFileStd(const std::filesystem::path &file_name, + std::string &data); + + /** + * @brief write file content using std struct + * + * @param file_name file name + * @param data data to write to file + * @return + */ + static bool WriteFileStd(const std::filesystem::path &file_name, + const std::string &data); + + /** + * @brief read file content + * + * @param file_name file name + * @param data data read from file + * @return true if success + * @return false if failed + */ + static bool ReadFile(const QString &file_name, QByteArray &data); + + /** + * @brief write file content + * + * @param file_name file name + * @param data data to write to file + * @return true if success + * @return false if failed + */ + static bool WriteFile(const QString &file_name, const QByteArray &data); + + /** + * calculate the hash of a file + * @param file_path + * @return + */ + static std::string CalculateHash(const std::filesystem::path &file_path); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_FILEOPERATOR_H diff --git a/src/core/function/GlobalSettingStation.cpp b/src/core/function/GlobalSettingStation.cpp new file mode 100644 index 00000000..7b3e868e --- /dev/null +++ b/src/core/function/GlobalSettingStation.cpp @@ -0,0 +1,141 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GlobalSettingStation.h" + +#include <openssl/bio.h> +#include <openssl/pem.h> + +#include <vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp> +#include <vmime/vmime.hpp> + +#include "core/function/FileOperator.h" + +void GpgFrontend::GlobalSettingStation::SyncSettings() noexcept { + using namespace libconfig; + try { + ui_cfg_.writeFile(ui_config_path_.string().c_str()); + LOG(INFO) << _("Updated ui configuration successfully written to") + << ui_config_path_; + + } catch (const FileIOException &fioex) { + LOG(ERROR) << _("I/O error while writing ui configuration file") + << ui_config_path_; + } +} + +GpgFrontend::GlobalSettingStation::GlobalSettingStation(int channel) noexcept + : SingletonFunctionObject<GlobalSettingStation>(channel) { + using namespace std::filesystem; + using namespace libconfig; + + el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); + + LOG(INFO) << _("App Path") << app_path_; + LOG(INFO) << _("App Configure Path") << app_configure_path_; + LOG(INFO) << _("App Data Path") << app_data_path_; + LOG(INFO) << _("App Log Path") << app_log_path_; + LOG(INFO) << _("App Locale Path") << app_locale_path_; + + if (!is_directory(app_configure_path_)) create_directory(app_configure_path_); + + if (!is_directory(app_data_path_)) create_directory(app_data_path_); + + if (!is_directory(app_log_path_)) create_directory(app_log_path_); + + if (!is_directory(ui_config_dir_path_)) create_directory(ui_config_dir_path_); + + if (!exists(ui_config_path_)) { + try { + this->ui_cfg_.writeFile(ui_config_path_.string().c_str()); + LOG(INFO) << _("UserInterface configuration successfully written to") + << ui_config_path_; + + } catch (const FileIOException &fioex) { + LOG(ERROR) + << _("I/O error while writing UserInterface configuration file") + << ui_config_path_; + } + } else { + try { + this->ui_cfg_.readFile(ui_config_path_.string().c_str()); + LOG(INFO) << _("UserInterface configuration successfully read from") + << ui_config_path_; + } catch (const FileIOException &fioex) { + LOG(ERROR) << _("I/O error while reading UserInterface configure file"); + } catch (const ParseException &pex) { + LOG(ERROR) << _("Parse error at ") << pex.getFile() << ":" + << pex.getLine() << " - " << pex.getError(); + } + } +} + +void GpgFrontend::GlobalSettingStation::AddRootCert( + const std::filesystem::path &path) { + std::string out_buffer; + if (!FileOperator::ReadFileStd(path.string(), out_buffer)) { + LOG(ERROR) << _("Failed to read root certificate file") << path; + return; + } + + auto mem_bio = std::shared_ptr<BIO>( + BIO_new_mem_buf(out_buffer.data(), static_cast<int>(out_buffer.size())), + [](BIO *_p) { BIO_free(_p); }); + + auto x509 = std::shared_ptr<X509>( + PEM_read_bio_X509(mem_bio.get(), nullptr, nullptr, nullptr), + [](X509 *_p) { X509_free(_p); }); + + if (!x509) return; + + root_certs_.push_back(x509); +} + +vmime::shared_ptr<vmime::security::cert::defaultCertificateVerifier> +GpgFrontend::GlobalSettingStation::GetCertVerifier() const { + auto p_cv = + vmime::make_shared<vmime::security::cert::defaultCertificateVerifier>(); + + std::vector<vmime::shared_ptr<vmime::security::cert::X509Certificate>> + _root_certs; + for (const auto &cert : root_certs_) { + _root_certs.push_back( + std::make_shared<vmime::security::cert::X509Certificate_OpenSSL>( + cert.get())); + } + return p_cv; +} + +const std::vector<std::shared_ptr<X509>> + &GpgFrontend::GlobalSettingStation::GetRootCerts() { + return root_certs_; +} + +void GpgFrontend::GlobalSettingStation::init_app_secure_key() {} + +GpgFrontend::GlobalSettingStation::~GlobalSettingStation() noexcept = default; diff --git a/src/core/function/GlobalSettingStation.h b/src/core/function/GlobalSettingStation.h new file mode 100644 index 00000000..d6521c8a --- /dev/null +++ b/src/core/function/GlobalSettingStation.h @@ -0,0 +1,232 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_GLOBALSETTINGSTATION_H +#define GPGFRONTEND_GLOBALSETTINGSTATION_H + +#include <openssl/x509.h> + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> + +#include "GpgFrontendBuildInstallInfo.h" +#include "core/GpgFrontendCore.h" +#include "core/GpgFunctionObject.h" + +namespace vmime::security::cert { +class defaultCertificateVerifier; +class X509Certificate; +} // namespace vmime::security::cert + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GlobalSettingStation + : public SingletonFunctionObject<GlobalSettingStation> { + public: + /** + * @brief Construct a new Global Setting Station object + * + */ + explicit GlobalSettingStation( + int channel = SingletonFunctionObject::GetDefaultChannel()) noexcept; + + /** + * @brief Destroy the Global Setting Station object + * + */ + ~GlobalSettingStation() noexcept override; + + /** + * @brief + * + * @return libconfig::Setting& + */ + libconfig::Setting &GetUISettings() noexcept { return ui_cfg_.getRoot(); } + + /** + * @brief Get the App Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetAppDir() const { return app_path_; } + + [[nodiscard]] std::filesystem::path GetAppDataPath() const { + return app_data_path_; + } + + /** + * @brief Get the Log Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetLogDir() const { + return app_log_path_; + } + + /** + * @brief Get the Standalone Database Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetStandaloneDatabaseDir() const { + auto db_path = app_configure_path_ / "db"; + if (!std::filesystem::exists(db_path)) { + std::filesystem::create_directory(db_path); + } + return db_path; + } + + [[nodiscard]] std::filesystem::path GetAppConfigPath() const { + return app_configure_path_; + } + + /** + * @brief Get the Standalone Gpg Bin Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetStandaloneGpgBinDir() const { + return app_resource_path_ / "gpg1.4" / "gpg"; + } + + /** + * @brief Get the Locale Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetLocaleDir() const { + return app_locale_path_; + } + + /** + * @brief Get the Resource Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetResourceDir() const { + return app_resource_path_; + } + + /** + * @brief Get the Certs Dir object + * + * @return std::filesystem::path + */ + [[nodiscard]] std::filesystem::path GetCertsDir() const { + return app_resource_path_ / "certs"; + } + + /** + * @brief Get the Cert Verifier object + * + * @return std::shared_ptr< + * vmime::security::cert::defaultCertificateVerifier> + */ + [[nodiscard]] std::shared_ptr< + vmime::security::cert::defaultCertificateVerifier> + GetCertVerifier() const; + + /** + * @brief + * + * @param path + */ + void AddRootCert(const std::filesystem::path &path); + + /** + * @brief Get the Root Certs object + * + * @return const std::vector<std::shared_ptr<X509>>& + */ + const std::vector<std::shared_ptr<X509>> &GetRootCerts(); + + /** + * @brief + * + */ + void ResetRootCerts() { root_certs_.clear(); } + + /** + * @brief sync the settings to the file + * + */ + void SyncSettings() noexcept; + + private: + std::filesystem::path app_path_ = + qApp->applicationDirPath().toStdString(); ///< Program Location + std::filesystem::path app_data_path_ = + QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + .toStdString(); ///< Program Data Location + std::filesystem::path app_log_path_ = + app_data_path_ / "logs"; ///< Program Data Location + std::filesystem::path app_data_objs_path_ = + app_data_path_ / "objs"; ///< Object storage path + +#ifdef LINUX_INSTALL_BUILD + std::filesystem::path app_resource_path_ = + std::filesystem::path(APP_LOCALSTATE_PATH) / + "gpgfrontend"; ///< Program Data Location +#else + std::filesystem::path app_resource_path_ = + RESOURCE_DIR_BOOST_PATH(app_path_); ///< Program Data Location +#endif + +#ifdef LINUX_INSTALL_BUILD + std::filesystem::path app_locale_path_ = + std::string(APP_LOCALE_PATH); ///< Program Data Location +#else + std::filesystem::path app_locale_path_ = + app_resource_path_ / "locales"; ///< Program Data Location +#endif + + std::filesystem::path app_configure_path_ = + QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + .toStdString(); ///< Program Configure Location + std::filesystem::path ui_config_dir_path_ = + app_configure_path_ / + "UserInterface"; ///< Configure File Directory Location + std::filesystem::path ui_config_path_ = + ui_config_dir_path_ / "ui.cfg"; ///< UI Configure File Location + + libconfig::Config ui_cfg_; ///< + std::vector<std::shared_ptr<X509>> root_certs_; ///< + + /** + * @brief + * + */ + void init_app_secure_key(); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GLOBALSETTINGSTATION_H diff --git a/src/core/function/KeyPackageOperator.cpp b/src/core/function/KeyPackageOperator.cpp new file mode 100644 index 00000000..2b2802f7 --- /dev/null +++ b/src/core/function/KeyPackageOperator.cpp @@ -0,0 +1,120 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "KeyPackageOperator.h" + +#include "FileOperator.h" +#include "function/PassphraseGenerator.h" +#include "function/gpg/GpgKeyGetter.h" +#include "function/gpg/GpgKeyImportExporter.h" +#include "qt-aes/qaesencryption.h" + +namespace GpgFrontend { + +bool KeyPackageOperator::GeneratePassphrase( + const std::filesystem::path& phrase_path, std::string& phrase) { + phrase = PassphraseGenerator::GetInstance().Generate(256); + LOG(INFO) << "Generated passphrase: " << phrase.size() << " bytes"; + return FileOperator::WriteFileStd(phrase_path, phrase); +} + +bool KeyPackageOperator::GenerateKeyPackage( + const std::filesystem::path& key_package_path, + const std::string& key_package_name, KeyIdArgsListPtr& key_ids, + std::string& phrase, bool secret) { + LOG(INFO) << "Generating key package: " << key_package_name; + + ByteArrayPtr key_export_data = nullptr; + if (!GpgKeyImportExporter::GetInstance().ExportKeys(key_ids, key_export_data, + secret)) { + LOG(ERROR) << "Failed to export keys"; + return false; + } + + auto key = QByteArray::fromStdString(phrase); + auto data = QString::fromStdString(*key_export_data).toLocal8Bit().toBase64(); + + auto hash_key = QCryptographicHash::hash(key, QCryptographicHash::Sha256); + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + auto encoded = encryption.encode(data, hash_key); + + LOG(INFO) << "Writing key package: " << key_package_name; + return FileOperator::WriteFileStd(key_package_path, encoded.toStdString()); +} + +bool KeyPackageOperator::ImportKeyPackage( + const std::filesystem::path& key_package_path, + const std::filesystem::path& phrase_path, + GpgFrontend::GpgImportInformation& import_info) { + + LOG(INFO) << "Importing key package: " << key_package_path.string(); + + std::string encrypted_data; + FileOperator::ReadFileStd(key_package_path, encrypted_data); + + if (encrypted_data.empty()) { + LOG(ERROR) << "Failed to read key package: " << key_package_path.string(); + return false; + }; + + std::string passphrase; + FileOperator::ReadFileStd(phrase_path, passphrase); + LOG(INFO) << "Passphrase: " << passphrase.size() << " bytes"; + if (passphrase.size() != 256) { + LOG(ERROR) << "Failed to read passphrase: " << phrase_path.string(); + return false; + } + + auto hash_key = QCryptographicHash::hash( + QByteArray::fromStdString(passphrase), QCryptographicHash::Sha256); + auto encoded = QByteArray::fromStdString(encrypted_data); + + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + + auto decoded = encryption.removePadding(encryption.decode(encoded, hash_key)); + auto key_data = QByteArray::fromBase64(decoded); + + LOG(INFO) << "key data" << key_data.size(); + if (!key_data.startsWith(GpgConstants::PGP_PUBLIC_KEY_BEGIN) && + !key_data.startsWith(GpgConstants::PGP_PRIVATE_KEY_BEGIN)) { + return false; + } + + auto key_data_ptr = std::make_unique<ByteArray>(key_data.toStdString()); + import_info = + GpgKeyImportExporter::GetInstance().ImportKey(std::move(key_data_ptr)); + return true; +} + +std::string KeyPackageOperator::GenerateKeyPackageName() { + return generate_key_package_name(); +} + +} // namespace GpgFrontend diff --git a/src/core/function/KeyPackageOperator.h b/src/core/function/KeyPackageOperator.h new file mode 100644 index 00000000..cd344688 --- /dev/null +++ b/src/core/function/KeyPackageOperator.h @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_KEYPACKAGEOPERATOR_H +#define GPGFRONTEND_KEYPACKAGEOPERATOR_H + +#include "core/GpgFrontendCore.h" +#include "core/function/gpg/GpgKeyImportExporter.h" + +namespace GpgFrontend { + +/** + * @brief give the possibility to import or export a key package + * + */ +class KeyPackageOperator { + public: + /** + * @brief generate passphrase for key package and save it to file + * + * @param phrase_path path to passphrase file + * @param phrase passphrase generated + * @return true if passphrase was generated and saved + * @return false if passphrase was not generated and saved + */ + static bool GeneratePassphrase(const std::filesystem::path &phrase_path, + std::string &phrase); + + /** + * @brief generate the name of the key package + * + * @return std::string name of the key package + */ + static std::string GenerateKeyPackageName(); + + /** + * @brief generate key package + * + * @param key_package_path path to key package + * @param key_package_name name of the key package + * @param key_ids key ids to export + * @param phrase passphrase to encrypt key package + * @param secret true if secret key should be exported + * @return true if key package was generated + * @return false if key package was not generated + */ + static bool GenerateKeyPackage(const std::filesystem::path &key_package_path, + const std::string &key_package_name, + KeyIdArgsListPtr &key_ids, std::string &phrase, + bool secret); + + /** + * @brief import key package + * + * @param key_package_path path to key package + * @param phrase_path path to passphrase file + * @param import_info import info + * @return true if key package was imported + * @return false if key package was not imported + */ + static bool ImportKeyPackage(const std::filesystem::path &key_package_path, + const std::filesystem::path &phrase_path, + GpgFrontend::GpgImportInformation &import_info); + + private: + /** + * @brief generate key package name + * + * @return std::string key package name + */ + static std::string generate_key_package_name() { + std::random_device rd_; ///< Random device + auto mt_ = std::mt19937(rd_()); ///< Mersenne twister + + std::uniform_int_distribution<int> dist(999, 99999); + auto file_string = boost::format("KeyPackage_%1%") % dist(mt_); + return file_string.str(); + } +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_KEYPACKAGEOPERATOR_H diff --git a/src/core/function/PassphraseGenerator.cpp b/src/core/function/PassphraseGenerator.cpp new file mode 100644 index 00000000..0267edda --- /dev/null +++ b/src/core/function/PassphraseGenerator.cpp @@ -0,0 +1,29 @@ +/** +* Copyright (C) 2021 Saturneric +* +* 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. +* +* GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +* +* The initial version of the source code is inherited from +* the gpg4usb project, which is under GPL-3.0-or-later. +* +* All the source code of GpgFrontend was modified and released by +* Saturneric<[email protected]> starting on May 12, 2021. +* +* SPDX-License-Identifier: GPL-3.0-or-later +* + */ + +#include "PassphraseGenerator.h" diff --git a/src/core/function/PassphraseGenerator.h b/src/core/function/PassphraseGenerator.h new file mode 100644 index 00000000..d1cc7607 --- /dev/null +++ b/src/core/function/PassphraseGenerator.h @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_PASSPHRASEGENERATOR_H +#define GPGFRONTEND_PASSPHRASEGENERATOR_H + +#include "core/GpgFrontendCore.h" +#include "core/GpgFunctionObject.h" + +namespace GpgFrontend { + +/** + * @brief The PassphraseGenerator class + * + * This class is used to generate a passphrase. + */ +class PassphraseGenerator + : public SingletonFunctionObject<PassphraseGenerator> { + public: + /** + * @brief PassphraseGenerator constructor + * + * @param channel The channel to use + */ + explicit PassphraseGenerator( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<PassphraseGenerator>(channel) {} + + /** + * @brief generate passphrase + * + * @param len length of the passphrase + * @return std::string passphrase + */ + std::string Generate(int len) { + std::uniform_int_distribution<int> dist(999, 99999); + + auto file_string = boost::format("KeyPackage_%1%") % dist(mt_); + 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; + } + + std::random_device rd_; ///< Random device + std::mt19937 mt_ = std::mt19937(rd_()); ///< Mersenne twister +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_PASSPHRASEGENERATOR_H diff --git a/src/core/function/aes/aes_ssl.h b/src/core/function/aes/aes_ssl.h new file mode 100644 index 00000000..b5f0820f --- /dev/null +++ b/src/core/function/aes/aes_ssl.h @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_AES_SSL_H +#define GPGFRONTEND_AES_SSL_H + +#include "GpgFrontend.h" + +#include <openssl/aes.h> +#include <openssl/evp.h> + +namespace GpgFrontend::RawAPI { + +/** + * @brief + * + * @param key_data + * @param key_data_len + * @param salt + * @param e_ctx + * @param d_ctx + * @return int + */ +int aes_256_cbc_init(uint8_t *key_data, int key_data_len, uint8_t *salt, + EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx); + +/** + * @brief + * + * @param e + * @param plaintext + * @param len + * @return uint8_t* + */ +uint8_t *aes_256_cbc_encrypt(EVP_CIPHER_CTX *e, uint8_t *plaintext, int *len); + +/** + * @brief + * + * @param e + * @param ciphertext + * @param len + * @return uint8_t* + */ +uint8_t *aes_256_cbc_decrypt(EVP_CIPHER_CTX *e, uint8_t *ciphertext, int *len); + +} // namespace GpgFrontend::RawAPI + +#endif // GPGFRONTEND_AES_SSL_H diff --git a/src/core/function/aes/aes_ssl_cbc.cpp b/src/core/function/aes/aes_ssl_cbc.cpp new file mode 100644 index 00000000..95ae0ce2 --- /dev/null +++ b/src/core/function/aes/aes_ssl_cbc.cpp @@ -0,0 +1,99 @@ +/** + * AES encryption/decryption demo program using OpenSSL EVP apis + * gcc -Wall openssl_aes.c -lcrypto + * this is public domain code. + * Saju Pillai ([email protected]) + **/ + +#include "aes_ssl.h" + +namespace GpgFrontend::RawAPI { + +/** + * @brief Create a 256 bit key and IV using the supplied key_data. salt can be + * added for taste. Fills in the encryption and decryption ctx objects and + * returns 0 on success + * + * @param key_data + * @param key_data_len + * @param salt + * @param e_ctx + * @param d_ctx + * @return int + */ +int aes_256_cbc_init(uint8_t *key_data, int key_data_len, uint8_t *salt, + EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx) { + int i, nrounds = 5; + uint8_t key[32], iv[32]; + + /* + * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the + * supplied key material. nrounds is the number of times the we hash the + * material. More rounds are more secure but slower. + */ + i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, + key_data_len, nrounds, key, iv); + if (i != 32) { + printf("Key size is %d bits - should be 256 bits\n", i); + return -1; + } + + EVP_CIPHER_CTX_init(e_ctx); + EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv); + EVP_CIPHER_CTX_init(d_ctx); + EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv); + + return 0; +} + +/** + * @brief Encrypt *len bytes of data All data going in & out is considered + * binary (uint8_t[]) + * + * @param e + * @param plaintext + * @param len + * @return uint8_t* + */ +uint8_t *aes_256_cbc_encrypt(EVP_CIPHER_CTX *e, uint8_t *plaintext, int *len) { + /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 + * bytes */ + int c_len = *len + AES_BLOCK_SIZE, f_len = 0; + auto *ciphertext = (uint8_t *)malloc(c_len); + + /* allows reusing of 'e' for multiple encryption cycles */ + EVP_EncryptInit_ex(e, nullptr, nullptr, nullptr, nullptr); + + /* update ciphertext, c_len is filled with the length of ciphertext generated, + *len is the size of plaintext in bytes */ + EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len); + + /* update ciphertext with the final remaining bytes */ + EVP_EncryptFinal_ex(e, ciphertext + c_len, &f_len); + + *len = c_len + f_len; + return ciphertext; +} + +/** + * @brief Decrypt *len bytes of ciphertext + * + * @param e + * @param ciphertext + * @param len + * @return uint8_t* + */ +uint8_t *aes_256_cbc_decrypt(EVP_CIPHER_CTX *e, uint8_t *ciphertext, int *len) { + /* plaintext will always be equal to or lesser than length of ciphertext*/ + int p_len = *len, f_len = 0; + auto *plaintext = (uint8_t *)malloc(p_len); + + EVP_DecryptInit_ex(e, nullptr, nullptr, nullptr, nullptr); + EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len); + EVP_DecryptFinal_ex(e, plaintext + p_len, &f_len); + + *len = p_len + f_len; + return plaintext; +} + +} // namespace GpgFrontend::RawAPI
\ No newline at end of file diff --git a/src/core/function/gpg/GpgBasicOperator.cpp b/src/core/function/gpg/GpgBasicOperator.cpp new file mode 100644 index 00000000..b92404a9 --- /dev/null +++ b/src/core/function/gpg/GpgBasicOperator.cpp @@ -0,0 +1,220 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgBasicOperator.h" + +#include <vector> + +#include "GpgKeyGetter.h" + +GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Encrypt( + KeyListPtr keys, GpgFrontend::BypeArrayRef in_buffer, + GpgFrontend::ByteArrayPtr& out_buffer, GpgFrontend::GpgEncrResult& result) { + // gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[keys->size() + 1]; + + int index = 0; + for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + + // Last entry data_in array has to be nullptr + recipients[keys->size()] = nullptr; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( + ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); + std::swap(result, temp_result); + + return err; +} + +GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Decrypt( + BypeArrayRef in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, + GpgFrontend::GpgDecrResult& result) { + gpgme_error_t err; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + err = check_gpg_error(gpgme_op_decrypt(ctx_, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_result = _new_result(gpgme_op_decrypt_result(ctx_)); + std::swap(result, temp_result); + + return err; +} + +GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Verify( + BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer, + GpgVerifyResult& result) const { + gpgme_error_t err; + + GpgData data_in(in_buffer.data(), in_buffer.size()); + GpgData data_out; + + if (sig_buffer != nullptr) { + GpgData sig_data(sig_buffer->data(), sig_buffer->size()); + err = check_gpg_error(gpgme_op_verify(ctx_, sig_data, data_in, nullptr)); + } else + err = check_gpg_error(gpgme_op_verify(ctx_, data_in, nullptr, data_out)); + + auto temp_result = _new_result(gpgme_op_verify_result(ctx_)); + std::swap(result, temp_result); + + return err; +} + +GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Sign(KeyListPtr signers, + BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, + gpgme_sig_mode_t mode, + GpgSignResult& result) { + gpgme_error_t err; + + // Set Singers of this opera + SetSigners(*signers); + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + err = check_gpg_error(gpgme_op_sign(ctx_, data_in, data_out, mode)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_result = _new_result(gpgme_op_sign_result(ctx_)); + + std::swap(result, temp_result); + + return err; +} + +gpgme_error_t GpgFrontend::GpgBasicOperator::DecryptVerify( + BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgDecrResult& decrypt_result, GpgVerifyResult& verify_result) { + gpgme_error_t err; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + err = check_gpg_error(gpgme_op_decrypt_verify(ctx_, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_decr_result = _new_result(gpgme_op_decrypt_result(ctx_)); + std::swap(decrypt_result, temp_decr_result); + + auto temp_verify_result = _new_result(gpgme_op_verify_result(ctx_)); + std::swap(verify_result, temp_verify_result); + + return err; +} + +gpgme_error_t GpgFrontend::GpgBasicOperator::EncryptSign( + KeyListPtr keys, KeyListPtr signers, BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, GpgEncrResult& encr_result, + GpgSignResult& sign_result) { + gpgme_error_t err; + SetSigners(*signers); + + // gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[keys->size() + 1]; + + // set key for user + int index = 0; + for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + + // Last entry dataIn array has to be nullptr + recipients[keys->size()] = nullptr; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + // If the last parameter isnt 0, a private copy of data is made + err = check_gpg_error(gpgme_op_encrypt_sign( + ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_encr_result = _new_result(gpgme_op_encrypt_result(ctx_)); + swap(encr_result, temp_encr_result); + auto temp_sign_result = _new_result(gpgme_op_sign_result(ctx_)); + swap(sign_result, temp_sign_result); + + return err; +} + +void GpgFrontend::GpgBasicOperator::SetSigners(KeyArgsList& signers) { + gpgme_signers_clear(ctx_); + for (const GpgKey& key : signers) { + DLOG(INFO) << "key" << key.GetFingerprint(); + if (key.IsHasActualSigningCapability()) { + DLOG(INFO) << "signer"; + auto error = gpgme_signers_add(ctx_, gpgme_key_t(key)); + check_gpg_error(error); + } + } + if (signers.size() != gpgme_signers_count(ctx_)) + DLOG(INFO) << "No All Signers Added"; +} + +std::unique_ptr<GpgFrontend::KeyArgsList> +GpgFrontend::GpgBasicOperator::GetSigners() { + auto count = gpgme_signers_count(ctx_); + auto signers = std::make_unique<std::vector<GpgKey>>(); + for (auto i = 0u; i < count; i++) { + auto key = GpgKey(gpgme_signers_enum(ctx_, i)); + signers->push_back(GpgKey(std::move(key))); + } + return signers; +} + +gpg_error_t GpgFrontend::GpgBasicOperator::EncryptSymmetric( + GpgFrontend::ByteArray& in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, + GpgFrontend::GpgEncrResult& result) { + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( + ctx_, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + // TODO(Saturneric): maybe a bug of gpgme + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { + auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); + std::swap(result, temp_result); + } + + return err; +} diff --git a/src/core/function/gpg/GpgBasicOperator.h b/src/core/function/gpg/GpgBasicOperator.h new file mode 100644 index 00000000..9b9d9f63 --- /dev/null +++ b/src/core/function/gpg/GpgBasicOperator.h @@ -0,0 +1,179 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H +#define GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H + +#include "core/GpgConstants.h" +#include "core/GpgContext.h" +#include "core/GpgFunctionObject.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { + +/** + * @brief Basic operation collection + * + */ +class GpgBasicOperator : public SingletonFunctionObject<GpgBasicOperator> { + public: + /** + * @brief Construct a new Basic Operator object + * + * @param channel Channel corresponding to the context + */ + explicit GpgBasicOperator( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgBasicOperator>(channel) {} + + /** + * @brief Call the interface provided by gpgme for encryption operation + * + * All incoming data pointers out_buffer will be replaced with new valid + * values + * + * @param keys list of public keys + * @param in_buffer data that needs to be encrypted + * @param out_buffer encrypted data + * @param result the result of the operation + * @return error code + */ + gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, GpgEncrResult& result); + + /** + * @brief Call the interface provided by GPGME to symmetrical encryption + * + * @param in_buffer Data for encryption + * @param out_buffer Encrypted data + * @param result Encrypted results + * @return gpg_error_t + */ + gpg_error_t EncryptSymmetric(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgEncrResult& result); + + /** + * + * @brief Call the interface provided by gpgme to perform encryption and + * signature operations at the same time. + * + * @param keys List of public keys + * @param signers Private key for signatures + * @param in_buffer Data for operation + * @param out_buffer Encrypted data + * @param encr_result Encrypted results + * @param sign_result Signature result + * @return + */ + gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers, + BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgEncrResult& encr_result, + GpgSignResult& sign_result); + + /** + * @brief Call the interface provided by gpgme for decryption operation + * + * @param in_buffer data that needs to be decrypted + * @param out_buffer decrypted data + * @param result the result of the operation + * @return error code + */ + gpgme_error_t Decrypt(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgDecrResult& result); + + /** + * @brief Call the interface provided by gpgme to perform decryption and + * verification operations at the same time. + * + * @param in_buffer data to be manipulated + * @param out_buffer data resulting from decryption operation + * @param decrypt_result the result of the decrypting operation + * @param verify_result the result of the verifying operation + * @return error code + */ + gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgDecrResult& decrypt_result, + GpgVerifyResult& verify_result); + + /** + * @brief Call the interface provided by gpgme for verification operation + * + * @param in_buffer data that needs to be verified + * @param out_buffer verified data + * @param result the result of the operation + * @return error code + */ + gpgme_error_t Verify(BypeArrayRef in_buffer, ByteArrayPtr& sig_buffer, + GpgVerifyResult& result) const; + + /** + * @brief Call the interface provided by gpgme for signing operation + * + * The signing modes are as follows: + * `GPGME_SIG_MODE_NORMAL' + * A normal signature is made, the output includes the plaintext and the + * signature. + * `GPGME_SIG_MODE_DETACH' + * A detached signature is made. + * `GPGME_SIG_MODE_CLEAR' + * A clear text signature is made. The ASCII armor and text mode settings + * of the context are ignored. + * + * @param signers private keys for signing operations + * @param in_buffer data that needs to be signed + * @param out_buffer verified data + * @param mode signing mode + * @param result the result of the operation + * @return error code + */ + gpg_error_t Sign(KeyListPtr signers, BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, gpgme_sig_mode_t mode, + GpgSignResult& result); + + /** + * @brief Set the private key for signatures, this operation is a global + * operation. + * + * @param keys + */ + void SetSigners(KeyArgsList& signers); + + /** + * @brief Get a global signature private keys that has been set. + * + * @return Intelligent pointer pointing to the private key list + */ + std::unique_ptr<KeyArgsList> GetSigners(); + + private: + GpgContext& ctx_ = GpgContext::GetInstance( + SingletonFunctionObject::GetChannel()); ///< Corresponding context +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp new file mode 100644 index 00000000..a6a67d08 --- /dev/null +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "GpgCommandExecutor.h" +#ifndef WINDOWS +#include <boost/asio.hpp> +#endif + +#ifndef WINDOWS + +using boost::process::async_pipe; + +void GpgFrontend::GpgCommandExecutor::Execute( + StringArgsRef arguments, + const std::function<void(async_pipe& in, async_pipe& out)>& interact_func) { + using namespace boost::process; + + boost::asio::io_service ios; + + std::vector<char> buf; + + async_pipe in_pipe_stream(ios); + async_pipe out_pipe_stream(ios); + + child child_process(ctx_.GetInfo().AppPath.c_str(), arguments, + std_out > in_pipe_stream, std_in < out_pipe_stream); + + boost::asio::async_read( + in_pipe_stream, boost::asio::buffer(buf), + [&](const boost::system::error_code& ec, std::size_t size) { + interact_func(in_pipe_stream, out_pipe_stream); + }); + + ios.run(); + child_process.wait(); + child_process.exit_code(); +} + +#endif diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h new file mode 100644 index 00000000..49baf406 --- /dev/null +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H +#define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H + +#ifndef WINDOWS +#include <boost/process.hpp> +#endif + +#include "core/GpgContext.h" +#include "core/GpgFunctionObject.h" + +namespace GpgFrontend { + +/** + * @brief Extra commands related to GPG + * + */ +class GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> { + public: + /** + * @brief Construct a new Gpg Command Executor object + * + * @param channel Corresponding context + */ + explicit GpgCommandExecutor( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgCommandExecutor>(channel) {} + +#ifndef WINDOWS + + /** + * @brief Excuting an order + * + * @param arguments Command parameters + * @param interact_func Command answering function + */ + void Execute(StringArgsRef arguments, + const std::function<void(boost::process::async_pipe &in, + boost::process::async_pipe &out)> + &interact_func); +#endif + + private: + GpgContext &ctx_ = GpgContext::GetInstance( + SingletonFunctionObject::GetChannel()); ///< Corresponding context +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H diff --git a/src/core/function/gpg/GpgFileOpera.cpp b/src/core/function/gpg/GpgFileOpera.cpp new file mode 100644 index 00000000..7044353b --- /dev/null +++ b/src/core/function/gpg/GpgFileOpera.cpp @@ -0,0 +1,182 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "GpgFileOpera.h" + +#include <memory> +#include <string> + +#include "GpgConstants.h" +#include "GpgBasicOperator.h" +#include "function/FileOperator.h" + +GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile( + KeyListPtr keys, const std::string& in_path, const std::string& out_path, + GpgEncrResult& result, int _channel) { + + std::string in_buffer; + if(!FileOperator::ReadFileStd(in_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + std::unique_ptr<std::string> out_buffer = nullptr; + + auto err = GpgBasicOperator::GetInstance(_channel).Encrypt( + std::move(keys), in_buffer, out_buffer, result); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!FileOperator::WriteFileStd(out_path, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile( + const std::string& in_path, const std::string& out_path, + GpgDecrResult& result) { + std::string in_buffer; + if(!FileOperator::ReadFileStd(in_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + std::unique_ptr<std::string> out_buffer; + + auto err = + GpgBasicOperator::GetInstance().Decrypt(in_buffer, out_buffer, result); + + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!FileOperator::WriteFileStd(out_path, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyListPtr keys, + const std::string& in_path, + const std::string& out_path, + GpgSignResult& result, + int _channel) { + std::string in_buffer; + if(!FileOperator::ReadFileStd(in_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + std::unique_ptr<std::string> out_buffer; + + auto err = GpgBasicOperator::GetInstance(_channel).Sign( + std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!FileOperator::WriteFileStd(out_path, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile( + const std::string& data_path, const std::string& sign_path, + GpgVerifyResult& result, int _channel) { + std::string in_buffer; + if(!FileOperator::ReadFileStd(data_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + std::unique_ptr<std::string> sign_buffer = nullptr; + if (!sign_path.empty()) { + std::string sign_buffer_str; + if (!FileOperator::ReadFileStd(sign_path, sign_buffer_str)) { + throw std::runtime_error("read file error"); + } + sign_buffer = + std::make_unique<std::string>(sign_buffer_str); + } + auto err = GpgBasicOperator::GetInstance(_channel).Verify(in_buffer, sign_buffer, + result); + return err; +} + +gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile( + KeyListPtr keys, KeyListPtr signer_keys, const std::string& in_path, + const std::string& out_path, GpgEncrResult& encr_res, + GpgSignResult& sign_res, int _channel) { + std::string in_buffer; + if(!FileOperator::ReadFileStd(in_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + std::unique_ptr<std::string> out_buffer = nullptr; + + auto err = GpgBasicOperator::GetInstance(_channel).EncryptSign( + std::move(keys), std::move(signer_keys), in_buffer, out_buffer, encr_res, + sign_res); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!FileOperator::WriteFileStd(out_path, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile( + const std::string& in_path, const std::string& out_path, + GpgDecrResult& decr_res, GpgVerifyResult& verify_res) { + std::string in_buffer; + if(!FileOperator::ReadFileStd(in_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + + std::unique_ptr<std::string> out_buffer = nullptr; + auto err = GpgBasicOperator::GetInstance().DecryptVerify(in_buffer, out_buffer, + decr_res, verify_res); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!FileOperator::WriteFileStd(out_path, *out_buffer)) { + throw std::runtime_error("write file error"); + }; + + return err; +} +unsigned int GpgFrontend::GpgFileOpera::EncryptFileSymmetric( + const std::string& in_path, const std::string& out_path, + GpgFrontend::GpgEncrResult& result, int _channel) { + std::string in_buffer; + if(!FileOperator::ReadFileStd(in_path, in_buffer)) { + throw std::runtime_error("read file error"); + } + + std::unique_ptr<std::string> out_buffer; + auto err = GpgBasicOperator::GetInstance(_channel).EncryptSymmetric( + in_buffer, out_buffer, result); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!FileOperator::WriteFileStd(out_path, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} diff --git a/src/core/function/gpg/GpgFileOpera.h b/src/core/function/gpg/GpgFileOpera.h new file mode 100644 index 00000000..f21bf04c --- /dev/null +++ b/src/core/function/gpg/GpgFileOpera.h @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_GPGFILEOPERA_H +#define GPGFRONTEND_GPGFILEOPERA_H + +#include "core/GpgConstants.h" +#include "core/GpgContext.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { + +/** + * @brief Executive files related to the basic operations that are provided by + * GpgBasicOperator + * @class class: GpgBasicOperator + */ +class GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> { + public: + explicit GpgFileOpera( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgFileOpera>(channel) {} + + /** + * @brief Encrypted file + * + * @param keys Used public key + * @param in_path The path where the enter file is located + * @param out_path The path where the output file is located + * @param result Encrypted results + * @param _channel Channel in context + * @return unsigned int error code + */ + static unsigned int EncryptFile(KeyListPtr keys, const std::string& in_path, + const std::string& out_path, + GpgEncrResult& result, + int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + + /** + * @brief 运用对称加密算法加密文件 + * + * @param in_path + * @param out_path + * @param result + * @param _channel + * @return unsigned int + */ + static unsigned int EncryptFileSymmetric( + const std::string& in_path, const std::string& out_path, + GpgEncrResult& result, int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + + /** + * @brief + * + * @param in_path + * @param out_path + * @param result + * @return GpgError + */ + static GpgError DecryptFile(const std::string& in_path, + const std::string& out_path, + GpgDecrResult& result); + + /** + * @brief + * + * @param keys + * @param in_path + * @param out_path + * @param result + * @param _channel + * @return GpgError + */ + static GpgError SignFile(KeyListPtr keys, const std::string& in_path, + const std::string& out_path, GpgSignResult& result, + int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + + /** + * @brief + * + * @param data_path + * @param sign_path + * @param result + * @param _channel + * @return GpgError + */ + static GpgError VerifyFile(const std::string& data_path, + const std::string& sign_path, + GpgVerifyResult& result, + int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + + /** + * @brief + * + * @param keys + * @param signer_keys + * @param in_path + * @param out_path + * @param encr_res + * @param sign_res + * @param _channel + * @return GpgError + */ + static GpgError EncryptSignFile(KeyListPtr keys, KeyListPtr signer_keys, + const std::string& in_path, + const std::string& out_path, + GpgEncrResult& encr_res, + GpgSignResult& sign_res, + int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + + /** + * @brief + * + * @param in_path + * @param out_path + * @param decr_res + * @param verify_res + * @return GpgError + */ + static GpgError DecryptVerifyFile(const std::string& in_path, + const std::string& out_path, + GpgDecrResult& decr_res, + GpgVerifyResult& verify_res); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGFILEOPERA_H diff --git a/src/core/function/gpg/GpgKeyGetter.cpp b/src/core/function/gpg/GpgKeyGetter.cpp new file mode 100644 index 00000000..1a4715e7 --- /dev/null +++ b/src/core/function/gpg/GpgKeyGetter.cpp @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgKeyGetter.h" + +#include <gpg-error.h> + +#include "GpgConstants.h" + +GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr) { + gpgme_key_t _p_key = nullptr; + gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 1); + if (_p_key == nullptr) { + DLOG(WARNING) << "GpgKeyGetter GetKey Private _p_key Null fpr" << fpr; + return GetPubkey(fpr); + } else { + return GpgKey(std::move(_p_key)); + } +} + +GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey( + const std::string& fpr) { + gpgme_key_t _p_key = nullptr; + gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 0); + if (_p_key == nullptr) + DLOG(WARNING) << "GpgKeyGetter GetKey _p_key Null" << fpr; + return GpgKey(std::move(_p_key)); +} + +GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() { + gpgme_error_t err; + + auto keys_list = std::make_unique<GpgKeyLinkList>(); + + err = gpgme_op_keylist_start(ctx_, nullptr, 0); + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + + gpgme_key_t key; + while ((err = gpgme_op_keylist_next(ctx_, &key)) == GPG_ERR_NO_ERROR) { + keys_list->push_back(GetKey(key->fpr)); + } + + assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF); + + err = gpgme_op_keylist_end(ctx_); + + assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_NO_ERROR); + + return keys_list; +} + +GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeys( + const KeyIdArgsListPtr& ids) { + auto keys = std::make_unique<KeyArgsList>(); + for (const auto& id : *ids) keys->push_back(GetKey(id)); + return keys; +} + +GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::GetKeysCopy( + const GpgFrontend::KeyLinkListPtr& keys) { + auto keys_copy = std::make_unique<GpgKeyLinkList>(); + for (const auto& key : *keys) keys_copy->push_back(key.Copy()); + return keys_copy; +} + +GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeysCopy( + const GpgFrontend::KeyListPtr& keys) { + auto keys_copy = std::make_unique<KeyArgsList>(); + for (const auto& key : *keys) keys_copy->push_back(key.Copy()); + return keys_copy; +} diff --git a/src/core/function/gpg/GpgKeyGetter.h b/src/core/function/gpg/GpgKeyGetter.h new file mode 100644 index 00000000..cde027a0 --- /dev/null +++ b/src/core/function/gpg/GpgKeyGetter.h @@ -0,0 +1,110 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H +#define GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H + +#include "core/GpgContext.h" +#include "core/GpgFunctionObject.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> { + public: + /** + * @brief Construct a new Gpg Key Getter object + * + * @param channel + */ + explicit GpgKeyGetter( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgKeyGetter>(channel) {} + + /** + * @brief Get the Key object + * + * @param fpr + * @return GpgKey + */ + GpgKey GetKey(const std::string& fpr); + + /** + * @brief Get the Keys object + * + * @param ids + * @return KeyListPtr + */ + KeyListPtr GetKeys(const KeyIdArgsListPtr& ids); + + /** + * @brief Get the Pubkey object + * + * @param fpr + * @return GpgKey + */ + GpgKey GetPubkey(const std::string& fpr); + + /** + * @brief + * + * @return KeyLinkListPtr + */ + KeyLinkListPtr FetchKey(); + + /** + * @brief Get the Keys Copy object + * + * @param keys + * @return KeyListPtr + */ + static KeyListPtr GetKeysCopy(const KeyListPtr& keys); + + /** + * @brief Get the Keys Copy object + * + * @param keys + * @return KeyLinkListPtr + */ + static KeyLinkListPtr GetKeysCopy(const KeyLinkListPtr& keys); + + private: + /** + * @brief + * + */ + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H diff --git a/src/core/function/gpg/GpgKeyImportExporter.cpp b/src/core/function/gpg/GpgKeyImportExporter.cpp new file mode 100644 index 00000000..0f1ebfa2 --- /dev/null +++ b/src/core/function/gpg/GpgKeyImportExporter.cpp @@ -0,0 +1,178 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgKeyImportExporter.h" + +#include "GpgConstants.h" +#include "GpgKeyGetter.h" + +/** + * Import key pair + * @param inBuffer input byte array + * @return Import information + */ +GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExporter::ImportKey( + StdBypeArrayPtr in_buffer) { + if (in_buffer->empty()) return {}; + + GpgData data_in(in_buffer->data(), in_buffer->size()); + auto err = check_gpg_error(gpgme_op_import(ctx_, data_in)); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; + + gpgme_import_result_t result; + result = gpgme_op_import_result(ctx_); + gpgme_import_status_t status = result->imports; + auto import_info = std::make_unique<GpgImportInformation>(result); + while (status != nullptr) { + GpgImportedKey key; + key.import_status = static_cast<int>(status->status); + key.fpr = status->fpr; + import_info->importedKeys.emplace_back(key); + status = status->next; + } + + return *import_info; +} + +/** + * Export Key + * @param uid_list key ids + * @param out_buffer output byte array + * @return if success + */ +bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, + ByteArrayPtr& out_buffer, + bool secret) const { + if (uid_list->empty()) return false; + + int _mode = 0; + if (secret) _mode |= GPGME_EXPORT_MODE_SECRET; + + auto keys = GpgKeyGetter::GetInstance().GetKeys(uid_list); + auto keys_array = new gpgme_key_t[keys->size() + 1]; + + int index = 0; + for (const auto& key : *keys) { + keys_array[index++] = gpgme_key_t(key); + } + keys_array[index] = nullptr; + + GpgData data_out; + auto err = gpgme_op_export_keys(ctx_, keys_array, _mode, data_out); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return false; + + delete[] keys_array; + + DLOG(INFO) << "exportKeys read_bytes" + << gpgme_data_seek(data_out, 0, SEEK_END); + + auto temp_out_buffer = data_out.Read2Buffer(); + + swap(temp_out_buffer, out_buffer); + + return true; +} + +/** + * Export keys + * @param keys keys used + * @param outBuffer output byte array + * @return if success + */ +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.GetId()); + return ExportKeys(key_ids, out_buffer, secret); +} + +/** + * Export the secret key of a key pair(including subkeys) + * @param key target key pair + * @param outBuffer output byte array + * @return if successful + */ +bool GpgFrontend::GpgKeyImportExporter::ExportSecretKey( + const GpgKey& key, ByteArrayPtr& out_buffer) const { + DLOG(INFO) << "Export Secret Key" << key.GetId().c_str(); + + gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr}; + + GpgData data_out; + // export private key to outBuffer + gpgme_error_t err = gpgme_op_export_keys(ctx_, target_key, + GPGME_EXPORT_MODE_SECRET, data_out); + + auto temp_out_buffer = data_out.Read2Buffer(); + std::swap(out_buffer, temp_out_buffer); + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} + +bool GpgFrontend::GpgKeyImportExporter::ExportKey( + const GpgFrontend::GpgKey& key, + GpgFrontend::ByteArrayPtr& out_buffer) const { + GpgData data_out; + auto err = gpgme_op_export(ctx_, key.GetId().c_str(), 0, data_out); + + 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); + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} + +bool GpgFrontend::GpgKeyImportExporter::ExportKeyOpenSSH( + const GpgFrontend::GpgKey& key, + GpgFrontend::ByteArrayPtr& out_buffer) const { + GpgData data_out; + auto err = gpgme_op_export(ctx_, key.GetId().c_str(), GPGME_EXPORT_MODE_SSH, + data_out); + + DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END); + + auto temp_out_buffer = data_out.Read2Buffer(); + std::swap(out_buffer, temp_out_buffer); + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} + +bool GpgFrontend::GpgKeyImportExporter::ExportSecretKeyShortest( + const GpgFrontend::GpgKey& key, + GpgFrontend::ByteArrayPtr& out_buffer) const { + GpgData data_out; + auto err = gpgme_op_export(ctx_, key.GetId().c_str(), + GPGME_EXPORT_MODE_MINIMAL, data_out); + + DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END); + + auto temp_out_buffer = data_out.Read2Buffer(); + std::swap(out_buffer, temp_out_buffer); + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} diff --git a/src/core/function/gpg/GpgKeyImportExporter.h b/src/core/function/gpg/GpgKeyImportExporter.h new file mode 100644 index 00000000..d7e6deae --- /dev/null +++ b/src/core/function/gpg/GpgKeyImportExporter.h @@ -0,0 +1,195 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef _GPGKEYIMPORTEXPORTOR_H +#define _GPGKEYIMPORTEXPORTOR_H + +#include <string> + +#include "core/GpgConstants.h" +#include "core/GpgContext.h" +#include "core/GpgFunctionObject.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GpgImportedKey { + public: + std::string fpr; ///< + int import_status; ///< +}; + +typedef std::list<GpgImportedKey> GpgImportedKeyList; ///< + +/** + * @brief + * + */ +class GpgImportInformation { + public: + GpgImportInformation() = default; + + /** + * @brief Construct a new Gpg Import Information object + * + * @param result + */ + explicit GpgImportInformation(gpgme_import_result_t result) { + if (result->unchanged) unchanged = result->unchanged; + if (result->considered) considered = result->considered; + if (result->no_user_id) no_user_id = result->no_user_id; + if (result->imported) imported = result->imported; + if (result->imported_rsa) imported_rsa = result->imported_rsa; + if (result->unchanged) unchanged = result->unchanged; + if (result->new_user_ids) new_user_ids = result->new_user_ids; + if (result->new_sub_keys) new_sub_keys = result->new_sub_keys; + if (result->new_signatures) new_signatures = result->new_signatures; + if (result->new_revocations) new_revocations = result->new_revocations; + if (result->secret_read) secret_read = result->secret_read; + if (result->secret_imported) secret_imported = result->secret_imported; + if (result->secret_unchanged) secret_unchanged = result->secret_unchanged; + if (result->not_imported) not_imported = result->not_imported; + } + + int considered = 0; ///< + int no_user_id = 0; ///< + int imported = 0; ///< + int imported_rsa = 0; ///< + int unchanged = 0; ///< + int new_user_ids = 0; ///< + int new_sub_keys = 0; ///< + int new_signatures = 0; ///< + int new_revocations = 0; ///< + int secret_read = 0; ///< + int secret_imported = 0; ///< + int secret_unchanged = 0; ///< + int not_imported = 0; ///< + GpgImportedKeyList importedKeys; ///< +}; + +/** + * @brief + * + */ +class GpgKeyImportExporter + : public SingletonFunctionObject<GpgKeyImportExporter> { + public: + /** + * @brief Construct a new Gpg Key Import Exporter object + * + * @param channel + */ + explicit GpgKeyImportExporter( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgKeyImportExporter>(channel) {} + + /** + * @brief + * + * @param inBuffer + * @return GpgImportInformation + */ + GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer); + + /** + * @brief + * + * @param uid_list + * @param out_buffer + * @param secret + * @return true + * @return false + */ + bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, + bool secret = false) const; + + /** + * @brief + * + * @param keys + * @param outBuffer + * @param secret + * @return true + * @return false + */ + bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer, + bool secret = false) const; + + /** + * @brief + * + * @param key + * @param out_buffer + * @return true + * @return false + */ + bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const; + + /** + * @brief + * + * @param key + * @param out_buffer + * @return true + * @return false + */ + bool ExportKeyOpenSSH(const GpgKey& key, ByteArrayPtr& out_buffer) const; + + /** + * @brief + * + * @param key + * @param outBuffer + * @return true + * @return false + */ + bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const; + + /** + * @brief + * + * @param key + * @param outBuffer + * @return true + * @return false + */ + bool ExportSecretKeyShortest(const GpgKey& key, + ByteArrayPtr& outBuffer) const; + + private: + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< +}; + +} // namespace GpgFrontend + +#endif // _GPGKEYIMPORTEXPORTOR_H
\ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp new file mode 100644 index 00000000..c17df49e --- /dev/null +++ b/src/core/function/gpg/GpgKeyManager.cpp @@ -0,0 +1,92 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgKeyManager.h" + +#include <boost/date_time/posix_time/conversion.hpp> +#include <string> + +#include "GpgBasicOperator.h" +#include "GpgKeyGetter.h" + +bool GpgFrontend::GpgKeyManager::SignKey( + const GpgFrontend::GpgKey& target, GpgFrontend::KeyArgsList& keys, + const std::string& uid, + const std::unique_ptr<boost::posix_time::ptime>& expires) { + using namespace boost::posix_time; + + GpgBasicOperator::GetInstance().SetSigners(keys); + + unsigned int flags = 0; + unsigned int expires_time_t = 0; + + if (expires == nullptr) + flags |= GPGME_KEYSIGN_NOEXPIRE; + else + expires_time_t = to_time_t(*expires); + + auto err = check_gpg_error(gpgme_op_keysign( + ctx_, gpgme_key_t(target), uid.c_str(), expires_time_t, flags)); + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} + +bool GpgFrontend::GpgKeyManager::RevSign( + const GpgFrontend::GpgKey& key, + const GpgFrontend::SignIdArgsListPtr& signature_id) { + auto& key_getter = GpgKeyGetter::GetInstance(); + + for (const auto& sign_id : *signature_id) { + auto signing_key = key_getter.GetKey(sign_id.first); + assert(signing_key.IsGood()); + auto err = check_gpg_error(gpgme_op_revsig(ctx_, gpgme_key_t(key), + gpgme_key_t(signing_key), + sign_id.second.c_str(), 0)); + if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) return false; + } + return true; +} + +bool GpgFrontend::GpgKeyManager::SetExpire( + const GpgFrontend::GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<boost::posix_time::ptime>& expires) { + using namespace boost::posix_time; + + unsigned long expires_time = 0; + + if (expires != nullptr) expires_time = to_time_t(ptime(*expires)); + + const char* sub_fprs = nullptr; + + if (subkey != nullptr) sub_fprs = subkey->GetFingerprint().c_str(); + + auto err = check_gpg_error( + gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, sub_fprs, 0)); + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h new file mode 100644 index 00000000..5bcac545 --- /dev/null +++ b/src/core/function/gpg/GpgKeyManager.h @@ -0,0 +1,93 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H +#define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H + +#include "core/GpgContext.h" +#include "core/GpgFunctionObject.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GpgKeyManager : public SingletonFunctionObject<GpgKeyManager> { + public: + /** + * @brief Construct a new Gpg Key Manager object + * + * @param channel + */ + explicit GpgKeyManager( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgKeyManager>(channel) {} + + /** + * @brief Sign a key pair(actually a certain uid) + * @param target target key pair + * @param uid target + * @param expires expire date and time of the signature + * @return if successful + */ + bool SignKey(const GpgKey& target, KeyArgsList& keys, const std::string& uid, + const std::unique_ptr<boost::posix_time::ptime>& expires); + + /** + * @brief + * + * @param key + * @param signature_id + * @return true + * @return false + */ + bool RevSign(const GpgFrontend::GpgKey& key, + const GpgFrontend::SignIdArgsListPtr& signature_id); + + /** + * @brief Set the Expire object + * + * @param key + * @param subkey + * @param expires + * @return true + * @return false + */ + bool SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<boost::posix_time::ptime>& expires); + + private: + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp new file mode 100644 index 00000000..23dcae9f --- /dev/null +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -0,0 +1,293 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgKeyOpera.h" + +#include <boost/asio.hpp> +#include <boost/date_time/posix_time/conversion.hpp> +#include <boost/format.hpp> +#include <boost/process/async_pipe.hpp> +#include <memory> +#include <string> +#include <vector> + +#include "core/GpgConstants.h" +#include "core/GpgGenKeyInfo.h" +#include "GpgCommandExecutor.h" +#include "GpgKeyGetter.h" + +/** + * Delete keys + * @param uidList key ids + */ +void GpgFrontend::GpgKeyOpera::DeleteKeys( + GpgFrontend::KeyIdArgsListPtr key_ids) { + GpgError err; + for (const auto& tmp : *key_ids) { + auto key = GpgKeyGetter::GetInstance().GetKey(tmp); + if (key.IsGood()) { + err = check_gpg_error( + gpgme_op_delete_ext(ctx_, gpgme_key_t(key), + GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE)); + assert(gpg_err_code(err) == GPG_ERR_NO_ERROR); + } else { + LOG(WARNING) << "GpgKeyOpera DeleteKeys get key failed" << tmp; + } + } +} + +/** + * Set the expire date and time of a key pair(actually the primary key) or + * subkey + * @param key target key pair + * @param subkey null if primary key + * @param expires date and time + * @return if successful + */ +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( + const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<boost::posix_time::ptime>& expires) { + unsigned long expires_time = 0; + + if (expires != nullptr) { + using namespace boost::posix_time; + using namespace std::chrono; + expires_time = + to_time_t(*expires) - system_clock::to_time_t(system_clock::now()); + } + + LOG(INFO) << key.GetId() << subkey_fpr << expires_time; + + GpgError err; + if (key.GetFingerprint() == subkey_fpr || subkey_fpr.empty()) + err = gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, nullptr, 0); + else + err = gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, + subkey_fpr.c_str(), 0); + + return err; +} + +/** + * Generate revoke cert of a key pair + * @param key target key pair + * @param outputFileName out file name(path) + * @return the process doing this job + */ +void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( + const GpgKey& key, const std::string& output_file_name) { + auto args = std::vector<std::string>{"--no-tty", + "--command-fd", + "0", + "--status-fd", + "1", + "-o", + output_file_name, + "--gen-revoke", + key.GetFingerprint()}; + + using boost::asio::async_write; + using boost::process::async_pipe; +#ifndef WINDOWS + GpgCommandExecutor::GetInstance().Execute( + args, [](async_pipe& in, async_pipe& out) -> void { + // boost::asio::streambuf buff; + // boost::asio::read_until(in, buff, '\n'); + // + // std::istream is(&buff); + // + // while (!is.eof()) { + // std::string line; + // is >> line; + // LOG(INFO) << "line" << line; + // boost::algorithm::trim(line); + // if (line == std::string("[GNUPG:] GET_BOOL + // gen_revoke.okay")) { + // + // } else if (line == + // std::string( + // "[GNUPG:] GET_LINE + // ask_revocation_reason.code")) { + // + // } else if (line == + // std::string( + // "[GNUPG:] GET_LINE + // ask_revocation_reason.text")) { + // + // } else if (line == + // std::string("[GNUPG:] GET_BOOL + // openfile.overwrite.okay")) { + // + // } else if (line == + // std::string( + // "[GNUPG:] GET_BOOL + // ask_revocation_reason.okay")) { + // + // } + // } + }); +#endif +} + +/** + * Generate a new key pair + * @param params key generation args + * @return error information + */ +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( + const std::unique_ptr<GenKeyInfo>& params, GpgGenKeyResult& result) { + auto userid_utf8 = params->GetUserid(); + const char* userid = userid_utf8.c_str(); + auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); + + LOG(INFO) << "params" << params->GetAlgo() << params->GetKeySizeStr(); + + const char* algo = algo_utf8.c_str(); + unsigned long expires = 0; + { + using namespace boost::posix_time; + using namespace std::chrono; + expires = to_time_t(ptime(params->GetExpireTime())) - + system_clock::to_time_t(system_clock::now()); + } + + GpgError err; + + if (ctx_.GetInfo().GnupgVersion >= "2.1.0") { + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + LOG(INFO) << "args: " << userid << algo << expires << flags; + + err = gpgme_op_createkey(ctx_, userid, algo, 0, expires, nullptr, flags); + + } else { + std::stringstream ss; + auto param_format = + boost::format{ + "<GnupgKeyParms format=\"internal\">\n" + "Key-Type: %1%\n" + "Key-Usage: sign\n" + "Key-Length: %2%\n" + "Name-Real: %3%\n" + "Name-Comment: %4%\n" + "Name-Email: %5%\n"} % + params->GetAlgo() % params->GetKeyLength() % params->GetName() % + params->GetComment() % params->GetEmail(); + ss << param_format; + + if (!params->IsNonExpired()) { + auto date = params->GetExpireTime().date(); + ss << boost::format{"Expire-Date: %1%\n"} % to_iso_string(date); + } else + ss << boost::format{"Expire-Date: 0\n"}; + if (!params->IsNoPassPhrase()) + ss << boost::format{"Passphrase: %1%\n"} % params->GetPassPhrase(); + + ss << "</GnupgKeyParms>"; + + DLOG(INFO) << "params" << std::endl << ss.str(); + + err = gpgme_op_genkey(ctx_, ss.str().c_str(), nullptr, nullptr); + } + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) { + auto temp_result = _new_result(gpgme_op_genkey_result(ctx_)); + std::swap(temp_result, result); + } + + return check_gpg_error(err); +} + +/** + * Generate a new subkey of a certain key pair + * @param key target key pair + * @param params opera args + * @return error info + */ +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( + const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params) { + if (!params->IsSubKey()) return GPG_ERR_CANCELED; + + auto algo_utf8 = (params->GetAlgo() + params->GetKeySizeStr()); + const char* algo = algo_utf8.c_str(); + unsigned long expires = 0; + { + using namespace boost::posix_time; + using namespace std::chrono; + expires = to_time_t(ptime(params->GetExpireTime())) - + system_clock::to_time_t(system_clock::now()); + } + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + + flags |= GPGME_CREATE_NOPASSWD; + + LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateSubkey Args: " << key.GetId() + << algo << expires << flags; + + auto err = + gpgme_op_createsubkey(ctx_, gpgme_key_t(key), algo, 0, expires, flags); + return check_gpg_error(err); +} + +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword( + const GpgFrontend::GpgKey& key) { + if (ctx_.GetInfo().GnupgVersion < "2.0.15") { + LOG(ERROR) << _("operator not support"); + return GPG_ERR_NOT_SUPPORTED; + } + auto err = gpgme_op_passwd(ctx_, gpgme_key_t(key), 0); + return check_gpg_error(err); +} +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy( + const GpgFrontend::GpgKey& key, gpgme_tofu_policy_t tofu_policy) { + if (ctx_.GetInfo().GnupgVersion < "2.1.10") { + LOG(ERROR) << _("operator not support"); + return GPG_ERR_NOT_SUPPORTED; + } + auto err = gpgme_op_tofu_policy(ctx_, gpgme_key_t(key), tofu_policy); + return check_gpg_error(err); +} + +void GpgFrontend::GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { + auto keys = std::make_unique<KeyIdArgsList>(); + keys->push_back(key_id); + DeleteKeys(std::move(keys)); +} diff --git a/src/core/function/gpg/GpgKeyOpera.h b/src/core/function/gpg/GpgKeyOpera.h new file mode 100644 index 00000000..04571c10 --- /dev/null +++ b/src/core/function/gpg/GpgKeyOpera.h @@ -0,0 +1,135 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef _GPGKEYOPERA_H +#define _GPGKEYOPERA_H + +#include "core/GpgConstants.h" +#include "core/GpgContext.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { +/** + * @brief + * + */ +class GenKeyInfo; + +/** + * @brief + * + */ +class GpgKeyOpera : public SingletonFunctionObject<GpgKeyOpera> { + public: + /** + * @brief Construct a new Gpg Key Opera object + * + * @param channel + */ + explicit GpgKeyOpera( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgKeyOpera>(channel) {} + + /** + * @brief + * + * @param key_ids + */ + void DeleteKeys(KeyIdArgsListPtr key_ids); + + /** + * @brief + * + * @param key_id + */ + void DeleteKey(const KeyId& key_id); + + /** + * @brief Set the Expire object + * + * @param key + * @param subkey_fpr + * @param expires + * @return GpgError + */ + GpgError SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<boost::posix_time::ptime>& expires); + + /** + * @brief + * + * @param key + * @param output_file_name + */ + static void GenerateRevokeCert(const GpgKey& key, + const std::string& output_file_name); + + /** + * @brief + * + * @param key + * @return GpgFrontend::GpgError + */ + GpgFrontend::GpgError ModifyPassword(const GpgKey& key); + + /** + * @brief + * + * @param key + * @param tofu_policy + * @return GpgFrontend::GpgError + */ + GpgFrontend::GpgError ModifyTOFUPolicy(const GpgKey& key, + gpgme_tofu_policy_t tofu_policy); + /** + * @brief + * + * @param params + * @param result + * @return GpgFrontend::GpgError + */ + GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params, + GpgGenKeyResult& result); + + /** + * @brief + * + * @param key + * @param params + * @return GpgFrontend::GpgError + */ + GpgFrontend::GpgError GenerateSubkey( + const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params); + + private: + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< +}; +} // namespace GpgFrontend + +#endif // _GPGKEYOPERA_H
\ No newline at end of file diff --git a/src/core/function/gpg/GpgUIDOperator.cpp b/src/core/function/gpg/GpgUIDOperator.cpp new file mode 100644 index 00000000..dd0c43f6 --- /dev/null +++ b/src/core/function/gpg/GpgUIDOperator.cpp @@ -0,0 +1,68 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgUIDOperator.h" + +#include "boost/format.hpp" + +bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, + const std::string& uid) { + auto err = gpgme_op_adduid(ctx_, gpgme_key_t(key), uid.c_str(), 0); + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + return true; + else + return false; +} + +bool GpgFrontend::GpgUIDOperator::RevUID(const GpgFrontend::GpgKey& key, + const std::string& uid) { + auto err = + check_gpg_error(gpgme_op_revuid(ctx_, gpgme_key_t(key), uid.c_str(), 0)); + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + return true; + else + return false; +} + +bool GpgFrontend::GpgUIDOperator::SetPrimaryUID(const GpgFrontend::GpgKey& key, + const std::string& uid) { + auto err = check_gpg_error(gpgme_op_set_uid_flag( + ctx_, gpgme_key_t(key), uid.c_str(), "primary", nullptr)); + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + return true; + else + return false; +} +bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, + const std::string& name, + const std::string& comment, + const std::string& email) { + LOG(INFO) << "GpgFrontend::UidOperator::AddUID" << name << comment << email; + auto uid = boost::format("%1%(%2%)<%3%>") % name % comment % email; + return AddUID(key, uid.str()); +} diff --git a/src/core/function/gpg/GpgUIDOperator.h b/src/core/function/gpg/GpgUIDOperator.h new file mode 100644 index 00000000..479505e5 --- /dev/null +++ b/src/core/function/gpg/GpgUIDOperator.h @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H +#define GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H + +#include "core/GpgContext.h" +#include "core/GpgModel.h" + +namespace GpgFrontend { +/** + * @brief + * + */ +class GpgUIDOperator : public SingletonFunctionObject<GpgUIDOperator> { + public: + explicit GpgUIDOperator( + int channel = SingletonFunctionObject::GetDefaultChannel()) + : SingletonFunctionObject<GpgUIDOperator>(channel) {} + + /** + * create a new uid in certain key pair + * @param key target key pair + * @param uid uid args(combine name&comment&email) + * @return if successful + */ + bool AddUID(const GpgKey& key, const std::string& uid); + + /** + * create a new uid in certain key pair + * @param key target key pair + * @param name + * @param comment + * @param email + * @return + */ + bool AddUID(const GpgKey& key, const std::string& name, + const std::string& comment, const std::string& email); + + /** + * Revoke(Delete) UID from certain key pair + * @param key target key pair + * @param uid target uid + * @return if successful + */ + bool RevUID(const GpgKey& key, const std::string& uid); + + /** + * Set one of a uid of a key pair as primary + * @param key target key pair + * @param uid target uid + * @return if successful + */ + bool SetPrimaryUID(const GpgKey& key, const std::string& uid); + + private: + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp new file mode 100644 index 00000000..ff3d2e27 --- /dev/null +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgDecryptResultAnalyse.h" + +#include "function/gpg/GpgKeyGetter.h" + +GpgFrontend::GpgDecryptResultAnalyse::GpgDecryptResultAnalyse(GpgError m_error, + GpgDecrResult m_result) + : error_(m_error), result_(std::move(m_result)) {} + +void GpgFrontend::GpgDecryptResultAnalyse::do_analyse() { + stream_ << "[#] " << _("Decrypt Operation"); + + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << "[" << _("Success") << "]" << std::endl; + } else { + stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) + << std::endl; + set_status(-1); + if (result_ != nullptr && result_->unsupported_algorithm != nullptr) { + stream_ << "------------>" << std::endl; + stream_ << _("Unsupported Algo") << ": " << result_->unsupported_algorithm + << std::endl; + } + } + + if (result_ != nullptr && result_->recipients != nullptr) { + stream_ << "------------>" << std::endl; + if (result_->file_name != nullptr) { + stream_ << _("File Name") << ": " << result_->file_name << std::endl; + stream_ << std::endl; + } + if (result_->is_mime) { + stream_ << _("MIME") << ": " << _("true") << std::endl; + } + + auto recipient = result_->recipients; + if (recipient != nullptr) stream_ << _("Recipient(s)") << ": " << std::endl; + while (recipient != nullptr) { + print_recipient(stream_, recipient); + recipient = recipient->next; + } + stream_ << "<------------" << std::endl; + } + + stream_ << std::endl; +} + +void GpgFrontend::GpgDecryptResultAnalyse::print_recipient( + std::stringstream &stream, gpgme_recipient_t recipient) { + // check + if (recipient->keyid == nullptr) return; + + stream << " {>} " << _("Recipient") << ": "; + auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(recipient->keyid); + if (key.IsGood()) { + stream << key.GetName().c_str(); + if (!key.GetEmail().empty()) { + stream << "<" << key.GetEmail().c_str() << ">"; + } + } else { + stream << "<" << _("Unknown") << ">"; + set_status(0); + } + + stream << std::endl; + + stream << " " << _("Key ID") << ": " << recipient->keyid << std::endl; + stream << " " << _("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(recipient->pubkey_algo) << std::endl; +} diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.h b/src/core/function/result_analyse/GpgDecryptResultAnalyse.h new file mode 100644 index 00000000..af42f995 --- /dev/null +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.h @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H +#define GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H + +#include "GpgResultAnalyse.h" +#include "core/GpgConstants.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GpgDecryptResultAnalyse : public GpgResultAnalyse { + public: + /** + * @brief Construct a new Decrypt Result Analyse object + * + * @param m_error + * @param m_result + */ + explicit GpgDecryptResultAnalyse(GpgError m_error, GpgDecrResult m_result); + + protected: + /** + * @brief + * + */ + void do_analyse() final; + + private: + /** + * @brief + * + * @param stream + * @param recipient + */ + void print_recipient(std::stringstream &stream, gpgme_recipient_t recipient); + + GpgError error_; ///< + GpgDecrResult result_; ///< +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp new file mode 100644 index 00000000..053a15a5 --- /dev/null +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgEncryptResultAnalyse.h" + +GpgFrontend::GpgEncryptResultAnalyse::GpgEncryptResultAnalyse(GpgError error, + GpgEncrResult result) + : error_(error), result_(std::move(result)) {} + +void GpgFrontend::GpgEncryptResultAnalyse::do_analyse() { + LOG(INFO) << _("Start Encrypt Result Analyse"); + + stream_ << "[#] " << _("Encrypt Operation") << " "; + + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) + stream_ << "[" << _("Success") << "]" << std::endl; + else { + stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) + << std::endl; + set_status(-1); + } + + if (!~status_) { + stream_ << "------------>" << std::endl; + if (result_ != nullptr) { + stream_ << _("Invalid Recipients") << ": " << std::endl; + auto inv_reci = result_->invalid_recipients; + while (inv_reci != nullptr) { + stream_ << _("Fingerprint") << ": " << inv_reci->fpr << std::endl; + stream_ << _("Reason") << ": " << gpgme_strerror(inv_reci->reason) + << std::endl; + stream_ << std::endl; + + inv_reci = inv_reci->next; + } + } + stream_ << "<------------" << std::endl; + } + + stream_ << std::endl; +} diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.h b/src/core/function/result_analyse/GpgEncryptResultAnalyse.h new file mode 100644 index 00000000..c5125fdc --- /dev/null +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.h @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H +#define GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H + +#include "GpgResultAnalyse.h" +#include "core/GpgConstants.h" + +namespace GpgFrontend { +/** + * @brief + * + */ +class GpgEncryptResultAnalyse : public GpgResultAnalyse { + public: + /** + * @brief Construct a new Encrypt Result Analyse object + * + * @param error + * @param result + */ + explicit GpgEncryptResultAnalyse(GpgError error, GpgEncrResult result); + + protected: + /** + * @brief + * + */ + void do_analyse() final; + + private: + GpgError error_; ///< + GpgEncrResult result_; ///< +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgResultAnalyse.cpp b/src/core/function/result_analyse/GpgResultAnalyse.cpp new file mode 100644 index 00000000..40ba4c3e --- /dev/null +++ b/src/core/function/result_analyse/GpgResultAnalyse.cpp @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgResultAnalyse.h" + +const std::string GpgFrontend::GpgResultAnalyse::GetResultReport() const { + return stream_.str(); +} + +int GpgFrontend::GpgResultAnalyse::GetStatus() const { return status_; } + +void GpgFrontend::GpgResultAnalyse::set_status(int m_status) { + if (m_status < status_) status_ = m_status; +} + +void GpgFrontend::GpgResultAnalyse::Analyse() { + if (!analysed_) { + do_analyse(); + analysed_ = true; + } +} diff --git a/src/core/function/result_analyse/GpgResultAnalyse.h b/src/core/function/result_analyse/GpgResultAnalyse.h new file mode 100644 index 00000000..888c6449 --- /dev/null +++ b/src/core/function/result_analyse/GpgResultAnalyse.h @@ -0,0 +1,86 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#ifndef GPGFRONTEND_GPGRESULTANALYSE_H +#define GPGFRONTEND_GPGRESULTANALYSE_H + +#include <sstream> +#include <string> + +#include "core/GpgConstants.h" +namespace GpgFrontend { + +class GpgResultAnalyse { + public: + /** + * @brief Construct a new Result Analyse object + * + */ + GpgResultAnalyse() = default; + + /** + * @brief Get the Result Report object + * + * @return const std::string + */ + [[nodiscard]] const std::string GetResultReport() const; + + /** + * @brief Get the Status object + * + * @return int + */ + [[nodiscard]] int GetStatus() const; + + /** + * @brief + * + */ + void Analyse(); + + protected: + /** + * @brief + * + */ + virtual void do_analyse() = 0; + + /** + * @brief Set the status object + * + * @param m_status + */ + void set_status(int m_status); + + std::stringstream stream_; ///< + int status_ = 1; ///< + bool analysed_ = false; ///< +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp new file mode 100644 index 00000000..e389523c --- /dev/null +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgSignResultAnalyse.h" + +#include "function/gpg/GpgKeyGetter.h" + +GpgFrontend::GpgSignResultAnalyse::GpgSignResultAnalyse(GpgError error, + GpgSignResult result) + : error_(error), result_(std::move(result)) {} + +void GpgFrontend::GpgSignResultAnalyse::do_analyse() { + LOG(INFO) << _("Start Sign Result Analyse"); + + stream_ << "[#] " << _("Sign Operation") << " "; + + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) + stream_ << "[" << _("Success") << "]" << std::endl; + else { + stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) + << std::endl; + set_status(-1); + } + + if (result_ != nullptr && + (result_->signatures != nullptr || result_->invalid_signers != nullptr)) { + LOG(INFO) << _("Sign Result Analyse Getting Result"); + stream_ << "------------>" << std::endl; + auto new_sign = result_->signatures; + + while (new_sign != nullptr) { + stream_ << "[>]" << _("New Signature") << ": " << std::endl; + + LOG(INFO) << _("Signers Fingerprint") << ": " << new_sign->fpr; + + stream_ << " " << _("Sign Mode") << ": "; + if (new_sign->type == GPGME_SIG_MODE_NORMAL) + stream_ << _("Normal"); + else if (new_sign->type == GPGME_SIG_MODE_CLEAR) + stream_ << _("Clear"); + else if (new_sign->type == GPGME_SIG_MODE_DETACH) + stream_ << _("Detach"); + + stream_ << std::endl; + + auto singerKey = + GpgFrontend::GpgKeyGetter::GetInstance().GetKey(new_sign->fpr); + if (singerKey.IsGood()) { + stream_ << " " << _("Signer") << ": " + << singerKey.GetUIDs()->front().GetUID() << std::endl; + } else { + stream_ << " " << _("Signer") << ": " + << "<unknown>" << std::endl; + } + stream_ << " " << _("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << std::endl; + stream_ << " " << _("Hash Algo") << ": " + << gpgme_hash_algo_name(new_sign->hash_algo) << std::endl; + stream_ << " " << _("Date") << "(" << _("UTC") << ")" + << ": " + << boost::posix_time::to_iso_extended_string( + boost::posix_time::from_time_t(new_sign->timestamp)) + << std::endl; + + stream_ << std::endl; + + new_sign = new_sign->next; + } + + LOG(INFO) << _("Sign Result Analyse Getting Invalid Signer"); + + auto invalid_signer = result_->invalid_signers; + + if (invalid_signer != nullptr) + stream_ << _("Invalid Signers") << ": " << std::endl; + + while (invalid_signer != nullptr) { + set_status(0); + stream_ << "[>] " << _("Signer") << ": " << std::endl; + stream_ << " " << _("Fingerprint") << ": " << invalid_signer->fpr + << std::endl; + stream_ << " " << _("Reason") << ": " + << gpgme_strerror(invalid_signer->reason) << std::endl; + stream_ << std::endl; + + invalid_signer = invalid_signer->next; + } + stream_ << "<------------" << std::endl; + } +}
\ No newline at end of file diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.h b/src/core/function/result_analyse/GpgSignResultAnalyse.h new file mode 100644 index 00000000..d593b33d --- /dev/null +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.h @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_GPGSIGNRESULTANALYSE_H +#define GPGFRONTEND_GPGSIGNRESULTANALYSE_H + +#include "GpgResultAnalyse.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GpgSignResultAnalyse : public GpgResultAnalyse { + public: + /** + * @brief Construct a new Sign Result Analyse object + * + * @param error + * @param result + */ + explicit GpgSignResultAnalyse(GpgError error, GpgSignResult result); + + protected: + /** + * @brief + * + */ + void do_analyse(); + + private: + GpgError error_; ///< + + GpgSignResult result_; ///< +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGSIGNRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp new file mode 100644 index 00000000..44031e67 --- /dev/null +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp @@ -0,0 +1,214 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgVerifyResultAnalyse.h" + +#include <boost/format.hpp> + +#include "GpgFrontend.h" +#include "core/GpgConstants.h" +#include "function/gpg/GpgKeyGetter.h" + +GpgFrontend::GpgVerifyResultAnalyse::GpgVerifyResultAnalyse(GpgError error, + GpgVerifyResult result) + : error_(error), result_(std::move(result)) {} + +void GpgFrontend::GpgVerifyResultAnalyse::do_analyse() { + LOG(INFO) << _("started"); + + stream_ << "[#] " << _("Verify Operation") << " "; + + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) + stream_ << "[" << _("Success") << "]" << std::endl; + else { + stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) + << std::endl; + set_status(-1); + } + + if (result_ != nullptr && result_->signatures != nullptr) { + stream_ << "------------>" << std::endl; + auto sign = result_->signatures; + + stream_ << "[>] " << _("Signed On") << "(" << _("UTC") << ")" + << " " + << boost::posix_time::to_iso_extended_string( + boost::posix_time::from_time_t(sign->timestamp)) + << std::endl; + + stream_ << std::endl << "[>] " << _("Signatures List") << ":" << std::endl; + + bool canContinue = true; + + int count = 1; + while (sign && canContinue) { + stream_ << boost::format(_("Signature [%1%]:")) % count++ << std::endl; + switch (gpg_err_code(sign->status)) { + case GPG_ERR_BAD_SIGNATURE: + stream_ << _("A Bad Signature.") << std::endl; + print_signer(stream_, sign); + stream_ << _("This Signature is invalid.") << std::endl; + canContinue = false; + set_status(-1); + break; + case GPG_ERR_NO_ERROR: + stream_ << _("A") << " "; + if (sign->summary & GPGME_SIGSUM_GREEN) { + stream_ << _("Good") << " "; + } + if (sign->summary & GPGME_SIGSUM_RED) { + stream_ << _("Bad") << " "; + } + if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) { + stream_ << _("Expired") << " "; + } + if (sign->summary & GPGME_SIGSUM_KEY_MISSING) { + stream_ << _("Missing Key's") << " "; + } + if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) { + stream_ << _("Revoked Key's") << " "; + } + if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) { + stream_ << _("Expired Key's") << " "; + } + if (sign->summary & GPGME_SIGSUM_CRL_MISSING) { + stream_ << _("Missing CRL's") << " "; + } + + if (sign->summary & GPGME_SIGSUM_VALID) { + stream_ << _("Signature Fully Valid.") << std::endl; + } else { + stream_ << _("Signature Not Fully Valid.") << std::endl; + } + + if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) { + if (!print_signer(stream_, sign)) set_status(0); + } else { + stream_ << _("Key is NOT present with ID 0x") << sign->fpr + << std::endl; + } + + set_status(1); + + break; + case GPG_ERR_NO_PUBKEY: + stream_ << _("A signature could NOT be verified due to a Missing Key") + << std::endl; + set_status(-2); + break; + case GPG_ERR_CERT_REVOKED: + stream_ << _("A signature is valid but the key used to verify the " + "signature has been revoked") + << std::endl; + if (!print_signer(stream_, sign)) { + set_status(0); + } + set_status(-1); + break; + case GPG_ERR_SIG_EXPIRED: + stream_ << _("A signature is valid but expired") << std::endl; + if (!print_signer(stream_, sign)) { + set_status(0); + } + set_status(-1); + break; + case GPG_ERR_KEY_EXPIRED: + stream_ << _("A signature is valid but the key used to " + "verify the signature has expired.") + << std::endl; + if (!print_signer(stream_, sign)) { + set_status(0); + } + break; + case GPG_ERR_GENERAL: + stream_ << _("There was some other error which prevented " + "the signature verification.") + << std::endl; + status_ = -1; + canContinue = false; + break; + default: + auto fpr = std::string(sign->fpr); + stream_ << _("Error for key with fingerprint") << " " + << GpgFrontend::beautify_fingerprint(fpr); + set_status(-1); + } + stream_ << std::endl; + sign = sign->next; + } + stream_ << "<------------" << std::endl; + } else { + stream_ + << "[>] " + << _("Could not find information that can be used for verification.") + << std::endl; + set_status(0); + return; + } +} + +bool GpgFrontend::GpgVerifyResultAnalyse::print_signer(std::stringstream &stream, + gpgme_signature_t sign) { + bool keyFound = true; + auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(sign->fpr); + + if (!key.IsGood()) { + stream << " " << _("Signed By") << ": " + << "<" << _("Unknown") << ">" << std::endl; + set_status(0); + keyFound = false; + } else { + stream << " " << _("Signed By") << ": " + << key.GetUIDs()->front().GetUID() << std::endl; + } + if (sign->pubkey_algo) + stream << " " << _("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl; + if (sign->hash_algo) + stream << " " << _("Hash Algo") << ": " + << gpgme_hash_algo_name(sign->hash_algo) << std::endl; + if (sign->timestamp) + stream << " " << _("Date") << "(" << _("UTC") << ")" + << ": " + << boost::posix_time::to_iso_extended_string( + boost::posix_time::from_time_t(sign->timestamp)) + << std::endl; + stream << std::endl; + return keyFound; +} + +gpgme_signature_t GpgFrontend::GpgVerifyResultAnalyse::GetSignatures() const { + if (result_) + return result_->signatures; + else + return nullptr; +} +GpgFrontend::GpgVerifyResult +GpgFrontend::GpgVerifyResultAnalyse::TakeChargeOfResult() { + return std::move(result_); +} diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.h b/src/core/function/result_analyse/GpgVerifyResultAnalyse.h new file mode 100644 index 00000000..12e4b7ff --- /dev/null +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.h @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_GPGVERIFYRESULTANALYSE_H +#define GPGFRONTEND_GPGVERIFYRESULTANALYSE_H + +#include "GpgResultAnalyse.h" +#include "core/model/GpgKeySignature.h" + +namespace GpgFrontend { +/** + * @brief + * + */ +class GpgVerifyResultAnalyse : public GpgResultAnalyse { + public: + /** + * @brief Construct a new Verify Result Analyse object + * + * @param error + * @param result + */ + explicit GpgVerifyResultAnalyse(GpgError error, GpgVerifyResult result); + + /** + * @brief Get the Signatures object + * + * @return gpgme_signature_t + */ + gpgme_signature_t GetSignatures() const; + + /** + * @brief + * + * @return GpgVerifyResult + */ + GpgVerifyResult TakeChargeOfResult(); + + private: + /** + * @brief + * + */ + void do_analyse(); + + private: + /** + * @brief + * + * @param stream + * @param sign + * @return true + * @return false + */ + bool print_signer(std::stringstream &stream, gpgme_signature_t sign); + + GpgError error_; ///< + GpgVerifyResult result_; ///< +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGVERIFYRESULTANALYSE_H |