encrypt files

This commit is contained in:
2025-11-03 12:12:43 +01:00
parent cf1ac6d556
commit 5d9850a781
7 changed files with 66 additions and 24 deletions

View File

@@ -29,4 +29,12 @@ using f64 = double;
inline std::string path_to_filename(const std::string &path) { inline std::string path_to_filename(const std::string &path) {
u64 pos = path.find_last_of("/\\"); u64 pos = path.find_last_of("/\\");
return (pos == std::string::npos) ? path : path.substr(pos + 1); return (pos == std::string::npos) ? path : path.substr(pos + 1);
} }
template <typename T> constexpr char *to_char_ptr(T *ptr) noexcept {
return reinterpret_cast<char *>(ptr);
}
template <typename T> constexpr const char *to_char_ptr(const T *ptr) noexcept {
return reinterpret_cast<const char *>(ptr);
}

View File

@@ -8,6 +8,13 @@
namespace Crypto { namespace Crypto {
static Botan::AutoSeeded_RNG g_rng; // NOLINT
const Botan::secure_vector<u8> KEY = {
0xaa, 0x1b, 0x6c, 0xd2, 0x8e, 0x54, 0x9d, 0xdb, 0xe8, 0xd6, 0x9e,
0xe9, 0xa4, 0x19, 0xa4, 0xc1, 0x2, 0x73, 0x58, 0x82, 0xa3, 0x75,
0x5f, 0x86, 0xbd, 0x0, 0x92, 0x97, 0x1e, 0xf3, 0x27, 0x5d};
inline Botan::secure_vector<u8> inline Botan::secure_vector<u8>
encrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &plaintext, encrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &plaintext,
const Botan::secure_vector<u8> &key, const Botan::secure_vector<u8> &key,
@@ -33,9 +40,9 @@ inline Botan::secure_vector<u8>
decrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &ciphertext, decrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &ciphertext,
const Botan::secure_vector<u8> &key, const Botan::secure_vector<u8> &key,
const std::vector<u8> &nonce) { const std::vector<u8> &nonce) {
ASSERT(ciphertext.size() >= 16);
ASSERT(key.size() == 32); ASSERT(key.size() == 32);
ASSERT(nonce.size() == 24); ASSERT(nonce.size() == 24);
ASSERT(ciphertext.size() >= 16);
auto cipher = Botan::AEAD_Mode::create_or_throw( auto cipher = Botan::AEAD_Mode::create_or_throw(
"ChaCha20Poly1305", Botan::Cipher_Dir::Decryption); "ChaCha20Poly1305", Botan::Cipher_Dir::Decryption);

View File

@@ -1,7 +1,7 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QApplication> #include <QApplication>
int main(int argc, char *argv[]) { i32 main(i32 argc, char *argv[]) {
QApplication app(argc, argv); QApplication app(argc, argv);
MainWindow window; MainWindow window;

View File

@@ -4,6 +4,7 @@
#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <botan/hex.h>
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(std::make_unique<Ui::MainWindow>()) { : QMainWindow(parent), ui(std::make_unique<Ui::MainWindow>()) {
@@ -19,6 +20,11 @@ MainWindow::MainWindow(QWidget *parent)
return; return;
} }
std::ofstream create(path.toStdString(), std::ios::binary);
create.write("DULL", 4);
create.write(to_char_ptr(&VERSION), sizeof(VERSION));
create.close();
m_vault = std::make_unique<Vault>(path.toStdString()); m_vault = std::make_unique<Vault>(path.toStdString());
reload_fs_tree(); reload_fs_tree();
}); });
@@ -37,7 +43,7 @@ MainWindow::MainWindow(QWidget *parent)
connect( connect(
ui->fsTreeWidget, &QTreeWidget::itemClicked, ui->fsTreeWidget, &QTreeWidget::itemClicked,
[this](QTreeWidgetItem *, int) { ui->filePreview->setVisible(false); }); [this](QTreeWidgetItem *, i32) { ui->filePreview->setVisible(false); });
connect(ui->fsTreeWidget, &QTreeWidget::customContextMenuRequested, this, connect(ui->fsTreeWidget, &QTreeWidget::customContextMenuRequested, this,
&MainWindow::file_context_menu); &MainWindow::file_context_menu);
@@ -72,6 +78,7 @@ void MainWindow::reload_fs_tree() {
item->setText(0, QString::fromStdString(header.name)); item->setText(0, QString::fromStdString(header.name));
item->setText(1, QString::number(header.size)); item->setText(1, QString::number(header.size));
item->setText(2, QString::number(header.offset)); item->setText(2, QString::number(header.offset));
item->setText(3, QString::fromStdString(Botan::hex_encode(header.nonce)));
} }
ui->fsTreeWidget->resizeColumnToContents(0); ui->fsTreeWidget->resizeColumnToContents(0);
} }

View File

@@ -38,6 +38,11 @@
<string>Offset</string> <string>Offset</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>Nonce</string>
</property>
</column>
</widget> </widget>
</item> </item>
<item> <item>

View File

