Please take a look at the following method:
int BCVirtualCard::decrypt(std::string from, std::string *to, int keyId, bool padding)
{
if (to == nullptr)
{
NSCAssert(NO, #"Invalid params");
return 0;
}
NSString* privateKey = [m_storage privateKeyForSlot:keyId];
NSArray<NSString*>* components = [privateKey componentsSeparatedByString:#"_"];
const NSInteger componentsCount = 4;
if (components.count != componentsCount)
{
*to = "";
return 0;
}
const char* d = [components[0] UTF8String];
const char* n = [components[1] UTF8String];
const char* p = [components[2] UTF8String];
const char* q = [components[3] UTF8String];
RSA* rsa = RSA_new();
BN_hex2bn(&rsa->d, d);
BN_hex2bn(&rsa->n, n);
BN_hex2bn(&rsa->p, p);
BN_hex2bn(&rsa->q, q);
unsigned char* _to = (unsigned char *)calloc(1, sizeof(unsigned char));
int decryptedSize = RSA_private_decrypt((int)from.length(), (unsigned char *)from.c_str(), _to, rsa, RSA_NO_PADDING);
free(_to);
if (decryptedSize <= 0)
{
ERR_print_errors_cb(test, NULL);
*to = "";
return 0;
}
_to = (unsigned char *)calloc(decryptedSize, sizeof(unsigned char));
RSA_private_decrypt((int)from.length(), (unsigned char *)from.c_str(), _to, rsa, RSA_NO_PADDING);
*to = std::string((char *)_to, strlen((char *)_to));
free(_to);
RSA_free(rsa);
return 1;
}
Here the string from is supposed to be decrypted and written to the string to. For decryption I use RSA_private_decrypt function. I call it two times. First time in order to determine the size of the decrypted text and second time in order to write the decrypted text into _to buffer. And when I call it second time it usually crashes like this:
malloc: Heap corruption detected, free list is damaged at 0x280ff3d70
*** Incorrect guard value: 0
No1BCmail(2171,0x170efb000) malloc: *** set a breakpoint in malloc_error_break to debug
The breakpoint is on and this let me find the place of the crash. However I can't understand the reason why it crashes. I tried recreating the RSA structure and playing with the size allocated for _to for the second time, but nothing helps. Can you see what is wrong here? Thanks
RSA_private_decrypt requires that the to parameter points to a buffer of an adequate size. Your first call only uses a buffer of size 1, which is too small and is undefined behavior. What you need to do is get the size from rsa using RSA_size(rsa), and then you can use that to allocate space for _to. That means you don't need to call the function twice, since you'll already have the size the first time around
You should also be using decryptedSize for the length if the string to build instead of using strlen as _to may not be null terminated.
Putting all that together you could should look something like
int BCVirtualCard::decrypt(std::string from, std::string *to, int keyId, bool padding)
{
if (to == nullptr)
{
NSCAssert(NO, #"Invalid params");
return 0;
}
NSString* privateKey = [m_storage privateKeyForSlot:keyId];
NSArray<NSString*>* components = [privateKey componentsSeparatedByString:#"_"];
const NSInteger componentsCount = 4;
if (components.count != componentsCount)
{
*to = "";
return 0;
}
const char* d = [components[0] UTF8String];
const char* n = [components[1] UTF8String];
const char* p = [components[2] UTF8String];
const char* q = [components[3] UTF8String];
RSA* rsa = RSA_new();
BN_hex2bn(&rsa->d, d);
BN_hex2bn(&rsa->n, n);
BN_hex2bn(&rsa->p, p);
BN_hex2bn(&rsa->q, q);
auto _to = std::make_unique<unsigned char[]>(RSA_size(rsa)); // use smart pointers so you don't have to worry about releasing the memory
int decryptedSize = RSA_private_decrypt((int)from.length(), (unsigned char *)from.c_str(), _to.get(), rsa, RSA_NO_PADDING);
if (decryptedSize <= 0)
{
ERR_print_errors_cb(test, NULL);
*to = "";
return 0;
}
*to = std::string((char *)_to.get(), decryptedSize);
return 1;
}
Related
I wrote the following code that should return a signature of the provided std::string signed using an EC private key.
std::string msg = "test";
size_t messageLength = msg.length();
size_t encMessageLength;
unsigned char* encMessage;
signMessage(msg, evp_private_key, messageLength, &encMessageLength, &encMessage);
bool signMessage(std::string msg, EVP_PKEY *&key, size_t messageLength, size_t *encMessageLength, unsigned char** encMessage) {
unsigned char * u_msg = (unsigned char*) msg.c_str();
EVP_MD_CTX* signCtx = EVP_MD_CTX_new();
if (EVP_DigestSignInit(signCtx,NULL, EVP_sha256(), NULL, key) <= 0) {
return NULL;
}
if (EVP_DigestSignUpdate(signCtx, u_msg, messageLength) <= 0) {
return NULL;
}
if (EVP_DigestSignFinal(signCtx, NULL, encMessageLength) <= 0) {
return NULL;
}
*encMessage = (unsigned char*)malloc(*encMessageLength);
if (EVP_DigestSignFinal(signCtx, *encMessage, encMessageLength) <= 0) {
return NULL;
}
EVP_MD_CTX_free(signCtx);
return true;
}
*encMessage is freed after the function call.
The length of encMessage varies greatly between 3 and 139.
An example output casted and printed as char* as well as hex looks like this:
�D�b���w�x�VS:������dƀ7�#����v�B%M�X2�ky���!�h�};J>�!���h�ħ�n����/�j�U���aL����z�X���>�2�>
Length: 138
hex: 30818702414fa9b7d8cac465525add0451784bc751544702edd0e24bdb0dca44f362fc80a11b3777e78316788e56533a91c0a1eb058bf1a564c68037900640cc13b9aca776c4024201254dd55832a16b799ad2f021f468a07d3b4a3e801321bba284688fc4a7c0156e86da1e84952f8c6ab755da1dd3ec614cec10bea1bc7aac58affa9c3efb32990f3e
Another function call:
msg: 0��B
Length: 5
hex: 3081880242
What am I doing wrong?
I am trying to make a program that reads a string from a file in SPIFFS with 4 tab-separated things and then processes it into four char arrays to be used in another function. However, I get the error cannot convert 'char*' to 'char**' in assignment. Is there any idea why? Here's my code:
#include <string.h>
#include "FS.h"
#include "AdafruitIO_WiFi.h"
char *ssid;
char *pass;
char *aiduser;
char *aidkey;
// comment out the following two lines if you are using fona or ethernet
#include "AdafruitIO_WiFi.h"
//AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
void setupWifi(char* *aiduser, char* *aidkey, char* *ssid, char* *pass){
#define WIFIFILE "/config.txt"
int addr = 0;
bool spiffsActive = false;
if (SPIFFS.begin()) {
spiffsActive = true;
}
File f = SPIFFS.open(WIFIFILE, "r");
String str;
while (f.position()<f.size())
{
str=f.readStringUntil('\n');
str.trim();
}
// Length (with one extra character for the null terminator)
int str_len = str.length() + 1;
// Prepare the character array (the buffer)
char char_array[str_len];
// Copy it over
str.toCharArray(char_array, str_len);
const char s[2] = {9, 0};
/* get the first token */
aiduser = strtok(char_array, s);
aidpass = strtok(NULL, s);
ssid = strtok(NULL, s);
pass = strtok(NULL, s);
/* walk through other tokens
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
}*/
// RESULT: A thingy
}
void setup(){
setupWifi(&aiduser, &aidkey, &ssid, &pass);
AdafruitIO_WiFi io(aiduser, aidkey, ssid, pass);}
Also, I can't run the setupWifi function unless it is in setup or loop, but I can't make it in another setup because this is #included into another main file.
You get this error because of this:
void setupWifi(char* *aiduser, char* *aidkey, char* *ssid, char* *pass)
{
...
aiduser = strtok(char_array, s);
aidpass = strtok(NULL, s);
ssid = strtok(NULL, s);
pass = strtok(NULL, s);
}
This variables are double pointers, strtok returns a pointer to char, those
are not compatible types.
Because strtok returns char_array + some_offset and char_array is a local
variable in setupWifi, you need to do a copy for each of them and return the
copy instead. You can do it with strdup.
*aiduser = strdup(strtok(char_array, s));
*aidpass = strdup(strtok(NULL, s));
*ssid = strdup(strtok(NULL, s));
*pass = strdup(strtok(NULL, s));
I encourage you to always check the return value of strdup, because it can
return NULL.1
If your system does not have strdup, then you can write your own:
char *strdup(const char *text)
{
if(text == NULL)
return NULL;
char *copy = calloc(strlen(text) + 1, 1);
if(copy == NULL)
return NULL;
return strcpy(copy, text);
}
One last thing:
void setupWifi(char* *aiduser, char* *aidkey, char* *ssid, char* *pass);
It looks really awkward, never seen declaring double pointer this way. Much
easier to read would be
void setupWifi(char **aiduser, char **aidkey, char **ssid, char **pass);
Fotenotes
1While the syntax is correct, I still consider this bad practice,
because you should always check the return values of functions that return
pointers. If they return NULL, you cannot access the memory. This adds a
little bit of more code, but your program will not die of segfaults and it can
recover from the errors.
I'd also change your function to return 1 on success, 0 otherwise:
int parse_and_set(char *txt, const char *delim, char **var)
{
if(delim == NULL || var == NULL)
return 0;
char *token = strtok(txt, delim);
if(token == NULL)
return 0;
token = strdup(token);
if(token == NULL)
return NULL;
*var = token;
return 1;
}
void init_parse(char ***vars, size_t len)
{
for(size_t i = 0; i < len; ++i)
**(vars + i) = NULL;
}
int cleanup_parse(char ***vars, size_t len, int retval)
{
for(size_t i = 0; i < len; ++i)
{
free(**(vars + i));
**(vars + i) = NULL;
}
}
int setupWifi(char **aiduser, char **aidkey, char **ssid, char **pass)
{
if(aiduser == NULL || aidkey == NULL || ssid == NULL || pass == NULL)
return 0;
...
/* get the token token */
char **vars[] = { aiduser, aidkey, ssid, pass };
size_t len = sizeof vars / sizeof *vars;
init_parse(vars, len);
if(parse_and_set(char_array, s, aiduser) == 0)
return cleanup_parse(vars, len, 0);
if(parse_and_set(NULL, s, aidpass) == 0)
return cleanup_parse(vars, len, 0);
if(parse_and_set(NULL, s, ssid) == 0)
return cleanup_parse(vars, len, 0);
if(parse_and_set(NULL, s, pass) == 0)
return cleanup_parse(vars, len, 0);
...
return 1;
}
I was making a re-creation of some System.IO functions from that class.
When I setup a buffer and allocate n number of bytes it'll read bytes to that and then add random bytes to the end of that buffer.
For example:
My Main:
int main(int argc, char *args[])
{
SetConsoleTitle(TEXT("Stream Test."));
cout<<"Press any Key to begin reading.";
cin.get();
const char* data = File::ReadAllBytes(args[1]);
Stream* stream = new Stream(data);
char* magic = new char[8];
stream->Read(magic, 0, 8);
magic[8] = '\0';
cout<<magic<<endl<<endl;
delete[]data;
cout<<"Press any key to quit.";
cin.get();
return 0;
}
and here is my System::IO namespace + stream class:
namespace System
{
namespace IO
{
class File
{
public:
static char* ReadAllBytes(const char *name)
{
ifstream fl(name, ifstream::in|ifstream::binary);
fl.seekg( 0, ifstream::end );
size_t len = fl.tellg();
char* ret = new char[len+1];
ret[len] = '\0';
fl.seekg(0);
fl.read(ret, len);
fl.close();
return ret;
}
//not sure of this use yet.
static size_t fileSize(const char* filename)
{
ifstream in(filename, ifstream::in | ifstream::binary);
in.seekg(0, ifstream::end);
return in.tellg();
}
};
class Stream
{
public:
const char *_buffer;
__int64 _origin;
__int64 _position;
__int64 _length;
__int64 _capacity;
bool _expandable;
bool _writable;
bool _exposable;
bool _isOpen;
static const int MemStreamMaxLength = 2147483647;
Stream()
{
InitializeInstanceFields();
}
Stream(const char *buffer)
{
_buffer = buffer;
_length = strlen(_buffer);
_capacity = _length;
_position = 0;
_origin = 0;
_expandable = false;
_writable = true;
_exposable = true;
_isOpen = true;
}
int ReadByte()
{
if (_position >= _length)
return -1;
return _buffer[_position++];
}
void Read(char* &buffer, int offset, int length)
{
if((_position + offset + length) <= _length)
{
memcpy( buffer, _buffer + (_position + offset), length );
_position += length;
}
}
private:
void InitializeInstanceFields()
{
_origin = 0;
_position = 0;
_length = 0;
_capacity = 0;
_expandable = false;
_writable = false;
_exposable = false;
_isOpen = false;
}
};
}
}
This is what ends up happening:
Can anyone explain why this happens, how I can fix, or anything else? I'm new to C++ so any explanations would help. Also please don't criticize my scripting, I know it may be bad, outdated, deprecated, etc. but I'm open to learning and any helping advice goes for the better. :)
You can only use operator << (char *) on C-style strings, not arbitrary arrays of characters. How would you expect it to know how many characters to output?
I would guess the file was not opened correctly and thus the magic buffer is not set at all which leaves it with initialized junk data:
If the constructor is not successful in opening the file, the object
is still created although no file is associated to the stream buffer
and the stream's failbit is set (which can be checked with inherited
member fail).
http://www.cplusplus.com/reference/fstream/ifstream/ifstream/
Try adding more error checking along the way (using cout), especially when opening and reading the buffer. Perhaps set the magic buffer to zero or something recognizable that is overwritten when successful.
I have tried both strcat and strcat_s, but they both crash. Does anyone know why this happens? I can't find the problem.
Crash: "Unhandled exception at 0x58636D2A (msvcr110d.dll)"
_Dst 0x00ea6b30 "C:\\Users\\Ruben\\Documents\\School\\" char *
_SizeInBytes 260 unsigned int
_Src 0x0032ef64 "CKV" const char *
available 228 unsigned int
p 0x00ea6b50 "" char *
Code:
#include <Windows.h>
#include <strsafe.h>
extern "C"
{
char* GetFilesInFolders(LPCWSTR filedir, char* path)
{
char* files = "";
char DefChar = ' ';
char* Streepje = "-";
bool LastPoint = false;
WIN32_FIND_DATA ffd;
TCHAR szDir[MAX_PATH];
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
StringCchCopy(szDir, MAX_PATH, filedir);
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
return "";
do
{
DWORD attributes = ffd.dwFileAttributes;
LPCWSTR nm = ffd.cFileName;
char name[260];
WideCharToMultiByte(CP_ACP,0,ffd.cFileName,-1, name,260,&DefChar, NULL);
for (int i = 0; i <= 260; i++)
{
if (name[i] == '.')
LastPoint = true;
else if (name[i] == ' ')
break;
}
if (LastPoint == true)
{
LastPoint = false;
continue;
}
if (attributes & FILE_ATTRIBUTE_HIDDEN)
{
continue;
}
else if (attributes & FILE_ATTRIBUTE_DIRECTORY)
{
char* newfiledir = "";
char* newpath = path;
char* add = "\\";
char* extra = "*";
strcat_s(newpath, sizeof(name), name);
strcat_s(newpath, sizeof(add), add);
puts(newpath);
strcpy_s(newfiledir, sizeof(newpath) + 1, newpath);
strcat_s(newfiledir, sizeof(extra) + 1, extra);
puts(newfiledir);
size_t origsize = strlen(newfiledir) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, newfiledir, _TRUNCATE);
LPCWSTR dir = wcstring;
GetFilesInFolders(dir, newpath);
}
else
{
char* file = path;
strcat_s(file, sizeof(name), name);
puts(file);
strcat_s(files, sizeof(file), file);
strcat_s(files, sizeof(Streepje), Streepje);
puts(files);
}
}
while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
return files;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char* path = "C:\\Users\\Ruben\\Documents\\School\\";
char* filedir = "C:\\Users\\Ruben\\Documents\\School\\*";
size_t origsize = strlen(filedir) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, filedir, _TRUNCATE);
LPCWSTR dir = wcstring;
char* files = GetFilesInFolders(dir, path);
return 0;
}
Extra info: I don't want to use boost or strings and I want to keep this in unicode (default).
You assign a const char* to files, then attempt to append to it.
char* files = "";
// ...
strcat_s(files, sizeof(file), file);
You cannot modify a constant string literal.
I would recommend that you turn on compiler warnings and make sure to look at them. This would warn you about assigning a const char* to a char*. To fix it, you might have changed files to be const, which would then cause your strcpy_s to no longer compile.
It looks like you don't understand how variables are stored in memory or how pointers work. In your _tmain() you have char * path pointing to a constant string literal, which you pass into GetFilesInFolders(), where it gets modified. Compilers tend to allow char *s to point at constant strings for backward compatibility with old C programs. You cannot modify these. You cannot append to them. The compiler (generally) puts these in a read-only segment. That's one reason why you're getting an exception.
Your whole GetFilesInFolders() is wrong. And as DarkFalcon pointed out, you haven't allocated any space anywhere for files, you have it pointing to a constant string literal.
Get "The C++ Programming Language" and read chapter 5.
Here is my code:
int function(const char * buffer,size_t len,unsigned char * value)
{
char* user = "username";
char*password = "password";
size_t text_len = strlen(user) + strlen(password) + 2;
unsigned char* key = (unsigned char*)calloc(1,16);
unsigned char* text= (unsigned char *)calloc(1,text_len);
snprintf((char*)text, text_len, "%s:%s",user,password );
MD5(text, text_len-1, key)
HMAC_CTX *ctx = NULL;
unsigned int md_len = 20;
ctx = (HMAC_CTX*) calloc(1,sizeof(HMAC_CTX));
if(ctx == NULL){return -1;}
HMAC_CTX_init(ctx);
`HMAC_Init(ctx, key, 16, EVP_sha1());` //crashing everytime, saying heap corruption
HMAC_Update(ctx, buffer, len);
HMAC_Final(ctx, value, &md_len);
HMAC_CTX_cleanup(ctx);
return 0;
}
I am using openssl 0.9.8.c. If anyone faced this problem please let me know.
According to the man page HMAC_Init is deprecated. Might be worth trying HMAC_Init_ex.