From 00c46e07ac0fa8a75f5d6e080a14e1da5edf1e4e Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 29 Apr 2026 00:03:19 -0700 Subject: post encoding and decoding this is not encryption but acts as a sort of pseudo deterrent? --- src/main.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 576eb27..2d94889 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,13 +3,17 @@ #include #include #include +#include +#include +#include +#include #include "markdown_translator.hpp" #include "file_uploader.hpp" #include "rclone_uploader.hpp" bool parseArguments(int argc, char* argv[], std::unordered_map& params, std::string& inputFile) { if (argc < 2) { - std::cerr << "Usage: COMMAND [-o ] [-css ] [other options]\n"; + std::cerr << "Usage: COMMAND [-o ] [-css ] [--encode ] [other options]\n"; return false; } params["-o"] = "index.html"; @@ -42,6 +46,69 @@ bool parseArguments(int argc, char* argv[], std::unordered_map& data) { + if (data.empty()) return std::string(); + size_t out_len = 4 * ((data.size() + 2) / 3) + 1; + std::vector out(out_len); + int written = EVP_EncodeBlock(out.data(), data.data(), (int)data.size()); + return std::string(reinterpret_cast(out.data()), written); +} + +static std::vector encryptAESGCM(const std::string& plaintext, const std::string& passphrase) { + const int SALT_LEN = 16; + const int IV_LEN = 12; + const int TAG_LEN = 16; + const int KEY_LEN = 32; + const int PBKDF2_ITER = 100000; + + std::vector salt(SALT_LEN); + if (RAND_bytes(salt.data(), SALT_LEN) != 1) { + throw std::runtime_error("RAND_bytes for salt failed"); + } + + std::vector iv(IV_LEN); + if (RAND_bytes(iv.data(), IV_LEN) != 1) { + throw std::runtime_error("RAND_bytes for iv failed"); + } + + std::vector key(KEY_LEN); + if (PKCS5_PBKDF2_HMAC(passphrase.c_str(), (int)passphrase.size(), salt.data(), SALT_LEN, PBKDF2_ITER, EVP_sha256(), KEY_LEN, key.data()) != 1) { + throw std::runtime_error("PBKDF2 key derivation failed"); + } + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) throw std::runtime_error("EVP_CIPHER_CTX_new failed"); + + int rc = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + if (rc != 1) { EVP_CIPHER_CTX_free(ctx); throw std::runtime_error("EVP_EncryptInit_ex failed"); } + rc = EVP_EncryptInit_ex(ctx, NULL, NULL, key.data(), iv.data()); + if (rc != 1) { EVP_CIPHER_CTX_free(ctx); throw std::runtime_error("EVP_EncryptInit_ex set key/iv failed"); } + + std::vector ciphertext(plaintext.size()); + int outlen = 0; + rc = EVP_EncryptUpdate(ctx, ciphertext.data(), &outlen, reinterpret_cast(plaintext.data()), (int)plaintext.size()); + if (rc != 1) { EVP_CIPHER_CTX_free(ctx); throw std::runtime_error("EVP_EncryptUpdate failed"); } + int tmplen = 0; + rc = EVP_EncryptFinal_ex(ctx, ciphertext.data() + outlen, &tmplen); + if (rc != 1) { EVP_CIPHER_CTX_free(ctx); throw std::runtime_error("EVP_EncryptFinal_ex failed"); } + int cipher_len = outlen + tmplen; + ciphertext.resize(cipher_len); + + std::vector tag(TAG_LEN); + rc = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_LEN, tag.data()); + if (rc != 1) { EVP_CIPHER_CTX_free(ctx); throw std::runtime_error("EVP_CIPHER_CTX_ctrl GET_TAG failed"); } + + EVP_CIPHER_CTX_free(ctx); + std::vector out; + out.reserve(salt.size() + iv.size() + ciphertext.size() + tag.size()); + out.insert(out.end(), salt.begin(), salt.end()); + out.insert(out.end(), iv.begin(), iv.end()); + out.insert(out.end(), ciphertext.begin(), ciphertext.end()); + out.insert(out.end(), tag.begin(), tag.end()); + return out; +} + int main(int argc, char* argv[]) { std::unordered_map params; std::string inputFile; @@ -77,6 +144,52 @@ int main(int argc, char* argv[]) { std::string htmlOutput = translator.translate(markdownContent); + if (params.find("--encode") != params.end() && !params["--encode"].empty()) { + try { + std::string startMarker = "
"; + size_t startPos = htmlOutput.find(startMarker); + if (startPos != std::string::npos) { + const std::string endMarker = ""; + size_t endPos = htmlOutput.find(endMarker, startPos); + if (endPos != std::string::npos) { + std::string contentBlock = htmlOutput.substr(startPos, endPos - startPos); + + std::vector encrypted = encryptAESGCM(contentBlock, params["--encode"]); + std::string b64 = base64Encode(encrypted); + + std::stringstream repl; + repl << "
\n"; + repl << "
\n"; + repl << "
🔒
\n"; + repl << "

Encoded Content

\n"; + repl << "

Enter the passphrase to decode this post.

\n"; + repl << " \n"; + repl << "
\n"; + repl << "
\n"; + repl << "
\n"; + repl << "\n"; + htmlOutput = htmlOutput.substr(0, startPos) + repl.str() + + htmlOutput.substr(endPos + endMarker.length()); + } + } + } catch (const std::exception& ex) { + } + } + + // Always strip the WIKI_CONTENT_END marker when not encrypted + { + const std::string marker = ""; + size_t pos = htmlOutput.find(marker); + if (pos != std::string::npos) + htmlOutput.erase(pos, marker.length()); + } + // Write to output file std::string outputFile = params["-o"]; std::ofstream outFile(outputFile); -- cgit v1.2.3