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) {
u64 pos = path.find_last_of("/\\");
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 {
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>
encrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &plaintext,
const Botan::secure_vector<u8> &key,
@@ -33,9 +40,9 @@ inline Botan::secure_vector<u8>
decrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &ciphertext,
const Botan::secure_vector<u8> &key,
const std::vector<u8> &nonce) {
ASSERT(ciphertext.size() >= 16);
ASSERT(key.size() == 32);
ASSERT(nonce.size() == 24);
ASSERT(ciphertext.size() >= 16);
auto cipher = Botan::AEAD_Mode::create_or_throw(
"ChaCha20Poly1305", Botan::Cipher_Dir::Decryption);

View File

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

View File

@@ -4,6 +4,7 @@
#include <QInputDialog>
#include <QMessageBox>
#include <QTemporaryFile>
#include <botan/hex.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(std::make_unique<Ui::MainWindow>()) {
@@ -19,6 +20,11 @@ MainWindow::MainWindow(QWidget *parent)
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());
reload_fs_tree();
});
@@ -37,7 +43,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(
ui->fsTreeWidget, &QTreeWidget::itemClicked,
[this](QTreeWidgetItem *, int) { ui->filePreview->setVisible(false); });
[this](QTreeWidgetItem *, i32) { ui->filePreview->setVisible(false); });
connect(ui->fsTreeWidget, &QTreeWidget::customContextMenuRequested, this,
&MainWindow::file_context_menu);
@@ -72,6 +78,7 @@ void MainWindow::reload_fs_tree() {
item->setText(0, QString::fromStdString(header.name));
item->setText(1, QString::number(header.size));
item->setText(2, QString::number(header.offset));
item->setText(3, QString::fromStdString(Botan::hex_encode(header.nonce)));
}
ui->fsTreeWidget->resizeColumnToContents(0);
}

View File

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

View File

@@ -1,17 +1,12 @@
#include "vault.h"
#include "common.h"
#include "crypto.h"
#include <array>
#include <filesystem>
Vault::Vault(std::string path) : m_path(std::move(path)) {
m_file.open(m_path, std::ios::in | std::ios::out | std::ios::binary);
if (!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.is_open());
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");
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);
}
@@ -54,11 +49,16 @@ std::optional<std::string> Vault::read_file(const std::string &filename) {
}
if (header->name == filename) {
std::string content(header->size, '\0');
if (!m_file.read(content.data(), static_cast<i64>(header->size))) {
Botan::secure_vector<u8> ciphertext;
ciphertext.resize(header->size);
if (!m_file.read(to_char_ptr(ciphertext.data()),
static_cast<i64>(header->size))) {
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);
@@ -73,13 +73,22 @@ void Vault::create_file(const std::string &filename,
m_file.seekp(0, std::ios::end);
u64 filename_size = filename.size();
u64 content_size = content.size();
ASSERT(m_file.write(reinterpret_cast<const char *>(&filename_size),
sizeof(u64)));
Botan::secure_vector<u8> plaintext(content.begin(), content.end());
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(reinterpret_cast<const char *>(&content_size), sizeof(u64)));
ASSERT(m_file.write(content.data(), static_cast<i64>(content_size)));
ASSERT(m_file.write(to_char_ptr(nonce.data()), nonce.size()));
ASSERT(m_file.write(to_char_ptr(&ciphertext_size), sizeof(u64)));
ASSERT(m_file.write(to_char_ptr(ciphertext.data()),
static_cast<i64>(ciphertext_size)));
m_file.flush();
}
@@ -101,7 +110,7 @@ void Vault::delete_file(const std::string &filename) {
if (header->name == filename) {
entry_start = current_pos;
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);
break;
}
@@ -144,7 +153,7 @@ std::optional<FileHeader> Vault::read_file_header(std::fstream &file) {
header.offset = file.tellg();
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;
}
@@ -155,7 +164,12 @@ std::optional<FileHeader> Vault::read_file_header(std::fstream &file) {
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 header;

View File

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