C++ Importing RSA public keys from modulus and exponent with CNG - c++

I'm trying to use CNG to encrypt some data with a public key that is given as a parameter. When calling NCryptImportKey function, I get a NTE_BAD_DATA error which isn't listed in the msdn page.
My code:
#include <iostream>
#include <Windows.h>
#include <Bcrypt.h>
#include <Ntstatus.h>
#include <string>
#include <vector>
#include "base64.h"
using std::string;
using std::vector;
struct MyRSAPublicBlob {
BCRYPT_RSAKEY_BLOB blob;
BYTE exponent[3];
BYTE modulus[128];
MyRSAPublicBlob(const vector<BYTE>& mod, const vector<BYTE>& exp)
{
blob.BitLength = (128 + 3) * 8;
blob.Magic = BCRYPT_RSAPUBLIC_MAGIC;
blob.cbModulus = 128;
blob.cbPublicExp = 3;
for (size_t i = 0; i < mod.size(); ++i) //copy BigEndian
modulus[i] = mod[mod.size() - 1 - i];
for (size_t i = 0; i < exp.size(); ++i) //copy BigEndian
exponent[i] = exp[exp.size() - 1 - i];
}
MyRSAPublicBlob() { ; }
};
MyRSAPublicBlob b;
bool RSA_encrypt() {
SECURITY_STATUS stat;
NCRYPT_PROV_HANDLE hProv;
NCRYPT_KEY_HANDLE hKey;
stat = NCryptOpenStorageProvider(&hProv, MS_KEY_STORAGE_PROVIDER, 0);
if (ERROR_SUCCESS != stat) {
std::cout << "failed in NCryptOpenStorageProvider: " << GetLastError() << std::endl;
return false;
}
stat = NCryptImportKey(hProv,
NULL,
BCRYPT_RSAPUBLIC_BLOB,
NULL,
&hKey,
(PBYTE)&b.blob,
sizeof(b),
0);
if (ERROR_SUCCESS != stat) {
std::cout << "failed in NCryptImportKey: " << GetLastError() << std::endl;
return false;
}
Example of how I construct MyRSAPublicBlob:
string PubKeyModulus = "yVUndgQFuB5Z5FgC0/WgWCg6Y8VuB582avGjQDdeoJDa1+RBKCyXo700sAMSGjM/bVakOlFqvCsVFNBysx1CH731CDb2DR1a0bsmYmDQ9d0ZHX+AOohVDIx9mc7bkDQZoEFpe9NqFsu95Y9yktpl1JKPmKyLOFgufGJYYvQyoOM=";
string PubKeyExp = "AQAB";
vector<BYTE> PubKeyModulus_bin = base64_decode(PubKeyModulus);
vector<BYTE> PubKeyExp_bin = base64_decode(PubKeyExp);
struct MyRSAPublicBlob c(PubKeyModulus_bin, PubKeyExp_bin);
b = c;
Anything I'm doing bluntly wrong?

An RSA public key BLOB (BCRYPT_RSAPUBLIC_BLOB) has the following format in contiguous memory. Try using #pragma pack to avoid any padding issues. For example,
#pragma pack(push, 1)
struct MyRSAPublicBlob {
BCRYPT_RSAKEY_BLOB blob;
BYTE exponent[3];
BYTE modulus[32];
...};
#pragma pack(pop)

The BitLength value is the "size of the key", which for RSA means "the size of the Modulus value". So it's sort of redundant with cbModulus, but c'est la vie.
If you remove the + 3 in your calculation of BitLength it'll probably start working. Compare to .NET building the blob for RSACng.ImportParameters: http://source.dot.net/#System.Security.Cryptography.Cng/Common/System/Security/Cryptography/RSACng.ImportExport.cs,79

Related

make a hwid login in c++ (mulitbyte)

hello guys i tried to make a hwid login for a app. The problem is when i compile all the code i have this error.
Error C2676 binary '==': 'std::basic_string,std::allocator>' does not define this operator or a conversion to a type acceptable to the predefined operator
#include <Windows.h>
#include <iostream>
#include <tchar.h>
#include <intrin.h>
#include <TlHelp32.h>
#include <algorithm>
#include <vector>
using namespace std;
vector<string> serial;
vector<string> windows;
void loadserial()
{
serial.push_back("1731602307");
}
void loadWindows()
{
windows.push_back("29548");
}
int main()
{
TCHAR volumeName[MAX_PATH + 1] = { 0 };
TCHAR fileSystemName[MAX_PATH + 1] = { 0 };
DWORD serialNumber = 0;
DWORD maxComponentLen = 0;
DWORD fileSystemFlags = 0;
if (GetVolumeInformation(
_T("C:\\"),
volumeName,
ARRAYSIZE(volumeName),
&serialNumber,
&maxComponentLen,
&fileSystemFlags,
fileSystemName,
ARRAYSIZE(fileSystemName)))
{
}
int cpuinfo[4] = { 0, 0, 0, 0 };
__cpuid(cpuinfo, 0);
char16_t hash = 0;
char16_t* ptr = (char16_t*)(&cpuinfo[0]);
for (char32_t i = 0; i < 8; i++)
hash += ptr[i];
while (true)
{
if (find(serial.begin(), serial.end(), serialNumber) != serial.end())
{
std::cout << "nice you are in our auth system!!";
}
else
{
std::cout << "you arent in the whitelist ;(";
}
}
return(0);
}
OK, now it's clear
find(serial.begin(), serial.end(), serialNumber)
serial is a vector<string> but serialNumber is a DWORD. You can't use find to look for a DWORD in a vector of strings. I guess you need to convert the DWORD to a string first, or maybe you could change serial to a vector<DWORD>.
And as drescherjm says get into the habit of looking at the output tab for your error messages, it's much more useful than the error list (which for some reason microsoft insist on showing you first).

Read a registry value correctly with the type reg_binary c++

My problem is that, I can't retrieve a Registry value correctly in a hex format, converting it to a string so it appears this way in my ListBox (image 1), I know how to do it correctly in C#, but I'm new to C++.
String ks;
DWORD reg2()
{
char value[255];
DWORD BufferSize = BUFFER;
RegGetValue(HKEY_CURRENT_USER, namebuf, "415846243", RRF_RT_ANY, NULL, (PVOID)&value, &BufferSize);
std::wstringstream box_messages;
box_messages << value;
ks = box_messages.str().c_str();
}
void __fastcall TAAP_Test::Button1Click(TObject *Sender)
{
ListBox1->Items->Add(ks);
}
This image shows the result on my program:
This image shows what registry value I'm trying to retrieve:
The Registry value you are reading is in a raw binary format (REG_BINARY). What you see in the Registry Editor is not the raw data itself, but a human-readable hex representation of the data. RegGetValueA() will not return that hex representation to you, it will return the raw binary data instead.
You are reading the raw data fine (minus the lack of error checking), but you are trying to write it as-is to your std::wstringstream, which is why you get the weird result you see in your ListBox. You need to instead loop through the individual bytes of the data, encoding each byte to a hex representation that is then put in to your std::wstringstream, eg:
#include <iostream>
#include <iomanip>
void reg2()
{
char value[255];
DWORD BufferSize = sizeof(value);
if (RegGetValueA(HKEY_CURRENT_USER, namebuf, "415846243", RRF_RT_ANY, NULL, value, &BufferSize) == ERROR_SUCCESS)
{
std::wstringstream box_messages;
for(DWORD i = 0; i < BufferSize; ++i) {
box_messages << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(value[i]) << L" ";
}
ks = box_messages.str().c_str();
}
else
ks = _D("error");
}
Alternatively, the RTL has an IntToHex() function available:
#include <System.SysUtils.hpp>
void reg2()
{
char value[255];
DWORD BufferSize = sizeof(value);
if (RegGetValueA(HKEY_CURRENT_USER, namebuf, "415846243", RRF_RT_ANY, NULL, value, &BufferSize) == ERROR_SUCCESS)
{
std::wstringstream box_messages;
for(DWORD i = 0; i < BufferSize; ++i) {
box_messages << IntToHex(static_cast<int>(value[i]), 2).c_str() << _D(" ");
}
ks = box_messages.str().c_str();
/* or simpler:
ks = _D("");
for(DWORD i = 0; i < BufferSize; ++i) {
ks += (IntToHex(static_cast<int>(value[i]), 2) + _D(" "));
}
*/
}
else
ks = _D("error");
}
Alternatively, UnicodeString has a cat_sprintf() method available:
void reg2()
{
char value[255];
DWORD BufferSize = sizeof(value);
if (RegGetValueA(HKEY_CURRENT_USER, namebuf, "415846243", RRF_RT_ANY, NULL, value, &BufferSize) == ERROR_SUCCESS)
{
ks = _D("");
for(DWORD i = 0; i < BufferSize; ++i) {
ks.cat_sprintf(_D("%02X "), static_cast<int>(value[i]));
}
}
else
ks = _D("error");
}

Incorrect signature with RSA and SHA256

I have the following string:ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=
I want to apply SHA256 to it and obtain its hash.
Then I want to sign that hash with RSA and a private key.
This is the signature I'm suppose to be obtaining (without line breaks):
Zg8ftxJqRyoreMQtMKAZNrjHHcD/rOSkU29Ty8zV9aItwHBDO0WpzaaPrqnX6/vdayUAndDVvSBoOc9g0WBkFHQHtB/auLlq+ABeBP4jxy
d7ypPxBbJFecfZiBDaGCq4jAxUnhQ2HjT5R23DHOOcf/i50TrWXr2G5k8enqa754TUn1JiDOJJT2JkfnKmgM7EPpCjHV/eCJsOQFXNaxht
h7zHz5hZ4aOfy6EGGveOggzIjKSLeo0pIE8jBc1wy9V8vZkhPTpkeLguCxnwvpMIV1X7zF3m5OoM0PbC5yXgPUYPrz0JNSlvCKR9q5CsFm
rnit5vBfi5el1ZmevP2MgyEA==
This is the signature I get:
AR1X19H5wyb9IEi9WHrhatkR1jtTc7TovX23tdx8yID5CEWz+DF5kBNCXZxttJ8v
ctsbOL0rrQ0b4Gqa2ld00+nfzZJNg1osWwKb+sj6yNLy1XLqxFvfn1wrZ9Y8yOwS
oqJ0tTCpYbbbMo1mSVO4YuD18GbZJEDBUhBYY5D8H0MoHCSWLXsAjThAImyxw4ch
Hr2d1Sli4n6OA+CckGOQ15uLk6JiO6rNzNWfbbSb8a9trJ7bAdVPiKoln1X9tnWF
s3HK6fnfro9jlRQQ/Z0bCpF+FQrWrLouvLk+mjuTeiC+86HeeqzqlReAtpqtcO5/
9lWmrxXV2qZIqfuPYMovcA==
The code I'm using:
#include <iostream>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <assert.h>
#include <string.h>
#include <cstring>
std::string privateKey = "-----BEGIN RSA PRIVATE KEY-----\n"\
"MIIEogIBAAKCAQEAjdKXiqYHzi++YmEb9X6qvqFWLCz1VEfxom2JhinPSJxxcuZW\n"\
"Bejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvYJumKO4R5zg0QSA7qdxiEhcwf/ekf\n"\
"SvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ7EgEcWUTvCs/GZJLI9s6XmKY2SMm\n"\
"v9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/yJ4vZwXvXGFqNDJyqG+ww7f77HYu\n"\
"bQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/BeZlL1YJHHM7CIBnb3/bzED0n944wo\n"\
"io+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/JRQIDAQABAoIBAG2AzvWE4L346z02\n"\
"0cmptdhe5hRR2lLrAc1yWh83JQ9hi881vfHuMtRql+3cZ218SV4nRNarIo6612NJ\n"\
"JFfM3SaeZ9cwoIPSXmHk8nBmg9xzEbiRSVIzA09uPZB4t9EB+sNYQvDkPMuPn0b3\n"\
"EWaq+LWRnayYaLZ/hccOx+m1mcnJnIs27+EPnufrUKVniCguburQoU3VEXSFCzBk\n"\
"23rhSu20vUOikLuuU4gcvWfnfUoOwdhb2iBhjgMbsjTTmg3+GQuPtblCSTKjk11F\n"\
"YX2MJHEDFfwVzSurmbqAZC9rjr7PbflC8GMmPfa1LCb7IG5s9AIM4v9Fea0SyZP+\n"\
"/pM9mzkCgYEAyjLPU7ieqly9+mgeb2fmWh7pYgO49KuFIqqHnP+LaXXYK/TvCJ8X\n"\
"zJ3PxBgwVMOT94nXSDNjzNLzp0hl8OWWBH0tN0fiq1OEyySM3Mlji6o8KpGcU1k4\n"\
"jFkXMK1rVQcW8ckLmzMrQF3SphQi4UiEpLX1Zba4YQ4fNHK8NHHHaEMCgYEAs48m\n"\
"Oe4iEZcVDnag+Mp0Zjgu4mYJeeeGtVUZFCJOeyLDsQVmnt5mJIgGwrxg4o3qljut\n"\
"aAUXzf8aYZ0fURAsLcwnQg03THFKeIt94Rw/72n2UWT+AZTU3GQtuwf+osZHUfS3\n"\
"XTLaQE+A1JBC4XLJ99j/95sxt6xZy5YyfhfY09cCgYAbqyhDxJexqE823NiNViJn\n"\
"YqN9DhVZJb9qJvu3uCBTphSWr0WmYF7ZWR79LnIupzSwQuR6tM2LUbKVyYpplIEa\n"\
"zCZL0kJqP1uEkNPVwpkkm37wNEy3+xWJ3wcVWiW91OKG44P7EN1ySWRx5X+AZHQC\n"\
"NgQGjyJb5ZrPioPGiWtIEQKBgE/0B/N3o9ftTET6cccWbootDkNlaAbOH1+TGu2q\n"\
"MQQHgNfMLdvD7/uITmpb81AuHSz0Ocy9p9HkK90XV6CC8QkbhMeWlu8E60It6slY\n"\
"COgUaMfpjmkp2nagbPSBJNNaMtu9egCX6jMEs7ry2bUFpgUkrSWWB1df+UP8B1O6\n"\
"TqRVAoGAVQoCUPVm6C6h6V5dgPvsJMxJ8EjOCgwkXNucAHWcpBV3/LlxLiCGRuEL\n"\
"B+epYxqwKLpSQBhldasKmmKB0M6MFTwxXwxCmCi80+DBdP5A7GIK52ZGth63i22t\n"\
"FI8MeDIzA5HqAI24P7ltozoEYAB7GIdJQXq9oT/DRagTwQUzQ8E=\n"\
"-----END RSA PRIVATE KEY-----\n";
/*std::string privateKey ="-----BEGIN PRIVATE KEY-----\n"\
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCN0peKpgfOL75i\n"\
"YRv1fqq+oVYsLPVUR/GibYmGKc9InHFy5lYF6OTYjnIIvmkOdRobbGlCUxORX/tL\n"\
"sl8Ya9gm6Yo7hHnODRBIDup3GISFzB/96R9K/MzYQOcscMIoBDARaycnLvy7FlMv\n"\
"O7/rlVnsSARxZRO8Kz8Zkksj2zpeYpjZIya/369+oGqQk1cTRkHo59JvJ4Tfbk/3\n"\
"iIyf4H/Ini9nBe9cYWo0MnKob7DDt/vsdi5tA8mMtA953LapNyCZIDCRQQlUGNgD\n"\
"qY9/8F5mUvVgkcczsIgGdvf9vMQPSf3jjCiKj7j6ucxl1+FwJWmbvgNmiaUR/0q4\n"\
"m2rm78lFAgMBAAECggEAbYDO9YTgvfjrPTbRyam12F7mFFHaUusBzXJaHzclD2GL\n"\
"zzW98e4y1GqX7dxnbXxJXidE1qsijrrXY0kkV8zdJp5n1zCgg9JeYeTycGaD3HMR\n"\
"uJFJUjMDT249kHi30QH6w1hC8OQ8y4+fRvcRZqr4tZGdrJhotn+Fxw7H6bWZycmc\n"\
"izbv4Q+e5+tQpWeIKC5u6tChTdURdIULMGTbeuFK7bS9Q6KQu65TiBy9Z+d9Sg7B\n"\
"2FvaIGGOAxuyNNOaDf4ZC4+1uUJJMqOTXUVhfYwkcQMV/BXNK6uZuoBkL2uOvs9t\n"\
"+ULwYyY99rUsJvsgbmz0Agzi/0V5rRLJk/7+kz2bOQKBgQDKMs9TuJ6qXL36aB5v\n"\
"Z+ZaHuliA7j0q4Uiqoec/4tpddgr9O8InxfMnc/EGDBUw5P3iddIM2PM0vOnSGXw\n"\
"5ZYEfS03R+KrU4TLJIzcyWOLqjwqkZxTWTiMWRcwrWtVBxbxyQubMytAXdKmFCLh\n"\
"SISktfVltrhhDh80crw0ccdoQwKBgQCzjyY57iIRlxUOdqD4ynRmOC7iZgl554a1\n"\
"VRkUIk57IsOxBWae3mYkiAbCvGDijeqWO61oBRfN/xphnR9RECwtzCdCDTdMcUp4\n"\
"i33hHD/vafZRZP4BlNTcZC27B/6ixkdR9LddMtpAT4DUkELhcsn32P/3mzG3rFnL\n"\
"ljJ+F9jT1wKBgBurKEPEl7GoTzbc2I1WImdio30OFVklv2om+7e4IFOmFJavRaZg\n"\
"XtlZHv0uci6nNLBC5Hq0zYtRspXJimmUgRrMJkvSQmo/W4SQ09XCmSSbfvA0TLf7\n"\
"FYnfBxVaJb3U4objg/sQ3XJJZHHlf4BkdAI2BAaPIlvlms+Kg8aJa0gRAoGAT/QH\n"\
"83ej1+1MRPpxxxZvKi0OQ2VoBs4fX5Ma7aoxBAeA18wt28Pv+4hOalvzUC4dLPQ5\n"\
"zL2n0eQr3RdXoILxCRuEx5aW7wTrQi3qyVgI6BRox+mOaSnadqBs9IEk01oy2716\n"\
"AJfqMwSzuvLZtQWmBSStJZYHV1/5Q/wHU7pOpFUCgYBVCgJQ9WboLqHpXl2A++wk\n"\
"zEnwSM4KDCRc25wAdZykFXf8uXEuIIZG4QsH56ljGrAoulJAGGV1qwqaYoHQzowV\n"\
"PDFfDEKYKLzT4MF0/kDsYgrnZka2HreLba0Ujwx4MjMDkeoAjbg/uW2jOgRgAHsY\n"\
"h0lBer2hP8NFqBPBBTNDwQ==\n"\
"-----END PRIVATE KEY-----\n";
*/
std::string publicKey ="-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjdKXiqYHzi++YmEb9X6q\n"\
"vqFWLCz1VEfxom2JhinPSJxxcuZWBejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvY\n"\
"JumKO4R5zg0QSA7qdxiEhcwf/ekfSvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ\n"\
"7EgEcWUTvCs/GZJLI9s6XmKY2SMmv9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/\n"\
"yJ4vZwXvXGFqNDJyqG+ww7f77HYubQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/Be\n"\
"ZlL1YJHHM7CIBnb3/bzED0n944woio+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/J\n"\
"RQIDAQAB\n"\
"-----END PUBLIC KEY-----\n";
RSA* createPrivateRSA(std::string key) {
RSA *rsa = NULL;
const char* c_string = key.c_str();
BIO * keybio = BIO_new_mem_buf((void*)c_string, -1);
if (keybio==NULL) {
return 0;
}
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
return rsa;
}
RSA* createPublicRSA(std::string key) {
RSA *rsa = NULL;
BIO *keybio;
const char* c_string = key.c_str();
keybio = BIO_new_mem_buf((void*)c_string, -1);
if (keybio==NULL) {
return 0;
}
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
return rsa;
}
bool RSASign( RSA* rsa,
const unsigned char* Msg,
size_t MsgLen,
unsigned char** EncMsg,
size_t* MsgLenEnc) {
EVP_MD_CTX* m_RSASignCtx = EVP_MD_CTX_create();
EVP_PKEY* priKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(priKey, rsa);
if (EVP_DigestSignInit(m_RSASignCtx,NULL, EVP_sha256(), NULL,priKey)<=0) {
return false;
}
if (EVP_DigestSignUpdate(m_RSASignCtx, Msg, MsgLen) <= 0) {
return false;
}
if (EVP_DigestSignFinal(m_RSASignCtx, NULL, MsgLenEnc) <=0) {
return false;
}
*EncMsg = (unsigned char*)malloc(*MsgLenEnc);
if (EVP_DigestSignFinal(m_RSASignCtx, *EncMsg, MsgLenEnc) <= 0) {
return false;
}
EVP_MD_CTX_free(m_RSASignCtx);
return true;
}
bool RSAVerifySignature( RSA* rsa,
unsigned char* MsgHash,
size_t MsgHashLen,
const char* Msg,
size_t MsgLen,
bool* Authentic) {
*Authentic = false;
EVP_PKEY* pubKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pubKey, rsa);
EVP_MD_CTX* m_RSAVerifyCtx = EVP_MD_CTX_create();
if (EVP_DigestVerifyInit(m_RSAVerifyCtx,NULL, EVP_sha256(),NULL,pubKey)<=0) {
return false;
}
if (EVP_DigestVerifyUpdate(m_RSAVerifyCtx, Msg, MsgLen) <= 0) {
return false;
}
int AuthStatus = EVP_DigestVerifyFinal(m_RSAVerifyCtx, MsgHash, MsgHashLen);
if (AuthStatus==1) {
*Authentic = true;
EVP_MD_CTX_free(m_RSAVerifyCtx);
return true;
} else if(AuthStatus==0){
*Authentic = false;
EVP_MD_CTX_free(m_RSAVerifyCtx);
return true;
} else{
*Authentic = false;
EVP_MD_CTX_free(m_RSAVerifyCtx);
return false;
}
}
void Base64Encode( const unsigned char* buffer,
size_t length,
char** base64Text) {
BIO *bio, *b64;
BUF_MEM *bufferPtr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_write(bio, buffer, length);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
BIO_free_all(bio);
*base64Text=(*bufferPtr).data;
}
size_t calcDecodeLength(const char* b64input) {
size_t len = strlen(b64input), padding = 0;
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
return (len*3)/4 - padding;
}
void Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) {
BIO *bio, *b64;
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
*length = BIO_read(bio, *buffer, strlen(b64message));
BIO_free_all(bio);
}
unsigned char * strToHex(std::string plainText){
unsigned char * hexArray;
hexArray = (unsigned char*)malloc(plainText.length());
for(int i = 0; i < plainText.size();i++){
hexArray[i] = std::strtol(&plainText[i],NULL,64);
}
return hexArray;
}
char* signMessage(std::string privateKey, std::string plainText) {
RSA* privateRSA = createPrivateRSA(privateKey);
unsigned char* encMessage;
char* base64Text;
size_t encMessageLength;
RSASign(privateRSA, (unsigned char*) plainText.data(), plainText.length(), &encMessage, &encMessageLength);
Base64Encode(encMessage, encMessageLength, &base64Text);
free(encMessage);
return base64Text;
}
bool verifySignature(std::string publicKey, std::string plainText, char* signatureBase64) {
RSA* publicRSA = createPublicRSA(publicKey);
unsigned char* encMessage;
size_t encMessageLength;
bool authentic;
Base64Decode(signatureBase64, &encMessage, &encMessageLength);
bool result = RSAVerifySignature(publicRSA, encMessage, encMessageLength, plainText.c_str(), plainText.length(), &authentic);
return result & authentic;
}
int main() {
std::string plainText = "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=";
char* signature = signMessage(privateKey, plainText);
bool authentic = verifySignature(publicKey, "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=", signature);
if ( authentic ) {
std::cout << "Authentic" << std::endl;
std::cout << signature << std::endl;
} else {
std::cout << "Not Authentic" << std::endl;
}
}
What I'm actually trying to do is to 'translate' a C# code used by a third-party, I REQUIRE to do the same operations, I tried looking for the docs of the libreries used here but I couldn't find much, the code I'm trying to replicate is the following:
using System;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace KeyPairLoad
{
class Program
{
static void Main(string[] args)
{
string cadena = ComputeSha256Hash("ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=");
string pathPrivateKey = #"C:\Users\xxx\Downloads\Fieles de pruebas\FOO1\some.key";
string password = "12345678a";
byte[] privBytes = System.IO.File.ReadAllBytes(pathPrivateKey);
AsymmetricKeyParameter llavePrivada = PrivateKeyFactory.DecryptKey(password.ToCharArray(), privBytes);
var rsaPriv = DotNetUtilities.ToRSA(llavePrivada as RsaPrivateCrtKeyParameters);
var csp = new CspParameters();
csp.KeyContainerName = "KeyContainer";
var rsaPrivate = new RSACryptoServiceProvider(csp);
string fin = Convert.ToBase64String(rsaPrivate.SignHash(Convert.FromBase64String(cadena), "SHA256"));
}
static string ComputeSha256Hash(string rawData)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
return Convert.ToBase64String(bytes);
}
}
}
}
This third-party gave me the signature I'm supposed to be obtaining. I've tried many things but nothing works, I get different signatures but not the one I'm looking for.
Am I missing something in my translation? Am I doing something wrong?
Thanks for your patience and time. Let me know if u require more info.
Regards!
This code gets the desired signature:
Zg8ftxJqRyoreMQtMKAZNrjHHcD/rOSkU29Ty8zV9aItwHBDO0WpzaaPrqnX6/vdayUAndDVvSBoOc9g0WBkFHQHtB/auLlq+ABeBP4jxy
d7ypPxBbJFecfZiBDaGCq4jAxUnhQ2HjT5R23DHOOcf/i50TrWXr2G5k8enqa754TUn1JiDOJJT2JkfnKmgM7EPpCjHV/eCJsOQFXNaxht
h7zHz5hZ4aOfy6EGGveOggzIjKSLeo0pIE8jBc1wy9V8vZkhPTpkeLguCxnwvpMIV1X7zF3m5OoM0PbC5yXgPUYPrz0JNSlvCKR9q5CsFm
rnit5vBfi5el1ZmevP2MgyEA==
that I originally stated. It writes it in a file called result.dat which I have to encode in base 64 resulting int he above signature.
#include <iostream>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <assert.h>
#include <string>
#include <cstring>
#include <memory>
#include <vector>
#include <fstream>
#include "base64.h"
std::string privateKey = "-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEogIBAAKCAQEAjdKXiqYHzi++YmEb9X6qvqFWLCz1VEfxom2JhinPSJxxcuZW\n"
"Bejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvYJumKO4R5zg0QSA7qdxiEhcwf/ekf\n"
"SvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ7EgEcWUTvCs/GZJLI9s6XmKY2SMm\n"
"v9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/yJ4vZwXvXGFqNDJyqG+ww7f77HYu\n"
"bQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/BeZlL1YJHHM7CIBnb3/bzED0n944wo\n"
"io+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/JRQIDAQABAoIBAG2AzvWE4L346z02\n"
"0cmptdhe5hRR2lLrAc1yWh83JQ9hi881vfHuMtRql+3cZ218SV4nRNarIo6612NJ\n"
"JFfM3SaeZ9cwoIPSXmHk8nBmg9xzEbiRSVIzA09uPZB4t9EB+sNYQvDkPMuPn0b3\n"
"EWaq+LWRnayYaLZ/hccOx+m1mcnJnIs27+EPnufrUKVniCguburQoU3VEXSFCzBk\n"
"23rhSu20vUOikLuuU4gcvWfnfUoOwdhb2iBhjgMbsjTTmg3+GQuPtblCSTKjk11F\n"
"YX2MJHEDFfwVzSurmbqAZC9rjr7PbflC8GMmPfa1LCb7IG5s9AIM4v9Fea0SyZP+\n"
"/pM9mzkCgYEAyjLPU7ieqly9+mgeb2fmWh7pYgO49KuFIqqHnP+LaXXYK/TvCJ8X\n"
"zJ3PxBgwVMOT94nXSDNjzNLzp0hl8OWWBH0tN0fiq1OEyySM3Mlji6o8KpGcU1k4\n"
"jFkXMK1rVQcW8ckLmzMrQF3SphQi4UiEpLX1Zba4YQ4fNHK8NHHHaEMCgYEAs48m\n"
"Oe4iEZcVDnag+Mp0Zjgu4mYJeeeGtVUZFCJOeyLDsQVmnt5mJIgGwrxg4o3qljut\n"
"aAUXzf8aYZ0fURAsLcwnQg03THFKeIt94Rw/72n2UWT+AZTU3GQtuwf+osZHUfS3\n"
"XTLaQE+A1JBC4XLJ99j/95sxt6xZy5YyfhfY09cCgYAbqyhDxJexqE823NiNViJn\n"
"YqN9DhVZJb9qJvu3uCBTphSWr0WmYF7ZWR79LnIupzSwQuR6tM2LUbKVyYpplIEa\n"
"zCZL0kJqP1uEkNPVwpkkm37wNEy3+xWJ3wcVWiW91OKG44P7EN1ySWRx5X+AZHQC\n"
"NgQGjyJb5ZrPioPGiWtIEQKBgE/0B/N3o9ftTET6cccWbootDkNlaAbOH1+TGu2q\n"
"MQQHgNfMLdvD7/uITmpb81AuHSz0Ocy9p9HkK90XV6CC8QkbhMeWlu8E60It6slY\n"
"COgUaMfpjmkp2nagbPSBJNNaMtu9egCX6jMEs7ry2bUFpgUkrSWWB1df+UP8B1O6\n"
"TqRVAoGAVQoCUPVm6C6h6V5dgPvsJMxJ8EjOCgwkXNucAHWcpBV3/LlxLiCGRuEL\n"
"B+epYxqwKLpSQBhldasKmmKB0M6MFTwxXwxCmCi80+DBdP5A7GIK52ZGth63i22t\n"
"FI8MeDIzA5HqAI24P7ltozoEYAB7GIdJQXq9oT/DRagTwQUzQ8E=\n"
"-----END RSA PRIVATE KEY-----\n";
// std::string privateKey ="-----BEGIN PRIVATE KEY-----\n"\
// "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCN0peKpgfOL75i\n"\
// "YRv1fqq+oVYsLPVUR/GibYmGKc9InHFy5lYF6OTYjnIIvmkOdRobbGlCUxORX/tL\n"\
// "sl8Ya9gm6Yo7hHnODRBIDup3GISFzB/96R9K/MzYQOcscMIoBDARaycnLvy7FlMv\n"\
// "O7/rlVnsSARxZRO8Kz8Zkksj2zpeYpjZIya/369+oGqQk1cTRkHo59JvJ4Tfbk/3\n"\
// "iIyf4H/Ini9nBe9cYWo0MnKob7DDt/vsdi5tA8mMtA953LapNyCZIDCRQQlUGNgD\n"\
// "qY9/8F5mUvVgkcczsIgGdvf9vMQPSf3jjCiKj7j6ucxl1+FwJWmbvgNmiaUR/0q4\n"\
// "m2rm78lFAgMBAAECggEAbYDO9YTgvfjrPTbRyam12F7mFFHaUusBzXJaHzclD2GL\n"\
// "zzW98e4y1GqX7dxnbXxJXidE1qsijrrXY0kkV8zdJp5n1zCgg9JeYeTycGaD3HMR\n"\
// "uJFJUjMDT249kHi30QH6w1hC8OQ8y4+fRvcRZqr4tZGdrJhotn+Fxw7H6bWZycmc\n"\
// "izbv4Q+e5+tQpWeIKC5u6tChTdURdIULMGTbeuFK7bS9Q6KQu65TiBy9Z+d9Sg7B\n"\
// "2FvaIGGOAxuyNNOaDf4ZC4+1uUJJMqOTXUVhfYwkcQMV/BXNK6uZuoBkL2uOvs9t\n"\
// "+ULwYyY99rUsJvsgbmz0Agzi/0V5rRLJk/7+kz2bOQKBgQDKMs9TuJ6qXL36aB5v\n"\
// "Z+ZaHuliA7j0q4Uiqoec/4tpddgr9O8InxfMnc/EGDBUw5P3iddIM2PM0vOnSGXw\n"\
// "5ZYEfS03R+KrU4TLJIzcyWOLqjwqkZxTWTiMWRcwrWtVBxbxyQubMytAXdKmFCLh\n"\
// "SISktfVltrhhDh80crw0ccdoQwKBgQCzjyY57iIRlxUOdqD4ynRmOC7iZgl554a1\n"\
// "VRkUIk57IsOxBWae3mYkiAbCvGDijeqWO61oBRfN/xphnR9RECwtzCdCDTdMcUp4\n"\
// "i33hHD/vafZRZP4BlNTcZC27B/6ixkdR9LddMtpAT4DUkELhcsn32P/3mzG3rFnL\n"\
// "ljJ+F9jT1wKBgBurKEPEl7GoTzbc2I1WImdio30OFVklv2om+7e4IFOmFJavRaZg\n"\
// "XtlZHv0uci6nNLBC5Hq0zYtRspXJimmUgRrMJkvSQmo/W4SQ09XCmSSbfvA0TLf7\n"\
// "FYnfBxVaJb3U4objg/sQ3XJJZHHlf4BkdAI2BAaPIlvlms+Kg8aJa0gRAoGAT/QH\n"\
// "83ej1+1MRPpxxxZvKi0OQ2VoBs4fX5Ma7aoxBAeA18wt28Pv+4hOalvzUC4dLPQ5\n"\
// "zL2n0eQr3RdXoILxCRuEx5aW7wTrQi3qyVgI6BRox+mOaSnadqBs9IEk01oy2716\n"\
// "AJfqMwSzuvLZtQWmBSStJZYHV1/5Q/wHU7pOpFUCgYBVCgJQ9WboLqHpXl2A++wk\n"\
// "zEnwSM4KDCRc25wAdZykFXf8uXEuIIZG4QsH56ljGrAoulJAGGV1qwqaYoHQzowV\n"\
// "PDFfDEKYKLzT4MF0/kDsYgrnZka2HreLba0Ujwx4MjMDkeoAjbg/uW2jOgRgAHsY\n"\
// "h0lBer2hP8NFqBPBBTNDwQ==\n"\
// "-----END PRIVATE KEY-----\n";
std::string publicKey ="-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjdKXiqYHzi++YmEb9X6q\n"\
"vqFWLCz1VEfxom2JhinPSJxxcuZWBejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvY\n"\
"JumKO4R5zg0QSA7qdxiEhcwf/ekfSvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ\n"\
"7EgEcWUTvCs/GZJLI9s6XmKY2SMmv9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/\n"\
"yJ4vZwXvXGFqNDJyqG+ww7f77HYubQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/Be\n"\
"ZlL1YJHHM7CIBnb3/bzED0n944woio+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/J\n"\
"RQIDAQAB\n"\
"-----END PUBLIC KEY-----\n";
RSA* createPrivateRSA(std::string key) {
RSA *rsa = NULL;
const char* c_string = key.c_str();
BIO * keybio = BIO_new_mem_buf((void*)c_string, -1);
if (keybio==NULL) {
return 0;
}
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
return rsa;
}
void sellar(std::string hashclear, std::string privateKey_string){
EVP_PKEY_CTX *ctx;
/* md is a SHA-256 digest in this example. */
unsigned char *sig;
size_t siglen;
unsigned char clear_message[hashclear.length()];
strcpy((char*) clear_message,hashclear.c_str());
size_t mdlen;
// //1. Decodificar hashclear. || base64 -d data.dat > b64.dat -> Me debe dar una cadena de 32 bytes.
unsigned char * md = base64_decode(clear_message, strlen((char*) clear_message), &mdlen);
std::cout << "MD is " << mdlen << " bytes long.\n";
// //2. Cargar llave privada.
RSA* privateRSA = createPrivateRSA(privateKey);
EVP_PKEY* signing_key = EVP_PKEY_new();
EVP_PKEY_assign_RSA(signing_key, privateRSA);
ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
if(!ctx) {
std::cout << "Error CTX_new" << std::endl;
return;
}
if (EVP_PKEY_sign_init(ctx) <= 0){
std::cout << "Error sign_init\n";
return;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0){
std::cout << "Error set_rsa_padding\n";
return;
}
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0){
std::cout << "Error set_signature_md\n";
return;
}
/* Determine buffer length */
if (EVP_PKEY_sign(ctx, NULL, &siglen, md, mdlen) <= 0){
std::cout << "Error PKEY_sign\n";
return;
}
sig = (unsigned char*)OPENSSL_malloc(siglen);
if (!sig){
std::cout << "Error malloc";
return;
}
if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0){
std::cout << "Error sign";
return;
}
std::cout << siglen << " bytes written in buffer sig\n";
/* Signature is siglen bytes written to buffer sig */
size_t cadena_sellada_len;
unsigned char * cadena_sellada = base64_encode(sig, siglen, &cadena_sellada_len);
std::ofstream myfile ("result_final.dat");
if (myfile.is_open())
{
for(int count = 0; count < cadena_sellada_len; count ++){
myfile << cadena_sellada[count] ;
}
myfile.close();
}
else std::cout << "Unable to open file";
}
int main() {
std::string plainText = "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=\n";
// unsigned char src[plainText.length()];
// strcpy((char*) src,plainText.c_str());
// std::cout << "Src has " << strlen((char*)src) << " entries.\n";
// size_t out_len;
// unsigned char * bytes = base64_decode(src, strlen((char*)src), &out_len);
// std::cout << "bytes has " << out_len << " entries.\n";
// std::cout << bytes << std::endl;
// size_t re_out_len;
// unsigned char * re_encode = base64_encode(bytes, out_len,&re_out_len);
// std::cout << re_encode << "\n";
// std::ofstream myfile ("b64.dat");
// if (myfile.is_open())
// {
// for(int count = 0; count < out_len; count ++){
// myfile << bytes[count] ;
// }
// myfile.close();
// }
// else std::cout << "Unable to open file";
sellar(plainText, privateKey);
return 0;
//strcpy()
//std::cout << "Length : " << b64dat.length() << std::endl;
//char* signature = signMessage(privateKey, plainText);
//std::cout << signature << std::endl;
// bool authentic = verifySignature(publicKey, "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=", signature);
// if ( authentic ) {
// std::cout << "Authentic" << std::endl;
// } else {
// std::cout << "Not Authentic" << std::endl;
// }
}
Thank you all for your time and patience.
I'm not going to read all the code to try and figure out what it is you're trying to do and thus where your mistake(s) are. Instead, I'll just examine what you've provided and you can go from there.
Clearly, both the signatures you've provided are valid signatures. This can be seen by manually going through the verification steps, stopping just after modular exponentiation using the encrypt exponent. The result is as expected for pkcs1 EMSA-PKCS1-v1_5 encoding. And just as clearly, we can see that different SHA-256 hashes are involved. In other words, the signatures are different because the data they are signing is different.
For the signature that starts with AR1X19... the data being signed is the UTF-8 encoding of the string ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=. Note that this string a pretty obviously the base64-encoding of random looking 32 bytes. In this context one might guess that those 32-bytes are actually the sha256 hash of some other unknown quantity. And sure, enough the signature that starts with Zg8ftxJqR... is over data whose sha256 hash is the base64-decoding of ET8d....
So it looks like the first signature is correct, and the second one is the result of base64-encoding the sha256 hash during in the middle of the signing operation.

