data download with set user-agent c++ - c++

I have a function to upload information to a byte array, but it ends with - if (!Httpsendrequest(httprequest, szHeaders, strlen(szhheaders), szRequest, strlen(szRequest)))
string GetUrlData(const string& url, LPCSTR host, string& output)
{
string request_data = "";
output = "";
HINTERNET hIntSession = InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hIntSession)
{
return request_data;
}
HINTERNET hHttpSession = InternetConnectA(hIntSession, host, 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hHttpSession)
{
return request_data;
}
HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", url.c_str()
, 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
if (!hHttpSession)
{
return request_data;
}
char* szHeaders = ("Content-Type: text/html\r\nUser-Agent: License");
char szRequest[1024] = { 0 };
if (!HttpSendRequestA(hHttpRequest, szHeaders, strlen(szHeaders), szRequest, strlen(szRequest)))
{
qDebug()<<"BLYA";
return request_data;
}
CHAR szBuffer[1024] = { 0 };
DWORD dwRead = 0;
while (InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer) - 1, &dwRead) && dwRead)
{
request_data.append(szBuffer, dwRead);
}
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
output = request_data;
}

The failure might have something to do with the fact that szHeaders is missing \r\n on the User-Agent header. Every header you send ust be terminated with \r\n. And BTW, there is no reason to send a Content-Type header in a GET request, since there is no message body being sent to the server.
Also, your code has a bunch of memory leaks if anything goes wrong. You need to close every handle you successfully open.
Also, there is no point in having both a return value and an output parameter that return the same data. Pick one or the other. I would suggest using a bool return value and a string output parameter.
Try something more like this:
bool GetUrlData(const string& resource, const string& host)
{
output.clear();
bool result = false;
HINTERNET hIntSession = InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hIntSession) {
qDebug() << "InternetOpen failed, error: " << GetLastError();
return false;
}
HINTERNET hHttpSession = InternetConnectA(hIntSession, host.c_str(), 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hHttpSession) {
qDebug() << "InternetConnect failed, error: " << GetLastError();
InternetCloseHandle(hIntSession);
return false;
}
HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", resource.c_str(), 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
if (!hHttpRequest) {
qDebug() << "HttpOpenRequest failed, error: " << GetLastError();
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return false;
}
const char* szHeaders = "User-Agent: License\r\n";
if (!HttpSendRequestA(hHttpRequest, szHeaders, -1, NULL, 0)) {
qDebug() << "HttpSendRequest failed, error: " << GetLastError();
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return false;
}
char szBuffer[1024];
DWORD dwRead = 0;
do {
if (!InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer), &dwRead)) {
qDebug() << "InternetReadFile failed, error: " << GetLastError();
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return false;
}
if (dwRead == 0)
break;
output.append(szBuffer, dwRead);
}
while (true);
return true;
}

Related

HttpSendRequestA is false and return 0

