diff --git a/src/common.h b/src/common.h index 06d4c01..fa33265 100644 --- a/src/common.h +++ b/src/common.h @@ -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); -} \ No newline at end of file +} + +template constexpr char *to_char_ptr(T *ptr) noexcept { + return reinterpret_cast(ptr); +} + +template constexpr const char *to_char_ptr(const T *ptr) noexcept { + return reinterpret_cast(ptr); +} diff --git a/src/crypto.h b/src/crypto.h index 69704c7..7789677 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -8,6 +8,13 @@ namespace Crypto { +static Botan::AutoSeeded_RNG g_rng; // NOLINT + +const Botan::secure_vector 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 encrypt_xchacha20_poly1305(const Botan::secure_vector &plaintext, const Botan::secure_vector &key, @@ -33,9 +40,9 @@ inline Botan::secure_vector decrypt_xchacha20_poly1305(const Botan::secure_vector &ciphertext, const Botan::secure_vector &key, const std::vector &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); diff --git a/src/main.cc b/src/main.cc index 6bd0704..94224dc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,7 +1,7 @@ #include "mainwindow.h" #include -int main(int argc, char *argv[]) { +i32 main(i32 argc, char *argv[]) { QApplication app(argc, argv); MainWindow window; diff --git a/src/mainwindow.cc b/src/mainwindow.cc index 985d4d0..755c274 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -4,6 +4,7 @@ #include #include #include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(std::make_unique()) { @@ -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(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); } diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 37c283e..8df10f0 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -38,6 +38,11 @@ Offset + + + Nonce + + diff --git a/src/vault.cc b/src/vault.cc index 048e50a..400b9a6 100644 --- a/src/vault.cc +++ b/src/vault.cc @@ -1,17 +1,12 @@ #include "vault.h" #include "common.h" +#include "crypto.h" #include #include 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(&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(&version), sizeof(version))); + ASSERT(m_file.read(to_char_ptr(&version), sizeof(version))); ASSERT(version == VERSION); } @@ -54,11 +49,16 @@ std::optional 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(header->size))) { + Botan::secure_vector ciphertext; + ciphertext.resize(header->size); + if (!m_file.read(to_char_ptr(ciphertext.data()), + static_cast(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(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(&filename_size), - sizeof(u64))); + + Botan::secure_vector plaintext(content.begin(), content.end()); + + auto nonce_sv = Crypto::g_rng.random_vec(24); + std::vector 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(filename_size))); - ASSERT( - m_file.write(reinterpret_cast(&content_size), sizeof(u64))); - ASSERT(m_file.write(content.data(), static_cast(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(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(header->size), std::ios::cur); break; } @@ -144,7 +153,7 @@ std::optional Vault::read_file_header(std::fstream &file) { header.offset = file.tellg(); u64 name_size = 0; - if (!file.read(reinterpret_cast(&name_size), sizeof(u64))) { + if (!file.read(to_char_ptr(&name_size), sizeof(u64))) { return std::nullopt; } @@ -155,7 +164,12 @@ std::optional Vault::read_file_header(std::fstream &file) { return std::nullopt; } - if (!file.read(reinterpret_cast(&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; diff --git a/src/vault.h b/src/vault.h index 3d5a9d9..79c9cdc 100644 --- a/src/vault.h +++ b/src/vault.h @@ -11,6 +11,7 @@ constexpr u64 AFTER_HEADER_OFFSET = 6; struct FileHeader { std::string name; u64 size; + std::vector nonce; u64 offset; };