#include "json_parser.h" #include #include #include #include #include // Helper: Base64 encode without line breaks static std::string encode_base64(const std::vector& data) { std::string result; CryptoPP::StringSource ss( data.data(), data.size(), true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(result), false /* insertLineBreaks */) ); return result; } // Helper: Base64 decode static std::vector decode_base64(const std::string& b64) { std::string decoded; CryptoPP::StringSource ss( b64, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)) ); return std::vector(decoded.begin(), decoded.end()); } json JsonParser::create_paste_json(const std::vector& cipher_text, const std::vector& auth_tag, const std::vector& iv, const std::vector& salt, const std::string& expiration, const std::string& format, bool burn_after_reading, bool open_discussion) { // Convert binary data to base64 strings std::string cipher_text_b64 = encode_base64(cipher_text); std::string iv_b64 = encode_base64(iv); std::string salt_b64 = encode_base64(salt); // Get current timestamp auto now = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); // Create the metadata array according to PrivateBin v2 json metadata = { { iv_b64, // base64(cipher_iv) salt_b64, // base64(kdf_salt) 100000, // iterations 256, // key size 128, // tag size "aes", // cipher "gcm", // mode "zlib" // compression }, format, // formatter key burn_after_reading ? 1 : 0, // burn after reading open_discussion ? 1 : 0 // open discussion }; // Create the main JSON structure // JSON close to v1.3 JSON-LD: meta.expire used by server json paste_json = { {"v", 2}, // version {"adata", metadata}, // metadata {"ct", cipher_text_b64}, // ciphertext (base64) {"meta", { {"expire", expiration} }} }; return paste_json; } bool JsonParser::parse_paste_json(const json& json_data, std::vector& cipher_text, std::vector& auth_tag, std::vector& iv, std::vector& salt, std::string& expiration) { try { // Extract and decode cipher text std::string ct_b64 = json_data.at("ct"); cipher_text = decode_base64(ct_b64); // Optional explicit tag field if (json_data.contains("tag")) { std::string tag_b64 = json_data.at("tag"); auth_tag = decode_base64(tag_b64); } else { auth_tag.clear(); } // Extract metadata and decode IV & salt json adata = json_data.at("adata"); if (adata.size() >= 1) { json first_element = adata[0]; if (first_element.is_array() && first_element.size() >= 2) { std::string iv_b64 = first_element[0]; std::string salt_b64 = first_element[1]; iv = decode_base64(iv_b64); salt = decode_base64(salt_b64); } } // Extract expiration; servers may return either meta.expire (string) // or meta.time_to_live (integer seconds). Both are optional for our use. try { expiration = json_data.at("meta").at("expire"); } catch (...) { try { auto ttl = json_data.at("meta").at("time_to_live").get(); expiration = std::to_string(ttl); } catch (...) { expiration.clear(); } } return true; } catch (...) { return false; } } bool JsonParser::parse_response(const std::string& response, int& status, std::string& message, std::string& paste_id, std::string& url, std::string& delete_token) { try { json json_response = json::parse(response); status = json_response.value("status", 1); if (status == 0) { paste_id = json_response.value("id", ""); url = json_response.value("url", ""); delete_token = json_response.value("deletetoken", ""); } else { message = json_response.value("message", ""); } return true; } catch (...) { return false; } }