@@ -1,17 +1,12 @@
#include "vault.h" #include "vault.h"
#include "common.h" #include "common.h"
#include "crypto.h"
#include <array> #include <array>
#include <filesystem> #include <filesystem>
Vault::Vault(std::string path) : m_path(std::move(path)) { Vault::Vault(std::string path) : m_path(std::move(path)) {
m_file.open(m_path, std::ios::in | std::ios::out | std::ios::binary); m_file.open(m_path, std::ios::in | std::ios::out | std::ios::binary);
if (!m_file.is_open()) { ASSERT(m_file.is_open());
std::ofstream create(m_path, std::ios::binary);
create.write("DULL", 4);
create.write(reinterpret_cast<const char *>(&VERSION), sizeof(VERSION));
create.close();
m_file.open(m_path, std::ios::in | std::ios::out | std::ios::binary);
}
ASSERT(m_file.good()); ASSERT(m_file.good());
@@ -20,7 +15,7 @@ Vault::Vault(std::string path) : m_path(std::move(path)) {
ASSERT(std::string_view(header.data(), header.size()) == "DULL"); ASSERT(std::string_view(header.data(), header.size()) == "DULL");
i16 version = 0; i16 version = 0;
ASSERT(m_file.read(reinterpret_cast<char *>(&version), sizeof(version))); ASSERT(m_file.read(to_char_ptr(&version), sizeof(version)));
ASSERT(version == VERSION); ASSERT(version == VERSION);
} }
@@ -54,11 +49,16 @@ std::optional<std::string> Vault::read_file(const std::string &filename) {
} }
if (header->name == filename) { if (header->name == filename) {
std::string content(header->size, '\0'); Botan::secure_vector<u8> ciphertext;
if (!m_file.read(content.data(), static_cast<i64>(header->size))) { ciphertext.resize(header->size);
if (!m_file.read(to_char_ptr(ciphertext.data()),
static_cast<i64>(header->size))) {
break; break;
} }
return content;
auto plaintext = Crypto::decrypt_xchacha20_poly1305(
ciphertext, Crypto::KEY, header->nonce);
return std::string(to_char_ptr(plaintext.data()), plaintext.size());
} }
m_file.seekg(static_cast<i64>(header->size), std::ios::cur); m_file.seekg(static_cast<i64>(header->size), std::ios::cur);
@@ -73,13 +73,22 @@ void Vault::create_file(const std::string &filename,
m_file.seekp(0, std::ios::end); m_file.seekp(0, std::ios::end);
u64 filename_size = filename.size(); u64 filename_size = filename.size();
u64 content_size = content.size();
ASSERT(m_file.write(reinterpret_cast<const char *>(&filename_size), Botan::secure_vector<u8> plaintext(content.begin(), content.end());
sizeof(u64)));
auto nonce_sv = Crypto::g_rng.random_vec(24);
std::vector<u8> nonce(nonce_sv.begin(), nonce_sv.end());
auto ciphertext =
Crypto::encrypt_xchacha20_poly1305(plaintext, Crypto::KEY, nonce);
u64 ciphertext_size = ciphertext.size();
ASSERT(m_file.write(to_char_ptr(&filename_size), sizeof(u64)));
ASSERT(m_file.write(filename.data(), static_cast<i64>(filename_size))); ASSERT(m_file.write(filename.data(), static_cast<i64>(filename_size)));
ASSERT( ASSERT(m_file.write(to_char_ptr(nonce.data()), nonce.size()));
m_file.write(reinterpret_cast<const char *>(&content_size), sizeof(u64))); ASSERT(m_file.write(to_char_ptr(&ciphertext_size), sizeof(u64)));
ASSERT(m_file.write(content.data(), static_cast<i64>(content_size))); ASSERT(m_file.write(to_char_ptr(ciphertext.data()),
static_cast<i64>(ciphertext_size)));
m_file.flush(); m_file.flush();
} }
@@ -101,7 +110,7 @@ void Vault::delete_file(const std::string &filename) {
if (header->name == filename) { if (header->name == filename) {
entry_start = current_pos; entry_start = current_pos;
entry_total_size = entry_total_size =
sizeof(u64) + header->name.length() + sizeof(u64) + header->size; sizeof(u64) + header->name.length() + 24 + sizeof(u64) + header->size;
m_file.seekg(static_cast<i64>(header->size), std::ios::cur); m_file.seekg(static_cast<i64>(header->size), std::ios::cur);
break; break;
} }
@@ -144,7 +153,7 @@ std::optional<FileHeader> Vault::read_file_header(std::fstream &file) {
header.offset = file.tellg(); header.offset = file.tellg();
u64 name_size = 0; u64 name_size = 0;
if (!file.read(reinterpret_cast<char *>(&name_size), sizeof(u64))) { if (!file.read(to_char_ptr(&name_size), sizeof(u64))) {
return std::nullopt; return std::nullopt;
} }
@@ -155,7 +164,12 @@ std::optional<FileHeader> Vault::read_file_header(std::fstream &file) {
return std::nullopt; return std::nullopt;
} }
if (!file.read(reinterpret_cast<char *>(&header.size), sizeof(u64))) { header.nonce.resize(24);
if (!file.read(to_char_ptr(header.nonce.data()), 24)) {
return std::nullopt;
}
if (!file.read(to_char_ptr(&header.size), sizeof(u64))) {
return std::nullopt; return std::nullopt;
} }
return header; return header;

View File

@@ -11,6 +11,7 @@ constexpr u64 AFTER_HEADER_OFFSET = 6;
struct FileHeader { struct FileHeader {
std::string name; std::string name;
u64 size; u64 size;
std::vector<u8> nonce;
u64 offset; u64 offset;
}; };