Hi i am trying to download something using WinInet with a costum user agent the issue is that i fails at HttpSendRequestA the error it return is 0
i dont know what this error means i have tried looking it up but nothing comes up
i get the error using std::to_string(GetLastError());
Here is the code bolow
std::string GetUrlData(const std::string& resource, const std::string& host)
{
std::string output = "";
output.clear();
HINTERNET hIntSession = InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hIntSession) {
return "ERROR: Session Cannot Start";
}
HINTERNET hHttpSession = InternetConnectA(hIntSession, host.c_str(), 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hHttpSession) {
InternetCloseHandle(hIntSession);
return "ERROR: Cannot Connect To Internet";
}
HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", resource.c_str(), 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
if (!hHttpRequest) {
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return "ERROR: Http Request Failed";
}
// const char* szHeaders = "User-Agent: Mozzila\r\n";
if (!HttpSendRequestA(hHttpRequest, NULL, 0, NULL, 0)) {
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return "ERROR: Http Request Failed 2";
}
char szBuffer[1024];
DWORD dwRead = 0;
do {
if (!InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer), &dwRead)) {
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return "ERROR: Cannot Download";
}
if (dwRead == 0)
break;
output.append(szBuffer, dwRead);
}
while (true);
return output;
}
I call this fuction like so std::string
data = GetUrlData("http://example.com/", "http://example.com/");
The problem is that your host parameter should only be the hostname, not the full URL and the resource should only be the resource part on the host.
Like this:
std::string data = GetUrlData("/", "example.com");
A sidenote: You acquire up to three resources that need to be manually released and try to make sure to release them using InternetCloseHandle() but it soon becomes verbose and you risk forgetting one eventually. As it happens, if your GetUrlData() call succeeds, you don't release any of the resources.
Consider wrapping each resource in a std::unique_ptr to get it released automatically. Not only does it make it safer, it also makes it easier to read and maintain the code.
Example:
#include <Windows.h>
#include <wininet.h>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
// custom deleter for the resource
struct internet_deleter {
void operator()(HINTERNET hi) { InternetCloseHandle(hi); }
};
// the resource's wrapper type
using ihandle = std::unique_ptr<std::remove_pointer_t<HINTERNET>, internet_deleter>;
// functions for acquiring resources
auto RAII_InternetOpen() {
ihandle rv(InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));
if (rv) return rv;
throw std::runtime_error("InternetOpenA: " + std::to_string(GetLastError()));
}
auto RAII_InternetConnect(const ihandle& hIntSession, const std::string& host) {
ihandle rv(
InternetConnectA(hIntSession.get(), host.c_str(), 80, 0, 0,
INTERNET_SERVICE_HTTP, 0, NULL));
if (rv) return rv;
throw std::runtime_error("InternetConnectA: " + std::to_string(GetLastError()));
}
auto RAII_HttpOpenRequest(const ihandle& hHttpSession, const std::string& resource) {
ihandle rv(
HttpOpenRequestA(hHttpSession.get(), "GET", resource.c_str(), 0, 0, 0,
INTERNET_FLAG_RELOAD, 0));
if (rv) return rv;
throw std::runtime_error("HttpOpenRequestA: " + std::to_string(GetLastError()));
}
With the three functions above, the GetUrlData() function becomes simpler and will not leak resources:
std::string GetUrlData(const std::string& resource, const std::string& host)
{
std::string output;
auto hIntSession = RAII_InternetOpen();
auto hHttpSession = RAII_InternetConnect(hIntSession, host);
auto hHttpRequest = RAII_HttpOpenRequest(hHttpSession, resource);
if (!HttpSendRequestA(hHttpRequest.get(), NULL, 0, NULL, 0))
throw std::runtime_error("HttpSendRequestA: " +
std::to_string(GetLastError()));
char szBuffer[1024];
DWORD dwRead = 0;
do {
if (!InternetReadFile(hHttpRequest.get(), szBuffer, sizeof(szBuffer), &dwRead))
throw std::runtime_error("InternetReadFile: " +
std::to_string(GetLastError()));
if (dwRead == 0)
break;
output.append(szBuffer, dwRead);
} while (true);
return output;
}
int main() {
try {
std::cout << GetUrlData("/", "www.google.com");
}
catch (const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << '\n';
}
}

Why does my while loop end without giving an error? C++