Protobuf with GZIP compression

I am having a problem in trying to serialize an array of unsigned char into file with GZIP compression using protobuf while playing with the library.
I think the problem might have to do with some of my syntax or misuse of API.
I have also tried std::fstream.
FYI, Windows 8.1 & VS2013 is the building environment.
scene.proto
syntax = "proto3";
package Recipe;
message Scene
{
repeated int32 imageData = 1 [packed=true];
}
source.cpp
#include <iostream>
#include <fstream>
#include <ostream>
#include <istream>
#include <string>
#include <cstdint>
#include "Scene.pb.h"
#include <google\protobuf\io\zero_copy_stream_impl.h>
#include <google\protobuf\io\gzip_stream.h>
int const _MIN = 0;
int const _MAX = 255;
unsigned int const _SIZE = 65200000;
unsigned int const _COMPRESSION_LEVEL = 10;
void randWithinUnsignedCharSize(uint8_t * buffer, unsigned int size)
{
for (size_t i = 0; i < size; ++i)
{
buffer[i] = _MIN + (rand() % static_cast<int>(_MAX - _MIN + 1));
}
}
using namespace google::protobuf::io;
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
Recipe::Scene * scene = new Recipe::Scene();
uint8_t * imageData = new uint8_t[_SIZE];
randWithinUnsignedCharSize(imageData, _SIZE);
for (size_t i = 0; i < _SIZE; i++)
{
scene->add_imagedata(imageData[i]);
}
std::cout << "scene->imagedata_size() " << scene->imagedata_size() << std::endl;
{
std::ofstream output("scene.art", std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
OstreamOutputStream outputFileStream(&output);
GzipOutputStream::Options options;
options.format = GzipOutputStream::GZIP;
options.compression_level = _COMPRESSION_LEVEL;
GzipOutputStream gzipOutputStream(&outputFileStream, options);
if (!scene->SerializeToZeroCopyStream(&gzipOutputStream)) {
std::cerr << "Failed to write scene." << std::endl;
return -1;
}
}
Recipe::Scene * scene1 = new Recipe::Scene();
{
std::ifstream input("scene.art", std::ifstream::in | std::ifstream::binary);
IstreamInputStream inputFileStream(&input);
GzipInputStream gzipInputStream(&inputFileStream);
if (!scene1->ParseFromZeroCopyStream(&gzipInputStream)) {
std::cerr << "Failed to parse scene." << std::endl;
return -1;
}
}
std::cout << "scene1->imagedata_size() " << scene1->imagedata_size() <<std::endl;
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
You seem to have a typo in your code. Compression level is according to documentation in range 0-9. You set incorrectly compression level to 10.
Your example is working for me when corrected to:
unsigned int const _COMPRESSION_LEVEL = 9;

How can I find the size of all files located inside a folder?

Is there any API in c++ for getting the size of a specified folder?
If not, how can I get the total size of a folder including all subfolders and files?
How about letting OS do it for you:
long long int getFolderSize(string path)
{
// command to be executed
std::string cmd("du -sb ");
cmd.append(path);
cmd.append(" | cut -f1 2>&1");
// execute above command and get the output
FILE *stream = popen(cmd.c_str(), "r");
if (stream) {
const int max_size = 256;
char readbuf[max_size];
if (fgets(readbuf, max_size, stream) != NULL) {
return atoll(readbuf);
}
pclose(stream);
}
// return error val
return -1;
}
Actually I don't want to use any third party library. Just want to
implement in pure c++.
If you use MSVC++ you have <filesystem> "as standard C++".
But using boost or MSVC - both are "pure C++".
If you don’t want to use boost, and only the C++ std:: library this answer is somewhat close. As you can see here, there is a Filesystem Library Proposal (Revision 4). Here you can read:
The Boost version of the library has been in widespread use for ten
years. The Dinkumware version of the library, based on N1975
(equivalent to version 2 of the Boost library), ships with Microsoft
Visual C++ 2012.
To illustrate the use, I adapted the answer of #Nayana Adassuriya , with very minor modifications (OK, he forgot to initialize one variable, and I use unsigned long long, and most important was to use: path filePath(complete (dirIte->path(), folderPath)); to restore the complete path before the call to other functions). I have tested and it work well in windows 7.
#include <iostream>
#include <string>
#include <filesystem>
using namespace std;
using namespace std::tr2::sys;
void getFoldersize(string rootFolder,unsigned long long & f_size)
{
path folderPath(rootFolder);
if (exists(folderPath))
{
directory_iterator end_itr;
for (directory_iterator dirIte(rootFolder); dirIte != end_itr; ++dirIte )
{
path filePath(complete (dirIte->path(), folderPath));
try{
if (!is_directory(dirIte->status()) )
{
f_size = f_size + file_size(filePath);
}else
{
getFoldersize(filePath,f_size);
}
}catch(exception& e){ cout << e.what() << endl; }
}
}
}
int main()
{
unsigned long long f_size=0;
getFoldersize("C:\\Silvio",f_size);
cout << f_size << endl;
system("pause");
return 0;
}
You may use boost in this way. You can try to optimize it some deeper.
#include <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;
namespace bsfs = boost::filesystem;
void getFoldersize(string rootFolder,long & file_size){
boost::replace_all(rootFolder, "\\\\", "\\");
bsfs::path folderPath(rootFolder);
if (bsfs::exists(folderPath)){
bsfs::directory_iterator end_itr;
for (bsfs::directory_iterator dirIte(rootFolder); dirIte != end_itr; ++dirIte )
{
bsfs::path filePath(dirIte->path());
try{
if (!bsfs::is_directory(dirIte->status()) )
{
file_size = file_size + bsfs::file_size(filePath);
}else{
getFoldersize(filePath.string(),file_size);
}
}catch(exception& e){
cout << e.what() << endl;
}
}
}
}
int main(){
long file_size =0;
getFoldersize("C:\\logs",file_size);
cout << file_size << endl;
system("pause");
return 0;
}
Something like this would be better to avoid adding symbolic(soft) links:
std::uintmax_t directorySize(const std::filesystem::path& directory)
{
std::uintmax_t size{ 0 };
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
{
if (entry.is_regular_file() && !entry.is_symlink())
{
size += entry.file_size();
}
}
return size;
}
Size of files in a folder
Please have a look at this link
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
__int64 TransverseDirectory(string path)
{
WIN32_FIND_DATA data;
__int64 size = 0;
string fname = path + "\\*.*";
HANDLE h = FindFirstFile(fname.c_str(),&data);
if(h != INVALID_HANDLE_VALUE)
{
do {
if( (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
// make sure we skip "." and "..". Have to use strcmp here because
// some file names can start with a dot, so just testing for the
// first dot is not suffient.
if( strcmp(data.cFileName,".") != 0 &&strcmp(data.cFileName,"..") != 0)
{
// We found a sub-directory, so get the files in it too
fname = path + "\\" + data.cFileName;
// recurrsion here!
size += TransverseDirectory(fname);
}
}
else
{
LARGE_INTEGER sz;
// All we want here is the file size. Since file sizes can be larger
// than 2 gig, the size is reported as two DWORD objects. Below we
// combine them to make one 64-bit integer.
sz.LowPart = data.nFileSizeLow;
sz.HighPart = data.nFileSizeHigh;
size += sz.QuadPart;
}
}while( FindNextFile(h,&data) != 0);
FindClose(h);
}
return size;
}
int main(int argc, char* argv[])
{
__int64 size = 0;
string path;
size = TransverseDirectory("c:\\dvlp");
cout << "\n\nDirectory Size = " << size << "\n";
cin.ignore();
return 0;
}
For more detail PLease CLick Here
The file system functions are integral part of each operative system, written mostly in C and assembler, not C++, each C++ library implementation for this are in one way or another a wrapper of this functions. Taking on count the effort and if you will not use your implementation in different OS, maybe is a good idea to use this functions directly and save some overhead and time.
Best regards.
I have my types definition file with:
typedef std::wstring String;
typedef std::vector<String> StringVector;
typedef unsigned long long uint64_t;
and code is:
uint64_t CalculateDirSize(const String &path, StringVector *errVect = NULL, uint64_t size = 0)
{
WIN32_FIND_DATA data;
HANDLE sh = NULL;
sh = FindFirstFile((path + L"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE )
{
//if we want, store all happened error
if (errVect != NULL)
errVect ->push_back(path);
return size;
}
do
{
// skip current and parent
if (!IsBrowsePath(data.cFileName))
{
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
// directory, then search it recursievly
size = CalculateDirSize(path + L"\\" + data.cFileName, NULL, size);
else
// otherwise get object size and add it to directory size
size += (uint64_t) (data.nFileSizeHigh * (MAXDWORD ) + data.nFileSizeLow);
}
} while (FindNextFile(sh, &data)); // do
FindClose(sh);
return size;
}
bool IsBrowsePath(const String& path)
{
return (path == _T(".") || path == _T(".."));
}
This uses UNICODE and returns failed dirs if you want that.
To call use:
StringVector vect;
CalculateDirSize(L"C:\\boost_1_52_0", &vect);
CalculateDirSize(L"C:\\boost_1_52_0");
But never pass size
//use FAT32
#undef UNICODE // to flag window deactive unicode
#include<Windows.h> //to use windows api
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#pragma pack(1) //tell compiler do'nt do prag
struct BPB
{
BYTE JMP[3];
BYTE OEM[8];
WORD NumberOfBytesPerSector;
BYTE NumberOfSectorsPerCluster;
WORD NumberOfReservedSectors;
BYTE NumberOfFATs;
WORD NumberOfRootEntries16;
WORD LowNumbferOfSectors;
BYTE MediaDescriptor;
WORD NumberOfSectorsPerFAT16;
WORD NumberOfSectorsPerTrack;
WORD NumberOfHeads;
DWORD NumberOfHiddenSectors;
DWORD HighNumberOfSectors;
DWORD NumberOfSectorsPerFAT32;
WORD Flags;
WORD FATVersionNumber;
DWORD RootDirectoryClusterNumber;
WORD FSInfoSector;
WORD BackupSector;
BYTE Reserver[12];
BYTE BiosDrive;
BYTE WindowsNTFlag;
BYTE Signature;
DWORD VolumeSerial;
BYTE VolumeLabel[11];
BYTE SystemID[8];
BYTE CODE[420];
WORD BPBSignature;
};
//-----------------------------------------------------------
struct DirectoryEntry
{
BYTE Name[11];
BYTE Attributes;
BYTE Reserved;
BYTE CreationTimeTenth;
WORD CreationTime;
WORD CreationDate;
WORD LastAccessTime;
WORD HiClusterNumber;
WORD WriteTime;
WORD WriteDate;
WORD LowClusterNumber;
DWORD FileSize; //acual size of file
};
//---------------------------------------------------
void dirFunction(string s){
string path = "\\\\.\\" + s + ":";
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open partition
BPB bootSector;//var from bootSector structure
DWORD readBytes = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "Error " << GetLastError()<<endl;
return;
}
ReadFile(hFile, (BYTE*)&bootSector, sizeof(bootSector), &readBytes, 0);//read partition and load bootSector information inside our structure
LONG t = 0;
ULONG distance = bootSector.NumberOfReservedSectors +
bootSector.NumberOfFATs*bootSector.NumberOfSectorsPerFAT32;//distance from begine until Root Directory or content of partetion
distance *= bootSector.NumberOfBytesPerSector;//convert distance number to bytes value
SetFilePointer(hFile, distance, &t, FILE_BEGIN);//set pointer to root directory begine or begine of data
int clusterSize = bootSector.NumberOfBytesPerSector*bootSector.NumberOfSectorsPerCluster; //cluster size
int NumberOfEntries = clusterSize / sizeof(DirectoryEntry); //number of record inside cluster
DirectoryEntry* root = new DirectoryEntry[NumberOfEntries];//descripe the partetion
ReadFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
DWORD clusterNumber;
for (int i = 0; i < NumberOfEntries; i++)
{
if (root[i].Name[0] == 0)//there no entery after this
break;
if (root[i].Name[0] == 0xE5)
continue;
if ((root[i].Attributes & 0xF) == 0xF)
continue;
for (int j = 0; j < 8; j++)
cout << root[i].Name[j];
if((root[i].Attributes & 0x10) != 0x10){
cout<<".";
for (int j = 8; j < 11; j++)
cout << root[i].Name[j];
}
if ((root[i].Attributes & 0x10) == 0x10){
cout << "\t<Folder>" ;
}else{
cout<<"\t<File>" ;
}
clusterNumber = root[i].HiClusterNumber << 16;
clusterNumber |= root[i].LowClusterNumber;
cout <<"\t"<<root[i].FileSize<<"bytes" << "\t" << clusterNumber<<"cluster" << endl;
}
CloseHandle(hFile);
}
//---------------------------------------------------------------
string convertLowerToUpper(string f){
string temp = "";
for (int i = 0; i < f.size(); i++){
temp += toupper(f[i]);
}
return temp;
}
//---------------------------------------------------------------
string getFileName(BYTE filename[11]){
string name = "";
for (int i = 0; i < 8; i++){
if (filename[i] != ' ')
name += filename[i];
}
return (name);
}
//------------------------------------------------------------------
int findEntryNumber(DirectoryEntry* root, int NumberOfEntries, string required){
string n;
int j = 0;
for (int i = 0; i < NumberOfEntries; i++){
if (strcmp((getFileName(root[i].Name).c_str()), convertLowerToUpper(required).c_str()) == 0){
return i;
}
}
return -1;
}
//---------------------------------------------------------------
void typeFunction(string fileName, string s){
string path = "\\\\.\\" + s + ":";
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open partition
BPB bootSector;//var from bootSector structure
DWORD readBytes = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "Error " << GetLastError()<<endl;
return;
}
ReadFile(hFile, (BYTE*)&bootSector, sizeof(bootSector), &readBytes, 0);//read partition and load bootSector information inside our structure
LONG t = 0;
ULONG distance = bootSector.NumberOfReservedSectors +
bootSector.NumberOfFATs*bootSector.NumberOfSectorsPerFAT32;//distance from begine until Root Directory or content of partetion
distance *= bootSector.NumberOfBytesPerSector;//convert distance number to bytes value
SetFilePointer(hFile, distance, &t, FILE_BEGIN);//set pointer to root directory begine or begine of data
int clusterSize = bootSector.NumberOfBytesPerSector*bootSector.NumberOfSectorsPerCluster; //cluster size
int NumberOfEntries = clusterSize / sizeof(DirectoryEntry); //number of record inside cluster
DirectoryEntry* root = new DirectoryEntry[NumberOfEntries];//descripe the partetion
ReadFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
DWORD clusterNumber;
int index = findEntryNumber(root, NumberOfEntries, fileName);
if (index == -1){
cout << "File is not found" << endl;
return;
}
if (((root[index].Attributes & 0x10) == 0x10) ){
cout << "Is not file name" << endl;
return;
}
clusterNumber = root[index].HiClusterNumber << 16;
clusterNumber |= root[index].LowClusterNumber;
ULONG temp = (clusterNumber - 2) * clusterSize;
distance += temp;
t = 0;
SetFilePointer(hFile, distance, &t, FILE_BEGIN);
BYTE* buffer = new BYTE[clusterSize];
readBytes = 0;
ReadFile(hFile, (BYTE*)buffer, clusterSize, &readBytes, 0);
for (int i = 0; i < root[index].FileSize; i++){
cout << buffer[i];
}
cout << endl;
CloseHandle(hFile);
}
//----------------------------------------------------------------------
void delFunction(string filename, string s){
string path = "\\\\.\\" + s + ":";
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open partition
BPB bootSector;//var from bootSector structure
DWORD readBytes = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "Error " << GetLastError()<<endl;
return;
}
ReadFile(hFile, (BYTE*)&bootSector, sizeof(bootSector), &readBytes, 0);//read partition and load bootSector information inside our structure
LONG t = 0;
ULONG distance = bootSector.NumberOfReservedSectors +
bootSector.NumberOfFATs*bootSector.NumberOfSectorsPerFAT32;//distance from begine until Root Directory or content of partetion
distance *= bootSector.NumberOfBytesPerSector;//convert distance number to bytes value
SetFilePointer(hFile, distance, &t, FILE_BEGIN);//set pointer to root directory begine or begine of data
int clusterSize = bootSector.NumberOfBytesPerSector*bootSector.NumberOfSectorsPerCluster; //cluster size
int NumberOfEntries = clusterSize / sizeof(DirectoryEntry); //number of record inside cluster
DirectoryEntry* root = new DirectoryEntry[NumberOfEntries];//descripe the partetion
ReadFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
DWORD clusterNumber;
readBytes = 0;
t = 0;
int index = findEntryNumber(root, NumberOfEntries, filename);
if (index == -1){
cout << "FIle is not found" << endl;
return;
}
if ((root[index].Attributes & 0x10) == 0x10){
cout << "Is not file name" << endl;
return;
}
//delete file
root[index].Name[0] = 0xE5;
SetFilePointer(hFile, distance, &t, FILE_BEGIN);
WriteFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
cout<<filename<<" is deleted\n";
CloseHandle(hFile);
}
//----------------------------------------------------------------------
string removeExtention(string s){
string t = "";
for (int i = 0; i < s.size(); i++){
if (s[i] == '.')break;
t += s[i];
}
return t;
}
//-------------------------------------------------------------------
void main()
{
string swich_value;
string directory;
string file_name;
//dirFunction("G");
cout<<"plz, Enter single Partition character ------> example E or G\n\n";
cin>>directory;
string path = "\\\\.\\" + directory + ":";
cout<<"current directory is "<<path<<endl;
cout<<"Enter Options: \n1- dir \n2- type file_name.extention \n3- del file_name.extention\n\n";
again:
cin>>swich_value;
if(swich_value.at(1)!='i')
cin>>file_name;
string answer;
switch(swich_value.at(1)){
case 'i':
dirFunction(directory);
cout<<"\nare you want to do another process: y or n?";
cin>>answer;
if (answer.at(0)=='y')
goto again;
break;
case 'y':
typeFunction(removeExtention(file_name), directory);
cout<<"\nare you want to do another process: y or n?";
cin>>answer;
if (answer.at(0)=='y')
goto again;
break;
case 'e':
delFunction(removeExtention(file_name), directory);
cout<<"\nare you want to do another process: y or n?";
cin>>answer;
if (answer.at(0)=='y')
goto again;
break;
}
}
You can use "boost::filesystem"
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
unsigned long long int get_directory_size(const fs::path& directory){
if (!fs::exists(directory)) return 0;
if (fs::is_directory(directory)){
unsigned long long int ret_size = 0;
fs::directory_iterator m_dir_itr(directory);
for (m_dir_itr = fs::begin(m_dir_itr); m_dir_itr != fs::end(m_dir_itr); ++m_dir_itr){
fs::directory_entry m_dir_entry = *m_dir_itr;
if (fs::is_regular_file(m_dir_entry.path())){
ret_size += fs::file_size(m_dir_entry.path());
}else if (fs::is_directory(m_dir_entry.path())){
ret_size += get_directory_size(m_dir_entry.path());
}
}
return ret_size;
} else if (fs::is_regular_file(directory)){
return fs::file_size(directory);
}
return 0;
}
#include <stdio.h>
int main(int /*argc*/, char** /*argv*/) {
// Assuming 'C:/Folder' be any directory then its size can be found using
auto folder_size = get_directory_size("C:/Folder");
printf("Size of 'C:/Folder' is %d\n",folder_size);
return 0;
}
With the introduction of std::filesystem, you no more have to use any system APIs or any external libraries.
#include <filesystem>
namespace n_fs = ::std::filesystem;
double archive::getFolderSize(std::string path)
{
double r = 0.0;
try{
if (!n_fs::is_directory(path))
{
r += (double)n_fs::file_size(path);
}
else
{
for(auto entry: n_fs::directory_iterator(path))
getFolderSize(entry.path().string());
}
}
catch(exception& e)
{
std::cout << e.what() << std::endl();
}
return r;
}
int main(){
double folderSize = getFolderSize("~/dev/"); //Replace with your path
std::cout << "Size of Folder: " << folderSize;
}
Try using GetFileSizeEx function. Following is some sample code for this. You need to get the size from the LARGE_INTEGER union though.
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <io.h>
using namespace std;
int main()
{
FILE *fp;
fp = fopen("C:\test.txt","r");
int fileNo = _fileno(fp);
HANDLE cLibHandle = (HANDLE)_get_osfhandle(fileNo);
long int fileSize = 0;
LARGE_INTEGER fileSizeL;
GetFileSizeEx(cLibHandle, &fileSizeL);
return 0;
}
5 years and not a simple solution with standard C++, that's why I would like to contribute my solution to this question:
uint64_t GetDirSize(const std::string &path)
{
uint64_t size = 0;
for (const auto & entry : std::experimental::filesystem::directory_iterator(path))
{
if(entry.status().type() == std::experimental::filesystem::file_type::regular)
size += std::experimental::filesystem::file_size(entry.path());
if (entry.status().type() == std::experimental::filesystem::file_type::directory)
size += GetDirSize(entry.path().generic_string());
}
return size;
}
Use it for example by calling
GetDirSize("C:\\dir_name")
if you're using Windows.
Calculating a folder size in bytes on Windows.
size_t GetFolderSizeInBytes(std::wstring path)
{
size_t result = 0;
WIN32_FIND_DATA findData;
HANDLE hFileHandle;
std::wstring sourcePath(path);
if (GetFileAttributes(sourcePath.c_str()) & FILE_ATTRIBUTE_DIRECTORY)
sourcePath.push_back(L'\\');
std::wstring fileName(sourcePath);
fileName.append(L"*");
hFileHandle = FindFirstFileEx(
fileName.data(),
FindExInfoStandard,
&findData,
FindExSearchNameMatch,
NULL,
FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY);
if (hFileHandle != INVALID_HANDLE_VALUE)
{
do
{
if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName, L".."))
continue;
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
// Folder
std::wstring newPath = path + L"\\" + findData.cFileName;
result += GetFolderSizeInBytes(newPath);
}
else
{
// File
unsigned long high = findData.nFileSizeHigh;
unsigned long low = findData.nFileSizeLow;
size_t size = size_t(high * (MAXWORD + 1)) + low;
result += size;
}
} while (FindNextFile(hFileHandle, &findData));
FindClose(hFileHandle);
}
return result;
}