/**
* 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
#include "core/function/FileOperator.h"
#include "core/function/PassphraseGenerator.h"
void GpgFrontend::DataObjectOperator::init_app_secure_key() {
SPDLOG_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)) {
SPDLOG_ERROR("failed to read app secure key file: {}",
app_secure_key_path_.u8string());
throw std::runtime_error("failed to read app secure key file");
}
hash_key_ = QCryptographicHash::hash(QByteArray::fromStdString(key),
QCryptographicHash::Sha256);
SPDLOG_INFO("app secure key loaded {} bytes", hash_key_.size());
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_);
SPDLOG_INFO("saving data object {} to {} , size: {} bytes", _hash_obj_key,
obj_path.u8string(), encoded.size());
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 {
SPDLOG_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)) {
SPDLOG_ERROR("data object not found :{}", _key);
return {};
}
std::string buffer;
if (!FileOperator::ReadFileStd(obj_path.u8string(), buffer)) {
SPDLOG_ERROR("failed to read data object: {}", _key);
return {};
}
SPDLOG_INFO("data object found {}", _key);
auto encoded = QByteArray::fromStdString(buffer);
QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB,
QAESEncryption::Padding::ISO);
SPDLOG_INFO("decrypting data object {} , hash key size: {}", encoded.size(),
hash_key_.size());
auto decoded =
encryption.removePadding(encryption.decode(encoded, hash_key_));
SPDLOG_INFO("data object decoded: {}", _key);
return nlohmann::json::parse(decoded.toStdString());
} catch (...) {
SPDLOG_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 {};
}
}