I have a project which you can create named pipes in c# or c++ and this program will work as a middle man and simply pass the data on. Used to maintain integrity. Though in one of my while loops when I debug it I step on the while loop then it will cancel the steps and not process the while loop. It reaches line 107 of this code. If you need more of my files I will be happy to post them if needed.
//Information\\
//----------------------------------------\\
//File Name: NamedPipes.cpp
//Date Of Creation: 03/12/2019
//Purpose
/*
This file is to handle the interprocess communication
between the pipes.
*/
//----------------------------------------\\
//Internal Includes\\
//----------------------------------------\\
#include "NamedPipes.h"
#include "MiddleMan.h"
//----------------------------------------\\
//Global Variables\\
//----------------------------------------\\
struct Connection NamedPipes::Server;
struct Connection NamedPipes::Client;
//----------------------------------------\\
//Functions\\
//----------------------------------------\\
int NamedPipes::CreateServer()
{
try
{
LPTSTR lpszPipename = (LPTSTR)"\\\\.\\pipe\\Omni3";
LPTSTR lpszPipename2 = (LPTSTR)"\\\\.\\pipe\\Omni4";
while (1) {
Server.Write = CreateNamedPipe(lpszPipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
Server.Read = CreateNamedPipe(lpszPipename2, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
if (Server.Write == INVALID_HANDLE_VALUE)
{
return -1;
}
if (ConnectNamedPipe(Server.Write, NULL) != FALSE) // wait for someone to connect to the pipe
{
Server.Connected = true;
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE)MiddleMan::Pass, // thread proc
(LPVOID)&Server, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
}
}
return 1;
}
catch (exception ex)
{
}
return 0;
}
int NamedPipes::CreateClient()
{
try
{
DWORD last_error;
unsigned int elapsed_seconds = 0;
const unsigned int timeout_seconds = 5;
LPTSTR lpszPipename = (LPTSTR)"\\\\.\\pipe\\Omni1";
LPTSTR lpszPipename2 = (LPTSTR)"\\\\.\\pipe\\Omni2";
Client.Read = CreateFile(lpszPipename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Client.Write = CreateFile(lpszPipename2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
while (INVALID_HANDLE_VALUE == Client.Read &&
elapsed_seconds < timeout_seconds)
{
last_error = GetLastError();
if (last_error != ERROR_PIPE_BUSY)
{
break;
}
Sleep(1000);
elapsed_seconds++;
Client.Read = CreateFile(lpszPipename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Client.Write = CreateFile(lpszPipename2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
}
if (INVALID_HANDLE_VALUE == Client.Read)
{
std::cerr << "Failed to connect to pipe " << lpszPipename <<
": last_error=" << last_error << "\n";
return 0;
}
else
{
std::cout << "Connected to pipe " << lpszPipename << "\n";
}
DWORD dwThreadId = 0;
Client.Connected = true;
HANDLE hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE)MiddleMan::Pass, // thread proc
(LPVOID)&Client, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
return 1;
}
catch (exception ex)
{
}
return 0;
}
/*
This function will loop until it recieves a transmission from the external UI.
*/
string NamedPipes::RecieveInformation(HANDLE Pipe)
{
BOOL fSuccess;
char chBuf[2048];
DWORD cbRead;
int i;
try
{
while (true)
{
if (Pipe) {
fSuccess = ReadFile(Pipe, chBuf, 2048, &cbRead, NULL);
if (cbRead != NULL && fSuccess)
{
string s(chBuf);
s.resize(cbRead);
printf("Pipe Recieved: %s\n", s.c_str());
return s;
}
printf("Error: Couldn't Read Pipe\n");
Sleep(500);
}
else
{
printf("Error: Invalid Pipe\n");
}
}
return "";
}
catch (exception ex)
{
printf("Error: %s\n", ex.what());
}
catch (...)
{
printf("Error Unknown\n");
}
}
int NamedPipes::SendInformation(HANDLE Pipe, string Information)
{
char buf[2048];
DWORD cbWritten;
try
{
strcpy(buf, Information.c_str());
if (!WriteFile(Pipe, buf, (DWORD)strlen(buf), &cbWritten, NULL))
{
printf("Message Sending Failed. Error: %d\n", GetLastError());
}
}
catch (exception ex)
{
}
return 1;
}
//----------------------------------------\\
EDIT: If it helps this is MiddleMan::Pass
void MiddleMan::Pass(LPVOID Pipe2)
{
Connection Pipe = *(Connection *)Pipe2;
while (1)
{
string Information = NamedPipes::RecieveInformation(Pipe.Read);
if (Information != "") {
if (Pipe.Read == NamedPipes::Server.Read)
{
if (NamedPipes::Client.Connected) {
NamedPipes::SendInformation(NamedPipes::Client.Write, Information);
}
}
else if (Pipe.Read == NamedPipes::Client.Read)
{
if (NamedPipes::Server.Connected) {
NamedPipes::SendInformation(NamedPipes::Server.Write, Information);
}
}
}
}
}

Generation RSA-2048 keys (public and private)

I'm making simple implementation RSA-2048. I found some code on another forum.
#include <string>
#include <iostream>
#include <windows.h>
#include <Wincrypt.h>
using namespace std;
#pragma comment (lib, "Crypt32.lib")
BYTE* Crypt(const string& _str, DWORD* _outLength);
BYTE* Decrypt(BYTE* _encryptedData, DWORD* _length);
const char* szPemPrivKey =
"-----BEGIN RSA PRIVATE KEY-----"
"MIICWwIBAAKBgQCn7fL/1qsWkJkUtXKZIJNqYfnVByVhK/LzQecPhVR7r+4ng1nZ"
"Bxg44SexS63iYlnodqDWkH/Hi82Uc0UmugY/Ow39uEGeoiYqWl5BLM8pfRAGqzxb"
"h600Qd/Oc5kYdg8hP0D/gAHXwutL74fygpB6xb8EZl2BHKvpDR80GYFlrQIDAQAB"
"AoGAZ4ZHsfTTEFwgIyYg+cmdV44DCJMZNihz5AcSvPzDMmUo+m79as/23MnhQGmZ"
"TuC28JqBWQVH4OqM2CGf1doEkuLZ/rcgxDipRqbLkEW3T/q+kJ2m9A652ePbHUKX"
"ayozDQrWtL4wkvAQQ9Il6vx+AJUzT41hv1PKZ5KWxONiJDkCQQDRsObUVVc6exb+"
"YUWVgN0pivHudKIwGUN3js09MjHoen9LbUcvupO3seAUhnNQ17t+1XxsrnPKabQQ"
"OimcPK3XAkEAzQQEI++NdoLYJv1oKYADzOUbDAmfoZ/szN6z//53h8zt5ni+6Q0n"
"k7nyrVXWuLeP0rEvD0hMOzI0mfUMwbtwGwJAMUYId8y1+qAB/zSMTV1CmwhzYT02"
"/2ZwXB/KSp8I60AduXOsTqLhI0FBDpGpd026WUuBOWik/ONp1IZWUMhRcQJAHI+U"
"rBTxVjNAPZ5L5owo+2BndjPZA0EuUhQsa1td95M7CUKFBh6JBvF+t1sgALfB145L"
"igt+YzjJTzFuR4b/RQJATgZuFyBiuLHrMES2vAtmLRlF6uTzsrNZLLUko2Rfzkzh"
"qR4inQOWWZLFzjqp3ha9rzCSVY+nBw+xD+B9hBlsNw=="
"-----END RSA PRIVATE KEY-----";
const char* szPemPublicKey =
"-----BEGIN PUBLIC KEY-----"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn7fL/1qsWkJkUtXKZIJNqYfnV"
"ByVhK/LzQecPhVR7r+4ng1nZBxg44SexS63iYlnodqDWkH/Hi82Uc0UmugY/Ow39"
"uEGeoiYqWl5BLM8pfRAGqzxbh600Qd/Oc5kYdg8hP0D/gAHXwutL74fygpB6xb8E"
"Zl2BHKvpDR80GYFlrQIDAQAB"
"-----END PUBLIC KEY-----";
int main()
{
string str_data = "test RSA implementation";
DWORD encryptedDataLen;
BYTE* encrytedData = Crypt(str_data, &encryptedDataLen);
cout << encrytedData << endl;
cout << endl;
BYTE* decryptedData = Decrypt(encrytedData, &encryptedDataLen);
cout << decryptedData << endl;
delete(encrytedData);
delete(decryptedData);
return 0;
}
BYTE* Crypt(const string& _str, DWORD* _outLength)
{
char pemPubKey[2048];
memcpy((void*)pemPubKey, szPemPublicKey, strlen(szPemPublicKey));
char derPubKey[2048];
DWORD derPubKeyLen = 2048;
CERT_PUBLIC_KEY_INFO* publicKeyInfo;
DWORD publicKeyInfoLen;
HANDLE hFile;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
// Convert from PEM format to DER format - removes header and footer and decodes from base64
if (!CryptStringToBinaryA(pemPubKey, 0, CRYPT_STRING_BASE64HEADER, (BYTE*)derPubKey, &derPubKeyLen, NULL, NULL))
{
fprintf(stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError());
return NULL;
}
// Decode from DER format to CERT_PUBLIC_KEY_INFO
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, (BYTE*)derPubKey, derPubKeyLen,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen))
{
fprintf(stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError());
return NULL;
}
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
{
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return NULL;
}
}
if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey))
{
fprintf(stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError());
return NULL;
}
// LocalFree( publicKeyInfo );
// get size of buffer
DWORD strLen = _str.length() * sizeof(char);
DWORD bufLen = strLen;
if (!CryptEncrypt(hKey, 0, true, 0, 0, &bufLen, strLen))
{
cout << "CryptEncrypt() failed with error " << GetLastError() << endl;
return NULL;
}
// Crypt string data
BYTE* cipherBlock = new BYTE[bufLen];
memset((void*)cipherBlock, 0, bufLen);
memcpy((void*)cipherBlock, _str.c_str(), strLen);
if (!CryptEncrypt(hKey, 0, TRUE, 0, cipherBlock, &strLen, bufLen))
{
cout << "CryptEncrypt() failed with error " << GetLastError() << endl;
return NULL;
}
*_outLength = bufLen;
return cipherBlock;
}
BYTE* Decrypt(BYTE* _encryptedData, DWORD* _length)
{
DWORD dwBufferLen = 0, cbKeyBlob = 0, cbSignature = 0/*,i*/;
LPBYTE pbBuffer = NULL, pbKeyBlob = NULL, pbSignature = NULL;
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;
if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen, NULL, NULL))
{
cout << "Failed to convert BASE64 private key. Error " << GetLastError() << endl;
return NULL;
}
pbBuffer = (LPBYTE)LocalAlloc(0, dwBufferLen);
if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, pbBuffer, &dwBufferLen, NULL, NULL))
{
cout << "Failed to convert BASE64 private key. Error " << GetLastError() << endl;
return NULL;
}
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob))
{
cout << "Failed to parse private key. Error " << GetLastError() << endl;
return NULL;
}
pbKeyBlob = (LPBYTE)LocalAlloc(0, cbKeyBlob);
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob))
{
cout << "Failed to parse private key. Error " << GetLastError() << endl;
return NULL;
}
if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
{
if (GetLastError() == NTE_BAD_KEYSET)
{
if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
cout << "CryptAcquireContext() failed with error " << GetLastError() << endl;
return NULL;
}
}
else
{
cout << "CryptAcquireContext() failed with error " << GetLastError() << endl;
return NULL;
}
}
if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, NULL, 0, &hKey))
{
cout << "CryptImportKey() failed with error " << GetLastError() << endl;
return NULL;
}
// Decrypt
DWORD bufLen = *_length + 1;
BYTE* cipherBlock = new BYTE[bufLen];
memset((void*)cipherBlock, 0, bufLen);
memcpy((void*)cipherBlock, _encryptedData, *_length);
if (!CryptDecrypt(hKey, 0, TRUE, 0, cipherBlock, _length))
{
cout << "CryptDecrypt() failed with error " << GetLastError() << endl;
return NULL;
}
// Decrypted data
BYTE* decryptedData = new BYTE[*_length + 1];
decryptedData[*_length] = 0;
memcpy((void*)decryptedData, cipherBlock, *_length);
delete(cipherBlock);
if (pbBuffer) LocalFree(pbBuffer);
if (pbKeyBlob) LocalFree(pbKeyBlob);
if (pbSignature) LocalFree(pbSignature);
if (hHash) CryptDestroyHash(hHash);
if (hKey) CryptDestroyKey(hKey);
if (hProv) CryptReleaseContext(hProv, 0);
return decryptedData;
}
So, encryption\decryption works perfectly well.
I need to change keys.
How can I generate keys for this code?
I tried this online generator but it doen't work.
https://travistidwell.com/jsencrypt/demo/
and other online generators
NCryptCreatePersistedKey . Please abandon old Crypt* functions in favor of NCrypt and BCrypt* variants. If you insist on the old API, use this.

