149 lines
5.3 KiB
C++
149 lines
5.3 KiB
C++
#include "json_parser.h"
|
|
#include <iostream>
|
|
#include <chrono>
|
|
#include <cryptopp/base64.h>
|
|
#include <cryptopp/filters.h>
|
|
#include <cryptopp/queue.h>
|
|
|
|
// Helper: Base64 encode without line breaks
|
|
static std::string encode_base64(const std::vector<unsigned char>& 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<unsigned char> decode_base64(const std::string& b64) {
|
|
std::string decoded;
|
|
CryptoPP::StringSource ss(
|
|
b64, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded))
|
|
);
|
|
return std::vector<unsigned char>(decoded.begin(), decoded.end());
|
|
}
|
|
|
|
json JsonParser::create_paste_json(const std::vector<unsigned char>& cipher_text,
|
|
const std::vector<unsigned char>& auth_tag,
|
|
const std::vector<unsigned char>& iv,
|
|
const std::vector<unsigned char>& 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::seconds>(
|
|
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<unsigned char>& cipher_text,
|
|
std::vector<unsigned char>& auth_tag,
|
|
std::vector<unsigned char>& iv,
|
|
std::vector<unsigned char>& 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<int>();
|
|
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;
|
|
}
|
|
} |