Initial commit: PrivateBin API C++ DLL implementation
This commit is contained in:
218
src/privatebinapi.cpp
Normal file
218
src/privatebinapi.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#include "privatebinapi.h"
|
||||
#include "http_client.h"
|
||||
#include "crypto.h"
|
||||
#include "json_parser.h"
|
||||
#include "base58.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#define PRIVATEBIN_API_VERSION "1.3"
|
||||
|
||||
// Error codes
|
||||
#define ERROR_SUCCESS 0
|
||||
#define ERROR_NETWORK 1
|
||||
#define ERROR_CRYPTO 2
|
||||
#define ERROR_INVALID_INPUT 3
|
||||
#define ERROR_SERVER 4
|
||||
#define ERROR_JSON_PARSE 5
|
||||
|
||||
// Helper function to copy string to output parameter
|
||||
static void copy_string_to_output(const std::string& source, char** destination) {
|
||||
if (destination) {
|
||||
*destination = static_cast<char*>(malloc(source.length() + 1));
|
||||
if (*destination) {
|
||||
std::strcpy(*destination, source.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int create_paste(const char* server_url, const char* content,
|
||||
const char* password, const char* expiration,
|
||||
const char* format, int burn_after_reading,
|
||||
int open_discussion, char** paste_url,
|
||||
char** delete_token) {
|
||||
|
||||
if (!server_url || !content) {
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
try {
|
||||
// Generate a random 32-byte paste key
|
||||
std::vector<unsigned char> paste_key = Crypto::generate_key(32);
|
||||
|
||||
// If password provided, append it to the paste key
|
||||
std::string paste_passphrase(reinterpret_cast<char*>(paste_key.data()), paste_key.size());
|
||||
if (password) {
|
||||
paste_passphrase += password;
|
||||
}
|
||||
|
||||
// Convert content to bytes
|
||||
std::vector<unsigned char> plaintext(content, content + strlen(content));
|
||||
|
||||
// Compress the plaintext
|
||||
std::vector<unsigned char> compressed_data = Crypto::compress(plaintext);
|
||||
|
||||
// Generate random salt and IV
|
||||
std::vector<unsigned char> salt = Crypto::generate_key(8);
|
||||
std::vector<unsigned char> iv = Crypto::generate_key(16);
|
||||
|
||||
// Derive key using PBKDF2
|
||||
std::vector<unsigned char> derived_key = Crypto::pbkdf2_hmac_sha256(
|
||||
paste_passphrase, salt, 100000, 32);
|
||||
|
||||
// Encrypt the data
|
||||
std::vector<unsigned char> auth_tag;
|
||||
std::vector<unsigned char> cipher_text = Crypto::encrypt(
|
||||
compressed_data, derived_key, iv, auth_tag);
|
||||
|
||||
// Create the JSON structure
|
||||
json paste_json = JsonParser::create_paste_json(
|
||||
cipher_text, auth_tag, iv, salt,
|
||||
expiration ? expiration : "1day",
|
||||
format ? format : "plaintext",
|
||||
burn_after_reading != 0,
|
||||
open_discussion != 0);
|
||||
|
||||
// Serialize JSON
|
||||
std::string json_data = paste_json.dump();
|
||||
|
||||
// Send POST request
|
||||
HttpClient client;
|
||||
std::string response;
|
||||
if (!client.post(server_url, json_data, response)) {
|
||||
return ERROR_NETWORK;
|
||||
}
|
||||
|
||||
// Parse response
|
||||
int status;
|
||||
std::string message, paste_id, url, del_token;
|
||||
if (!JsonParser::parse_response(response, status, message, paste_id, url, del_token)) {
|
||||
return ERROR_JSON_PARSE;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
return ERROR_SERVER;
|
||||
}
|
||||
|
||||
// Encode the paste key with Base58
|
||||
std::string encoded_key = Base58::encode(paste_key);
|
||||
|
||||
// Construct the full URL
|
||||
std::string full_url = url + "#" + encoded_key;
|
||||
|
||||
// Copy results to output parameters
|
||||
copy_string_to_output(full_url, paste_url);
|
||||
copy_string_to_output(del_token, delete_token);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} catch (...) {
|
||||
return ERROR_CRYPTO;
|
||||
}
|
||||
}
|
||||
|
||||
int get_paste(const char* server_url, const char* paste_id,
|
||||
const char* key, char** content) {
|
||||
|
||||
if (!server_url || !paste_id || !key || !content) {
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
try {
|
||||
// Construct the URL
|
||||
std::string url = std::string(server_url) + "/" + paste_id;
|
||||
|
||||
// Send GET request
|
||||
HttpClient client;
|
||||
std::string response;
|
||||
if (!client.get(url, response)) {
|
||||
return ERROR_NETWORK;
|
||||
}
|
||||
|
||||
// Parse the JSON response
|
||||
json json_data = json::parse(response);
|
||||
|
||||
// Extract encrypted data
|
||||
std::vector<unsigned char> cipher_text, auth_tag, iv, salt;
|
||||
std::string expiration;
|
||||
if (!JsonParser::parse_paste_json(json_data, cipher_text, auth_tag, iv, salt, expiration)) {
|
||||
return ERROR_JSON_PARSE;
|
||||
}
|
||||
|
||||
// Decode the key from Base58
|
||||
std::vector<unsigned char> paste_key = Base58::decode(key);
|
||||
|
||||
// Derive key using PBKDF2
|
||||
std::string paste_passphrase(reinterpret_cast<char*>(paste_key.data()), paste_key.size());
|
||||
std::vector<unsigned char> derived_key = Crypto::pbkdf2_hmac_sha256(
|
||||
paste_passphrase, salt, 100000, 32);
|
||||
|
||||
// Decrypt the data
|
||||
std::vector<unsigned char> compressed_data = Crypto::decrypt(
|
||||
cipher_text, derived_key, iv, auth_tag);
|
||||
|
||||
// Decompress the data
|
||||
std::vector<unsigned char> plaintext = Crypto::decompress(compressed_data);
|
||||
|
||||
// Convert to string
|
||||
std::string result(reinterpret_cast<char*>(plaintext.data()), plaintext.size());
|
||||
|
||||
// Copy result to output parameter
|
||||
copy_string_to_output(result, content);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} catch (...) {
|
||||
return ERROR_CRYPTO;
|
||||
}
|
||||
}
|
||||
|
||||
int delete_paste(const char* server_url, const char* paste_id,
|
||||
const char* delete_token) {
|
||||
|
||||
if (!server_url || !paste_id || !delete_token) {
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
try {
|
||||
// Create the JSON payload
|
||||
json payload = {
|
||||
{"pasteid", paste_id},
|
||||
{"deletetoken", delete_token}
|
||||
};
|
||||
|
||||
std::string json_data = payload.dump();
|
||||
|
||||
// Send DELETE request
|
||||
HttpClient client;
|
||||
std::string response;
|
||||
if (!client.delete_req(server_url, json_data, response)) {
|
||||
return ERROR_NETWORK;
|
||||
}
|
||||
|
||||
// Parse response
|
||||
int status;
|
||||
std::string message, paste_id_result, url, del_token;
|
||||
if (!JsonParser::parse_response(response, status, message, paste_id_result, url, del_token)) {
|
||||
return ERROR_JSON_PARSE;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
return ERROR_SERVER;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} catch (...) {
|
||||
return ERROR_CRYPTO;
|
||||
}
|
||||
}
|
||||
|
||||
void free_string(char* str) {
|
||||
if (str) {
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Reference in New Issue
Block a user