WinInet upload file

I wrote a C++ function to perform uploading file using WinInet Library. The code is compiled and executed without returning error, but I can't handle the file in the server side. Both the php and the python server don't recognize file.
Here is the code :
#define DEFAULT_USERAGENT "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
#define MY_HOST "192.168.1.101"
#define ALT_HTTP_PORT 8080
#define METHOD_POST "POST"
#define BUFSIZE 1024
void UploadFile()
{
char szHeaders[] = "Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575";
char szContent[] = "---------------------------974767299852498929531610575\r\nContent-Disposition: form-data; name=\"file\"; filename=\"main.cpp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
char szEndData[] = "\r\n---------------------------974767299852498929531610575--\r\n";
unsigned char c;
char szBuffer[BUFSIZE];
memset(szBuffer, 0, BUFSIZE);
char* szData = NULL;
DWORD dwBytes;
HANDLE hIn = CreateFile("main.cpp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
for(int i = 0; i < BUFSIZE - 1 ; i++){
ReadFile(hIn, &c, 1, NULL, NULL);
szBuffer[i] = c;
}
szBuffer[BUFSIZE - 1] = '\0';
CloseHandle(hIn);
size_t sDataSize = strlen(szBuffer) + strlen(szContent) + strlen(szEndData) + 1;
szData = new char[sDataSize];
SecureZeroMemory(szData, sizeof(szData));
strcat(szData, szContent);
strcat(szData, szBuffer);
strcat(szData, szEndData);
szData[sDataSize] = '\0';
HINTERNET io = InternetOpen(DEFAULT_USERAGENT, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if(!io){
std::cerr << "InternetOpen Error" << std::endl;
return;
}
HINTERNET ic = InternetConnect(io, MY_HOST, ALT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if(!ic){
std::cerr << "InternetConnect Error" << std::endl;
return;
}
HINTERNET hreq = HttpOpenRequest(ic, METHOD_POST, "/upload", NULL,NULL, NULL, 0, 0);
if(!hreq){
std::cerr << "HttpOpenRequest Error" << std::endl;
return;
}
HttpSendRequest(hreq, szHeaders, strlen(szHeaders), szData, strlen(szData));
InternetCloseHandle(io);
InternetCloseHandle(ic);
InternetCloseHandle(hreq);
delete[] szData;
}
Your MIME boundary lines in szContent and szEndData are wrong. Read RFC 2046. A boundary line in the content data begins with two - characters, followed by the text specified in the boundary parameter of the Content-Type header (and in the case of an ending boundary line, then followed by two more - characters).
The boundary lines you are using in your content data are missing those two leading - characters. You have 27 leading dashes in the boundary header, so you need 29 leading dashes in the content, not 27 like you have.
Also, you are assuming the input file is exactly 1023 bytes in size. But, more importantly, you are not doing any error handling on the CreateFile() call to make sure the file is actually open, or any error handling on the ReadFile() call to make sure data is actually being read in (hint: the 4th parameter cannot be NULL when the 5th parameter is NULL).
You are trying to read the entire file (well, up to 1023 bytes, anyway) into memory, and then send it. At the very least, you should use GetFileSize() to get the actual file size, and then allocate szData accordingly and read directly into it. You don't need szBuffer at all.
There are other minor errors in your code, too. Like misusing sizeof(), assuming that the file data does not contain any null bytes in it, leaking memory, etc.
Try something more like this instead:
#define DEFAULT_USERAGENT "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
#define MY_HOST "192.168.1.101"
#define ALT_HTTP_PORT 8080
#define METHOD_POST "POST"
#include <vector>
#include <memory>
struct FileCloser
{
typedef HANDLE pointer;
void operator()(HANDLE h)
{
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
};
struct InetCloser
{
typedef HINTERNET pointer;
void operator()(HINTERNET h)
{
if (h != NULL)
InternetCloseHandle(h);
}
};
void UploadFile()
{
const char *szHeaders = "Content-Type: multipart/form-data; boundary=----974767299852498929531610575";
const char *szContent = "------974767299852498929531610575\r\nContent-Disposition: form-data; name=\"file\"; filename=\"main.cpp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
const char *szEndData = "\r\n------974767299852498929531610575--\r\n";
std::unique_ptr<HANDLE, FileCloser> hIn(CreateFile("main.cpp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL));
if (hIn.get() == INVALID_HANDLE_VALUE)
{
std::cerr << "CreateFile Error" << std::endl;
return;
}
DWORD dwFileSize = GetFileSize(hIn.get(), NULL);
if (dwFileSize == INVALID_FILE_SIZE)
{
std::cerr << "GetFileSize Error" << std::endl;
return;
}
size_t sContentSize = strlen(szContent);
size_t sEndDataSize = strlen(szEndData);
std::vector<char> vBuffer(sContentSize + dwFileSize + sEndDataSize);
char *szData = &vBuffer[0];
memcpy(szData, szContent, sContentSize);
szData += sContentSize;
DWORD dw = 0, dwBytes;
while (dw < dwFileSize)
{
if (!ReadFile(hIn.get(), szData, dwFileSize-dw, &dwBytes, NULL))
{
std::cerr << "ReadFile Error" << std::endl;
return;
}
szData += dwBytes;
dw += dwBytes;
}
hIn.reset();
memcpy(szData, szEndData, sEndDataSize);
std::unique_ptr<HINTERNET, InetCloser> io(InternetOpen(DEFAULT_USERAGENT, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));
if (io.get() == NULL)
{
std::cerr << "InternetOpen Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> ic(InternetConnect(io.get(), MY_HOST, ALT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0));
if (ic.get() == NULL)
{
std::cerr << "InternetConnect Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> hreq(HttpOpenRequest(ic.get(), METHOD_POST, "/upload", NULL, NULL, NULL, 0, 0));
if (hreq.get() == NULL)
{
std::cerr << "HttpOpenRequest Error" << std::endl;
return;
}
if (!HttpSendRequest(hreq.get(), szHeaders, -1, &vBuffer[0], vBuffer.size()))
std::cerr << "HttpSendRequest Error" << std::endl;
}
An alternative option is to use HttpSendRequestEx() instead, so you can then use InternetWriteFile() in a loop to read+send the file in chunks on each loop iteration. That way, you do not have to read the entire file into memory before sending:
#define DEFAULT_USERAGENT "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
#define MY_HOST "192.168.1.101"
#define ALT_HTTP_PORT 8080
#define METHOD_POST "POST"
#define BUFSIZE 1024
#include <memory>
#include <algorithm>
struct FileCloser
{
typedef HANDLE pointer;
void operator()(HANDLE h)
{
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
};
struct InetCloser
{
typedef HINTERNET pointer;
void operator()(HINTERNET h)
{
if (h != NULL)
InternetCloseHandle(h);
}
};
bool WriteToInternet(HINTERNET hInet, const void *Data, DWORD DataSize)
{
const BYTE *pData = (const BYTE *) Data;
DWORD dwBytes;
while (DataSize > 0)
{
if (!InternetWriteFile(hInet, pData, DataSize, &dwBytes))
return false;
pData += dwBytes;
DataSize -= dwBytes;
}
return true;
}
void UploadFile()
{
const char *szHeaders = "Content-Type: multipart/form-data; boundary=----974767299852498929531610575";
const char *szContent = "------974767299852498929531610575\r\nContent-Disposition: form-data; name=\"file\"; filename=\"main.cpp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
const char *szEndData = "\r\n------974767299852498929531610575--\r\n";
std::unique_ptr<HANDLE, FileCloser> hIn(CreateFile("main.cpp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL));
if (hIn.get() == INVALID_HANDLE_VALUE)
{
std::cerr << "CreateFile Error" << std::endl;
return;
}
DWORD dwFileSize = GetFileSize(hIn.get(), NULL);
if (dwFileSize == INVALID_FILE_SIZE)
{
std::cerr << "GetFileSize Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> io(InternetOpen(DEFAULT_USERAGENT, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));
if (io.get() == NULL)
{
std::cerr << "InternetOpen Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> ic(InternetConnect(io.get(), MY_HOST, ALT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0));
if (ic.get() == NULL)
{
std::cerr << "InternetConnect Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> hreq(HttpOpenRequest(ic.get(), METHOD_POST, "/upload", NULL, NULL, NULL, 0, 0));
if (hreq.get() == NULL)
{
std::cerr << "HttpOpenRequest Error" << std::endl;
return;
}
if (!HttpAddRequestHeaders(hreq.get(), szHeaders, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))
{
std::cerr << "HttpAddRequestHeaders Error" << std::endl;
return;
}
size_t sContentSize = strlen(szContent);
size_t sEndDataSize = strlen(szEndData);
INTERNET_BUFFERS bufferIn = {};
bufferIn.dwStructSize = sizeof(INTERNET_BUFFERS);
bufferIn.dwBufferTotal = sContentSize + dwFileSize + sEndDataSize;
if (!HttpSendRequestEx(hreq.get(), &bufferIn, NULL, HSR_INITIATE, 0))
{
std::cerr << "HttpSendRequestEx Error" << std::endl;
return;
}
if (!WriteToInternet(hreq.get(), szContent, sContentSize)))
{
std::cerr << "InternetWriteFile Error" << std::endl;
return;
}
char szData[BUFSIZE];
DWORD dw = 0, dwBytes;
while (dw < dwFileSize)
{
if (!ReadFile(hIn.get(), szData, std::min(dwFileSize-dw, sizeof(szData)), &dwBytes, NULL))
{
std::cerr << "ReadFile Error" << std::endl;
return;
}
if (!WriteToInternet(hreq.get(), szData, dwBytes))
{
std::cerr << "InternetWriteFile Error" << std::endl;
return;
}
dw += dwBytes;
}
if (!WriteToInternet(hreq.get(), szEndData, sEndDataSize))
{
std::cerr << "InternetWriteFile Error" << std::endl;
return;
}
if (!HttpEndRequest(hreq.get(), NULL, HSR_INITIATE, 0))
std::cerr << "HttpEndRequest Error" << std::endl;
}

Handling InternetCloseHandle failure

INTRODUCTION AND RELEVANT INFORMATION:
I am learning WinInet on my own. I have written (in my humble opinion) "typical" piece of code, that needs to perform cleanup in the end:
DWORD CSomeClass::MVCE4StackOverflow()
{
DWORD errorCode = ERROR_SUCCESS;
URL_COMPONENTS urlComp;
::ZeroMemory(&urlComp, sizeof(URL_COMPONENTS));
urlComp.dwStructSize = sizeof(URL_COMPONENTS);
urlComp.dwHostNameLength = -1;
urlComp.dwSchemeLength = -1;
urlComp.dwUrlPathLength = -1;
if (!::InternetCrackUrl(m_URL.c_str(), m_URL.length(), 0, &urlComp))
{
errorCode = ::GetLastError();
return errorCode;
}
HINTERNET hInternetSession = ::InternetOpen("WinInet",
INTERNET_OPEN_TYPE_DIRECT,
NULL, NULL, 0);
if (NULL == hInternetSession)
{
errorCode = ::GetLastError();
return errorCode;
}
std::string hostname(urlComp.dwHostNameLength, 0);
::memcpy(&hostname[0], urlComp.lpszHostName, urlComp.dwHostNameLength);
HINTERNET hHttpSession = ::InternetConnect(hInternetSession,
hostname.c_str(),
INTERNET_DEFAULT_HTTP_PORT, 0, 0,
INTERNET_SERVICE_HTTP, 0, NULL);
if (NULL == hHttpSession)
{
errorCode = ::GetLastError();
return errorCode;
}
HINTERNET hHttpRequest = ::HttpOpenRequest(hHttpSession, "POST",
urlComp.lpszUrlPath, 0, 0, 0,
INTERNET_FLAG_RELOAD, 0);
if (NULL == hHttpRequest)
{
errorCode = ::GetLastError();
return errorCode;
}
const char header[] = "Content-Type: application/x-www-form-urlencoded";
std::string data = "input=1234";
if (!::HttpSendRequest(hHttpRequest, header, strlen(header),
&data[0], data.length()))
{
errorCode = ::GetLastError();
return errorCode;
}
DWORD dwBytesRead = 0;
BOOL result = false;
char szBuffer[1025] = "";
char *temp = szBuffer;
const DWORD dwBytes2Read = sizeof(szBuffer) - 1;
do{
result = ::InternetReadFile(hHttpRequest, szBuffer, dwBytes2Read, &dwBytesRead);
if (FALSE == result)
{
errorCode = ::GetLastError();
}
temp += dwBytesRead;
} while (result && dwBytesRead > 0);
// need error handling for below 3
result = ::InternetCloseHandle(hHttpRequest);
result = ::InternetCloseHandle(hHttpSession);
result = ::InternetCloseHandle(hInternetSession);
return errorCode;
}
PROBLEM:
In the provided code example, I need to call InternetCloseHandle 3 times consecutively.
I do not know how to structure that part of code to perform proper error handling.
My idea would be to do do the following:
result = ::InternetCloseHandle(hHttpRequest);
if(result)
{
result = ::InternetCloseHandle(hHttpSession);
if (result)
{
result = ::InternetCloseHandle(hInternetSession);
if(!result) return ::GetLastError();
}
else return ::GetLastError();
}
else return ::GetLastError();
However, being new to WinInet, I am not sure if my solution is correct.
QUESTION:
Can you please instruct me on how to handle the scenario in the provided code example?
I understand that my question might be confusing, but please take into consideration that English is not my native. Please leave a comment seeking further clarifications.
UPDATE #1:
I have tried to apply RAII:
#include <Windows.h>
#include <iostream>
#include <WinInet.h>
#pragma comment(lib, "Wininet.lib")
class CInternetOpenRAII
{
HINTERNET hIntSession;
public:
CInternetOpenRAII(){}
HINTERNET get() const { return hIntSession; }
DWORD init()
{
hIntSession = ::InternetOpen("WinInet", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
return hIntSession ? ERROR_SUCCESS : ::GetLastError();
}
~CInternetOpenRAII()
{
if(hIntSession)
{
if(!::InternetCloseHandle(hIntSession))
{
std::cerr << "InternetOpen failed with GetLastErrorCode: " << ::GetLastError();
}
}
}
};
class CInternetConnectRAII
{
HINTERNET hHttpSession;
public:
CInternetConnectRAII() {}
HINTERNET get() const { return hHttpSession; }
DWORD init(const HINTERNET &hIntSession, const char *url)
{
hHttpSession = ::InternetConnect(hIntSession, url, INTERNET_DEFAULT_HTTP_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
return hHttpSession ? ERROR_SUCCESS : ::GetLastError();
}
~CInternetConnectRAII()
{
if(hHttpSession)
{
if(!::InternetCloseHandle(hHttpSession))
{
std::cerr << "InternetConnect failed with GetLastErrorCode: " << ::GetLastError();
}
}
}
};
class CHttpOpenRequestRAII
{
HINTERNET hHttpRequest;
public:
CHttpOpenRequestRAII() {}
HINTERNET get() const { return hHttpRequest; }
DWORD init(const HINTERNET &hHttpSession, const char *request)
{
hHttpRequest = ::HttpOpenRequest(hHttpSession, "POST", request, 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
return hHttpRequest ? ERROR_SUCCESS : ::GetLastError();
}
DWORD doRequest(const char *data, size_t dataLength, const char *header, size_t headerLength)
{
if (!::HttpSendRequest(hHttpRequest, header, headerLength, (void *)data, dataLength))
return ::GetLastError();
CHAR szBuffer[10] = "";
DWORD dwRead = 0;
const int dwBytes2Read = sizeof(szBuffer) - 1;
while (::InternetReadFile(hHttpRequest, szBuffer, dwBytes2Read, &dwRead) && dwRead)
{
std::cout << szBuffer;
}
return ERROR_SUCCESS;
}
~CHttpOpenRequestRAII()
{
if(hHttpRequest)
{
if(!::InternetCloseHandle(hHttpRequest))
{
std::cerr << "HttpOpenRequest failed with GetLastErrorCode: " << ::GetLastError();
}
}
}
};
int main()
{
DWORD error = ERROR_SUCCESS;
CInternetOpenRAII session;
error = session.init();
if(error) return error;
CInternetConnectRAII conn;
error = conn.init(session.get(), "www.test.com");
if(error) return error;
CHttpOpenRequestRAII req;
error = req.init(conn.get(), "/home/something");
if(error) return error;
error = req.doRequest("parameter=1234", strlen("parameter=1234"),
"Content-Type: application/x-www-form-urlencoded", strlen("Content-Type: application/x-www-form-urlencoded"));
if(error) return error;
return 0;
}
Now I do not know how to handle error in destructor. Can somebody please look at the code and provide some advice on that?