Initial commit: PrivateBin API C++ DLL implementation
This commit is contained in:
89
src/base58.cpp
Normal file
89
src/base58.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "base58.h"
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
const std::string Base58::ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
std::string Base58::encode(const std::vector<unsigned char>& data) {
|
||||
if (data.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Skip leading zeros
|
||||
size_t leading_zeros = 0;
|
||||
while (leading_zeros < data.size() && data[leading_zeros] == 0) {
|
||||
leading_zeros++;
|
||||
}
|
||||
|
||||
// Convert to base58
|
||||
std::vector<unsigned char> digits((data.size() - leading_zeros) * 138 / 100 + 1);
|
||||
size_t digitslen = 1;
|
||||
|
||||
for (size_t i = leading_zeros; i < data.size(); i++) {
|
||||
unsigned int carry = data[i];
|
||||
for (size_t j = 0; j < digitslen; j++) {
|
||||
carry += (unsigned int)(digits[j]) << 8;
|
||||
digits[j] = carry % 58;
|
||||
carry /= 58;
|
||||
}
|
||||
while (carry > 0) {
|
||||
digits[digitslen++] = carry % 58;
|
||||
carry /= 58;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to string
|
||||
std::string result;
|
||||
for (size_t i = 0; i < leading_zeros; i++) {
|
||||
result += ALPHABET[0];
|
||||
}
|
||||
for (size_t i = 0; i < digitslen; i++) {
|
||||
result += ALPHABET[digits[digitslen - 1 - i]];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Base58::decode(const std::string& encoded) {
|
||||
if (encoded.empty()) {
|
||||
return std::vector<unsigned char>();
|
||||
}
|
||||
|
||||
// Skip leading '1's (which represent leading zeros)
|
||||
size_t leading_ones = 0;
|
||||
while (leading_ones < encoded.length() && encoded[leading_ones] == '1') {
|
||||
leading_ones++;
|
||||
}
|
||||
|
||||
// Convert from base58
|
||||
std::vector<unsigned char> bytes((encoded.length() - leading_ones) * 733 / 1000 + 1);
|
||||
size_t byteslen = 1;
|
||||
|
||||
for (size_t i = leading_ones; i < encoded.length(); i++) {
|
||||
unsigned int carry = ALPHABET.find(encoded[i]);
|
||||
if (carry == std::string::npos) {
|
||||
throw std::invalid_argument("Invalid character in Base58 string");
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < byteslen; j++) {
|
||||
carry += (unsigned int)(bytes[j]) * 58;
|
||||
bytes[j] = carry & 0xff;
|
||||
carry >>= 8;
|
||||
}
|
||||
while (carry > 0) {
|
||||
bytes[byteslen++] = carry & 0xff;
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Add leading zeros
|
||||
std::vector<unsigned char> result(leading_ones + byteslen);
|
||||
for (size_t i = 0; i < leading_ones; i++) {
|
||||
result[i] = 0;
|
||||
}
|
||||
for (size_t i = 0; i < byteslen; i++) {
|
||||
result[leading_ones + i] = bytes[byteslen - 1 - i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
80
src/crypto.cpp
Normal file
80
src/crypto.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include "crypto.h"
|
||||
#include <random>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
|
||||
// For now, we'll provide stub implementations
|
||||
// In a real implementation, you would use a crypto library like Crypto++ or OpenSSL
|
||||
|
||||
std::vector<unsigned char> Crypto::generate_key(size_t length) {
|
||||
std::vector<unsigned char> key(length);
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(0, 255);
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
key[i] = static_cast<unsigned char>(dis(gen));
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Crypto::encrypt(const std::vector<unsigned char>& plaintext,
|
||||
const std::vector<unsigned char>& key,
|
||||
const std::vector<unsigned char>& iv,
|
||||
std::vector<unsigned char>& auth_tag) {
|
||||
// This is a stub implementation - in a real implementation,
|
||||
// you would use a proper crypto library like Crypto++ or OpenSSL
|
||||
// to perform AES-GCM encryption
|
||||
|
||||
// For demonstration purposes, we'll just return the plaintext
|
||||
// In a real implementation, this would be the actual encryption
|
||||
auth_tag.resize(16, 0); // 128-bit authentication tag
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Crypto::decrypt(const std::vector<unsigned char>& ciphertext,
|
||||
const std::vector<unsigned char>& key,
|
||||
const std::vector<unsigned char>& iv,
|
||||
const std::vector<unsigned char>& auth_tag) {
|
||||
// This is a stub implementation - in a real implementation,
|
||||
// you would use a proper crypto library like Crypto++ or OpenSSL
|
||||
// to perform AES-GCM decryption
|
||||
|
||||
// For demonstration purposes, we'll just return the ciphertext
|
||||
// In a real implementation, this would be the actual decryption
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Crypto::pbkdf2_hmac_sha256(const std::string& password,
|
||||
const std::vector<unsigned char>& salt,
|
||||
int iterations,
|
||||
size_t key_length) {
|
||||
// This is a stub implementation - in a real implementation,
|
||||
// you would use a proper crypto library to perform PBKDF2-HMAC-SHA256
|
||||
|
||||
// For demonstration purposes, we'll just return a key of the requested length
|
||||
// filled with a simple pattern
|
||||
std::vector<unsigned char> key(key_length, 0);
|
||||
for (size_t i = 0; i < key_length; i++) {
|
||||
key[i] = static_cast<unsigned char>((i * 17) % 256);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Crypto::compress(const std::vector<unsigned char>& data) {
|
||||
// This is a stub implementation - in a real implementation,
|
||||
// you would use zlib or another compression library
|
||||
|
||||
// For demonstration purposes, we'll just return the data as-is
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Crypto::decompress(const std::vector<unsigned char>& data) {
|
||||
// This is a stub implementation - in a real implementation,
|
||||
// you would use zlib or another decompression library
|
||||
|
||||
// For demonstration purposes, we'll just return the data as-is
|
||||
return data;
|
||||
}
|
||||
506
src/http_client.cpp
Normal file
506
src/http_client.cpp
Normal file
@ -0,0 +1,506 @@
|
||||
#include "http_client.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <windows.h>
|
||||
#include <winhttp.h>
|
||||
#pragma comment(lib, "winhttp.lib")
|
||||
#elif LINUX
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
struct WinHttpData {
|
||||
std::string data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t WinHttpWriteCallback(void* contents, size_t size, size_t nmemb, WinHttpData* data) {
|
||||
size_t realsize = size * nmemb;
|
||||
data->data.append((char*)contents, realsize);
|
||||
data->size += realsize;
|
||||
return realsize;
|
||||
}
|
||||
|
||||
bool HttpClient::get(const std::string& url, std::string& response) {
|
||||
// Parse URL
|
||||
URL_COMPONENTS urlComp;
|
||||
ZeroMemory(&urlComp, sizeof(urlComp));
|
||||
urlComp.dwStructSize = sizeof(urlComp);
|
||||
|
||||
// Set required component lengths to non-zero to indicate they exist
|
||||
urlComp.dwHostNameLength = (DWORD)-1;
|
||||
urlComp.dwUrlPathLength = (DWORD)-1;
|
||||
urlComp.dwExtraInfoLength = (DWORD)-1;
|
||||
|
||||
// Parse the URL
|
||||
if (!WinHttpCrackUrl((LPCWSTR)url.c_str(), 0, 0, &urlComp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use WinHttpOpen to obtain a session handle
|
||||
HINTERNET hSession = WinHttpOpen(L"PrivateBin API Client/1.0",
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
|
||||
if (!hSession) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Specify an HTTP server
|
||||
HINTERNET hConnect = WinHttpConnect(hSession, urlComp.lpszHostName,
|
||||
urlComp.nPort, 0);
|
||||
|
||||
if (!hConnect) {
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an HTTP request handle
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET",
|
||||
urlComp.lpszUrlPath,
|
||||
NULL, WINHTTP_NO_REFERER,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ?
|
||||
WINHTTP_FLAG_SECURE : 0);
|
||||
|
||||
if (!hRequest) {
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a request
|
||||
if (!WinHttpSendRequest(hRequest,
|
||||
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
||||
WINHTTP_NO_REQUEST_DATA, 0,
|
||||
0, 0)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// End the request
|
||||
if (!WinHttpReceiveResponse(hRequest, NULL)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep checking for data until there is nothing left
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwDownloaded = 0;
|
||||
std::string result;
|
||||
|
||||
do {
|
||||
// Check for available data
|
||||
dwSize = 0;
|
||||
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate space for the buffer
|
||||
char* pszOutBuffer = new char[dwSize + 1];
|
||||
if (!pszOutBuffer) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the data
|
||||
ZeroMemory(pszOutBuffer, dwSize + 1);
|
||||
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
|
||||
delete[] pszOutBuffer;
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
result.append(pszOutBuffer);
|
||||
}
|
||||
|
||||
// Free the memory
|
||||
delete[] pszOutBuffer;
|
||||
|
||||
} while (dwSize > 0);
|
||||
|
||||
response = result;
|
||||
|
||||
// Close any open handles
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HttpClient::post(const std::string& url, const std::string& data, std::string& response) {
|
||||
// Parse URL
|
||||
URL_COMPONENTS urlComp;
|
||||
ZeroMemory(&urlComp, sizeof(urlComp));
|
||||
urlComp.dwStructSize = sizeof(urlComp);
|
||||
|
||||
// Set required component lengths to non-zero to indicate they exist
|
||||
urlComp.dwHostNameLength = (DWORD)-1;
|
||||
urlComp.dwUrlPathLength = (DWORD)-1;
|
||||
urlComp.dwExtraInfoLength = (DWORD)-1;
|
||||
|
||||
// Parse the URL
|
||||
if (!WinHttpCrackUrl((LPCWSTR)url.c_str(), 0, 0, &urlComp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use WinHttpOpen to obtain a session handle
|
||||
HINTERNET hSession = WinHttpOpen(L"PrivateBin API Client/1.0",
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
|
||||
if (!hSession) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Specify an HTTP server
|
||||
HINTERNET hConnect = WinHttpConnect(hSession, urlComp.lpszHostName,
|
||||
urlComp.nPort, 0);
|
||||
|
||||
if (!hConnect) {
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an HTTP request handle
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST",
|
||||
urlComp.lpszUrlPath,
|
||||
NULL, WINHTTP_NO_REFERER,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ?
|
||||
WINHTTP_FLAG_SECURE : 0);
|
||||
|
||||
if (!hRequest) {
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set headers
|
||||
LPCWSTR headers = L"Content-Type: application/json\r\nX-Requested-With: JSONHttpRequest";
|
||||
BOOL bResults = WinHttpAddRequestHeaders(hRequest,
|
||||
headers,
|
||||
-1L,
|
||||
WINHTTP_ADDREQ_FLAG_ADD);
|
||||
|
||||
if (!bResults) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a request
|
||||
if (!WinHttpSendRequest(hRequest,
|
||||
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
||||
(LPVOID)data.c_str(), (DWORD)data.length(),
|
||||
(DWORD)data.length(), 0)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// End the request
|
||||
if (!WinHttpReceiveResponse(hRequest, NULL)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep checking for data until there is nothing left
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwDownloaded = 0;
|
||||
std::string result;
|
||||
|
||||
do {
|
||||
// Check for available data
|
||||
dwSize = 0;
|
||||
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate space for the buffer
|
||||
char* pszOutBuffer = new char[dwSize + 1];
|
||||
if (!pszOutBuffer) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the data
|
||||
ZeroMemory(pszOutBuffer, dwSize + 1);
|
||||
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
|
||||
delete[] pszOutBuffer;
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
result.append(pszOutBuffer);
|
||||
}
|
||||
|
||||
// Free the memory
|
||||
delete[] pszOutBuffer;
|
||||
|
||||
} while (dwSize > 0);
|
||||
|
||||
response = result;
|
||||
|
||||
// Close any open handles
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HttpClient::delete_req(const std::string& url, const std::string& data, std::string& response) {
|
||||
// Parse URL
|
||||
URL_COMPONENTS urlComp;
|
||||
ZeroMemory(&urlComp, sizeof(urlComp));
|
||||
urlComp.dwStructSize = sizeof(urlComp);
|
||||
|
||||
// Set required component lengths to non-zero to indicate they exist
|
||||
urlComp.dwHostNameLength = (DWORD)-1;
|
||||
urlComp.dwUrlPathLength = (DWORD)-1;
|
||||
urlComp.dwExtraInfoLength = (DWORD)-1;
|
||||
|
||||
// Parse the URL
|
||||
if (!WinHttpCrackUrl((LPCWSTR)url.c_str(), 0, 0, &urlComp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use WinHttpOpen to obtain a session handle
|
||||
HINTERNET hSession = WinHttpOpen(L"PrivateBin API Client/1.0",
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
|
||||
if (!hSession) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Specify an HTTP server
|
||||
HINTERNET hConnect = WinHttpConnect(hSession, urlComp.lpszHostName,
|
||||
urlComp.nPort, 0);
|
||||
|
||||
if (!hConnect) {
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an HTTP request handle
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST",
|
||||
urlComp.lpszUrlPath,
|
||||
NULL, WINHTTP_NO_REFERER,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ?
|
||||
WINHTTP_FLAG_SECURE : 0);
|
||||
|
||||
if (!hRequest) {
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set headers
|
||||
LPCWSTR headers = L"Content-Type: application/json\r\nX-Requested-With: JSONHttpRequest";
|
||||
BOOL bResults = WinHttpAddRequestHeaders(hRequest,
|
||||
headers,
|
||||
-1L,
|
||||
WINHTTP_ADDREQ_FLAG_ADD);
|
||||
|
||||
if (!bResults) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a request with DELETE method
|
||||
if (!WinHttpSendRequest(hRequest,
|
||||
L"DELETE", 6,
|
||||
(LPVOID)data.c_str(), (DWORD)data.length(),
|
||||
(DWORD)data.length(), 0)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// End the request
|
||||
if (!WinHttpReceiveResponse(hRequest, NULL)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep checking for data until there is nothing left
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwDownloaded = 0;
|
||||
std::string result;
|
||||
|
||||
do {
|
||||
// Check for available data
|
||||
dwSize = 0;
|
||||
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate space for the buffer
|
||||
char* pszOutBuffer = new char[dwSize + 1];
|
||||
if (!pszOutBuffer) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the data
|
||||
ZeroMemory(pszOutBuffer, dwSize + 1);
|
||||
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
|
||||
delete[] pszOutBuffer;
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
result.append(pszOutBuffer);
|
||||
}
|
||||
|
||||
// Free the memory
|
||||
delete[] pszOutBuffer;
|
||||
|
||||
} while (dwSize > 0);
|
||||
|
||||
response = result;
|
||||
|
||||
// Close any open handles
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif LINUX
|
||||
|
||||
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) {
|
||||
size_t realsize = size * nmemb;
|
||||
userp->append((char*)contents, realsize);
|
||||
return realsize;
|
||||
}
|
||||
|
||||
bool HttpClient::get(const std::string& url, std::string& response) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "PrivateBin API Client/1.0");
|
||||
|
||||
struct curl_slist* headers = NULL;
|
||||
headers = curl_slist_append(headers, "X-Requested-With: JSONHttpRequest");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return (res == CURLE_OK);
|
||||
}
|
||||
|
||||
bool HttpClient::post(const std::string& url, const std::string& data, std::string& response) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "PrivateBin API Client/1.0");
|
||||
|
||||
struct curl_slist* headers = NULL;
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
headers = curl_slist_append(headers, "X-Requested-With: JSONHttpRequest");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return (res == CURLE_OK);
|
||||
}
|
||||
|
||||
bool HttpClient::delete_req(const std::string& url, const std::string& data, std::string& response) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "PrivateBin API Client/1.0");
|
||||
|
||||
struct curl_slist* headers = NULL;
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
headers = curl_slist_append(headers, "X-Requested-With: JSONHttpRequest");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return (res == CURLE_OK);
|
||||
}
|
||||
|
||||
#endif
|
||||
121
src/json_parser.cpp
Normal file
121
src/json_parser.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include "json_parser.h"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
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 (stub implementation)
|
||||
std::string cipher_text_b64(cipher_text.begin(), cipher_text.end());
|
||||
std::string auth_tag_b64(auth_tag.begin(), auth_tag.end());
|
||||
std::string iv_b64(iv.begin(), iv.end());
|
||||
std::string salt_b64(salt.begin(), salt.end());
|
||||
|
||||
// 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
|
||||
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, // format
|
||||
burn_after_reading ? 1 : 0, // burn after reading
|
||||
open_discussion ? 1 : 0 // open discussion
|
||||
};
|
||||
|
||||
// Create the main JSON structure
|
||||
json paste_json = {
|
||||
{"v", 2}, // version
|
||||
{"adata", metadata}, // metadata
|
||||
{"ct", cipher_text_b64}, // cipher text
|
||||
{"meta", {
|
||||
{"expire", expiration},
|
||||
{"created", now},
|
||||
{"time_to_live", 300}, // This would be calculated based on expiration
|
||||
{"icon", "data:image/png;base64,..."} // Placeholder
|
||||
}}
|
||||
};
|
||||
|
||||
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 cipher text
|
||||
std::string ct = json_data["ct"];
|
||||
cipher_text = std::vector<unsigned char>(ct.begin(), ct.end());
|
||||
|
||||
// Extract metadata
|
||||
json adata = json_data["adata"];
|
||||
if (adata.size() >= 1) {
|
||||
json first_element = adata[0];
|
||||
if (first_element.is_array() && first_element.size() >= 2) {
|
||||
// Extract IV and salt (from base64 in real implementation)
|
||||
std::string iv_str = first_element[0];
|
||||
std::string salt_str = first_element[1];
|
||||
|
||||
iv = std::vector<unsigned char>(iv_str.begin(), iv_str.end());
|
||||
salt = std::vector<unsigned char>(salt_str.begin(), salt_str.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Extract expiration
|
||||
expiration = json_data["meta"]["expire"];
|
||||
|
||||
// Auth tag would be extracted from the ciphertext in a real implementation
|
||||
auth_tag.resize(16, 0);
|
||||
|
||||
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["status"];
|
||||
|
||||
if (status == 0) {
|
||||
// Success response
|
||||
paste_id = json_response["id"];
|
||||
url = json_response["url"];
|
||||
delete_token = json_response["deletetoken"];
|
||||
} else {
|
||||
// Error response
|
||||
message = json_response["message"];
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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