/**
* 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 .
*
* 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 starting on May 12, 2021.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "DataObjectOperator.h"
#include
#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(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_.u8string(), 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.u8string(), encoded.toStdString());
return _key.empty() ? _hash_obj_key : std::string();
}
std::optional 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.u8string(), 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
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.u8string(), 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 {};
}
}