string <-> byte[] conversions - c++

I'm implementing a system that uses libcrafter and crypto++ to transmit specific frames on the network. But the problem I'm stuck with isn't at this level at all.
It's about conversion between types used in these libraries.
1) At the emission (solved)
I'm trying to convert the Crafter::byte array to a std::string, in order to put this message into a network frame (as an initialization vector for an AES encryption/decryption).
Moreover, the iv must be zeroed, and I can't initialize it properly (despite the answers here or there).
EDIT : to initialize it to 00, I had to do it in hexadecimal : 0x30. And to convert it to a std::string I had to provide the length ie ivLen2 (thanks for the answers).
Here's what I do :
const int ivLen2 = 2;
std::string encrypted_message("whatever");
Crafter::byte iv[ivLen2]={0x30, 0x30}; // crypto salt of 2 bytes at 0.
std::string ivStr( reinterpret_cast< char const* >(iv), ivLen2 ) ;
string mess2send = ivStr + encrypted_message;
And if I display them, with this :
cout<<"iv[0] : "<<iv[0]<<endl; // display 0
cout<<"mess2send : "<<mess2send<<endl; // display 00whatever
Why don't I simply create a zeroed string and send it ? In order to have generic functions, and a re-usable code.
2) At the reception (pending)
Without surprises I have to do the opposite. I get a iv and the message concatenated within a vector<byte>* payload, and I have to extract the iv as a byte array, and the message within a string.
The message isn't actually the problem, given that std::string is close to vector.
Here's what I tempt to retrieve the iv :
Crafter::byte iv[ ivLen2 ];
for (int i = 0; i < ivLen2; i++)
{
iv[i] = (byte)payload->at(i);
}
std::string iv_rcv( reinterpret_cast< char const* >(iv) ) ;
And to display them, I do (in the same loop) :
cout<<iv[i];
But it gives me a non-ASCII character.
I've also tried this (following this and this answers) :
Crafter::byte* iv;
std::string iv_rcv( payload->begin(), payload->begin()+ivLen2 ) ;
iv = (byte*)iv_rcv.c_str();
But it doesn't give me the supposed initialized values...
Does anybody have a clue ? Is my code wrong ?

I don't think this will work:
const int ivLen2 = 2;
std::string encrypted_message("whatever");
Crafter::byte iv[ivLen2]={0x00, 0x00}; // crypto salt of 2 bytes
std::string ivStr( reinterpret_cast< char const* >(iv) ) ;
How does the std::string know how much data to copy from the iv pointer?
You have to use a constructor that takes the length of the data like:
std::string ivStr( reinterpret_cast< char const* >(iv), ivLen2 ) ;
The pointer only constructor is for specifically encoded strings that are terminated by a null character. Unless you are using one of those you must pass the length.
Try this:
const int ivLen2 = 2;
std::string encrypted_message("whatever");
Crafter::byte iv[ivLen2]={0x00, 0x00}; // crypto salt of 2 bytes
std::string ivStr( reinterpret_cast< char const* >(iv), ivLen2 ) ;
std::string mess2send = ivStr + encrypted_message;
std::cout << (int)mess2send[0] << (int)mess2send[1] << mess2send.substr(2) << '\n';

Related

Convert from vector<unsigned char> to char* includes garbage data

I'm trying to base64 decode a string, then convert that value to a char array for later use. The decode works fine, but then I get garbage data when converting.
Here's the code I have so far:
std::string encodedData = "VGVzdFN0cmluZw=="; //"TestString"
std::vector<BYTE> decodedData = base64_decode(encodedData);
char* decodedChar;
decodedChar = new char[decodedData.size() +1]; // +1 for the final 0
decodedChar[decodedData.size() + 1] = 0; // terminate the string
for (size_t i = 0; i < decodedData.size(); ++i) {
decodedChar[i] = decodedData[i];
}
vector<BYTE> is a typedef of unsigned char BYTE, as taken from this SO answer. The base64 code is also from this answer (the most upvoted answer, not the accepted answer).
When I run this code, I get the following value in the VisualStudio Text Visualiser:
TestStringÍ
I've also tried other conversion methods, such as:
char* decodedChar = reinterpret_cast< char *>(&decodedData[0]);
Which gives the following:
TestStringÍÍÍýýýýÝÝÝÝÝÝÝ*b4d“
Why am I getting the garbage data at the end of the string? What am i doing wrong?
EDIT: clarified which answer in the linked question I'm using
char* decodedChar;
decodedChar = new char[decodedData.size() +1]; // +1 for the final 0
Why would you manually allocate a buffer and then copy to it when you have std::string available that does this for you?
Just do:
std::string encodedData = "VGVzdFN0cmluZw=="; //"TestString"
std::vector<BYTE> decodedData = base64_decode(encodedData);
std::string decodedString { decodedData.begin(), decodedData.end() };
std::cout << decodedString << '\n';
If you need a char * out of this, just use .c_str()
const char* cstr = decodedString.c_str();
If you need to pass this on to a function that takes char* as input, for example:
void someFunc(char* data);
//...
//call site
someFunc( &decodedString[0] );
We have a TON of functions and abstractions and containers in C++ that were made to improve upon the C language, and so that programmers wouldn't have to write things by hand and make same mistakes every time they code. It would be best if we use those functionalities wherever we can to avoid raw loops or to do simple modifications like this.
You are writing beyond the last element of your allocated array, which can cause literally anything to happen (according to the C++ standard). You need decodedChar[decodedData.size()] = 0;

Subsetting char array without copying it in C++

I have a long array of char (coming from a raster file via GDAL), all composed of 0 and 1. To compact the data, I want to convert it to an array of bits (thus dividing the size by 8), 4 bytes at a time, writing the result to a different file. This is what I have come up with by now:
uint32_t bytes2bits(char b[33]) {
b[32] = 0;
return strtoul(b,0,2);
}
const char data[36] = "00000000000000000000000010000000101"; // 101 is to be ignored
char word[33];
strncpy(word,data,32);
uint32_t byte = bytes2bits(word);
printf("Data: %d\n",byte); // 128
The code is working, and the result is going to be written in a separate file. What I'd like to know is: can I do that without copying the characters to a new array?
EDIT: I'm using a const variable here just to make a minimal, reproducible example. In my program it's a char *, which is continually changing value inside a loop.
Yes, you can, as long as you can modify the source string (in your example code you can't because it is a constant, but I assume in reality you have the string in writable memory):
uint32_t bytes2bits(const char* b) {
return strtoul(b,0,2);
}
void compress (char* data) {
// You would need to make sure that the `data` argument always has
// at least 33 characters in length (the null terminator at the end
// of the original string counts)
char temp = data[32];
data[32] = 0;
uint32_t byte = bytes2bits(data);
data[32] = temp;
printf("Data: %d\n",byte); // 128
}
In this example by using char* as a buffer to store that long data there is not necessary to copy all parts into a temporary buffer to convert it to a long.
Just use a variable to step through the buffer by each 32 byte length period, but after the 32th byte there needs the 0 termination byte.
So your code would look like:
uint32_t bytes2bits(const char* b) {
return strtoul(b,0,2);
}
void compress (char* data) {
int dataLen = strlen(data);
int periodLen = 32;
char* periodStr;
char tmp;
int periodPos = periodLen+1;
uint32_t byte;
periodStr = data[0];
while(periodPos < dataLen)
{
tmp = data[periodPos];
data[periodPos] = 0;
byte = bytes2bits(periodStr);
printf("Data: %d\n",byte); // 128
data[periodPos] = tmp;
periodStr = data[periodPos];
periodPos += periodLen;
}
if(periodPos - periodLen <= dataLen)
{
byte = bytes2bits(periodStr);
printf("Data: %d\n",byte); // 128
}
}
Please than be careful to the last period, which could be smaller than 32 bytes.
const char data[36]
You are in violation of your contract with the compiler if you declare something as const and then modify it.
Generally speaking, the compiler won't let you modify it...so to even try to do so with a const declaration you'd have to cast it (but don't)
char *sneaky_ptr = (char*)data;
sneaky_ptr[0] = 'U'; /* the U is for "undefined behavior" */
See: Can we change the value of an object defined with const through pointers?
So if you wanted to do this, you'd have to be sure the data was legitimately non-const.
The right way to do this in modern C++ is by using std::string to hold your string and std::string_view to process parts of that string without copying it.
You can using string_view with that char array you have though. It's common to use it to modernize the classical null-terminated string const char*.

How to Convert Data structure to convert char* in c++

I'm think pointer is 4Byte or(2Byte) heap memory allocated
I need Structure data convert to char* Just need 12byte convert
this is my code
please Contact me.
thank you
struct MyData {
unsigned int myNumber;
float x;
float y;
};
int main(){
Mydata* mydata = new Mydata();
mydata->userNumber = 188242268;
mydata->x = 100.0f;
mydata->y = 102.0f;
char* sender = (char*)&mydata;
sioclient->send(sender);
// SocketIO Server Send
}
I don't think what you are asking is possible. string doesn't like having null characters in itself, which would be necessary to directly send the data (For example, a int(1) would have 1 NULL (0x0) character (modern systems would have 3 NULL characters) and 1 0x1 character, which string wouldn't like the null and terminate the string there).
I think you should find another networking library for what you are doing if you can't use WebSocket and need to have the efficiency of sending the bytes of a struct. (Boost::asio perhaps?)
But if you HAVE to use Cocos2d-x SIOClient without the WebSocket, then in the sending side, create a string with the values separated by commas:
string sendMe = to_string(mydata->userNumber) + "," + to_string(mydata->x) + "," + to_string(mydata->y);
And then on the receiving side:
Mydata receiver;
string recStr;//Received string
string temp;
int stage = 0;
for (int itr = 0; itr < temp.length(); itr++)
{
if (recStr[itr] == ',')
{
if (stage==0)
receiver.myNumber = stoi(temp);
else if (stage==1)
receiver.x = stof(temp);
stage++;
temp = "";
}
else
temp += recStr[itr];
}
receiver.y = stof(temp);
Hope that helps.
The old answer, in case you want to switch and have a solution:
Ok, try using the overloaded function
void send (const unsigned char * binaryMsg, unsigned int len);
instead. read about it here
This should look something like the following:
sioclient->send(reinterpret_cast<unsigned char*>(mydata), sizeof(MyData));
Tell me if you are using a different version of Cocos2d-x and thus this doesn't work, or if it failed to solve the problem. When I tried this, it compiled nicely and seemed to behave correctly.
If your compiler doesn't like unsigned char* for a const unsigned char* parameter, just add a const_cast.
Also, remember to delete (mydata); when you are done with it.

Salsa20 using Crypto++

I am trying to use the salsa20 code in the crypto++ Library. ( http://www.cryptopp.com/) to communicate between two programs.
Both programs use the same code which follows
std::string salsaDo(std::string key, std::string msg, byte iv[STREAM_IV_LENGTH]) {
//Set up byte arrays for proccess
byte *plaintextBytes = (byte *)msg.c_str();
byte *ciphertextBytes = new byte[msg.length()];
byte *reversetextBytes = new byte[msg.length()];
//Set up key array
byte* keyBytes = (byte *)key.substr(0, STREAM_KEY_LENGTH).c_str();
//Peform encryption method
Salsa20::Encryption salsa;
salsa.SetKeyWithIV(keyBytes, STREAM_KEY_LENGTH, iv);
salsa.ProcessData(ciphertextBytes, plaintextBytes, msg.length());
salsa.SetKeyWithIV(keyBytes, STREAM_KEY_LENGTH, iv);
salsa.ProcessData(reversetextBytes, ciphertextBytes, msg.length());
std::string ivStr((char*)iv, STREAM_IV_LENGTH);
std::cout << "____\nK:" << key.c_str();
std::cout << "\nI:" << ivStr.c_str();
std::cout << "\nM:" << msg.c_str();
std::cout << "\nE:" << std::string((const char *)ciphertextBytes, msg.length()).c_str();
std::cout << "\nR:" << std::string((const char *)reversetextBytes, msg.length()).c_str();
std::cout << "\n____\n";
//return msg;
//return string
return std::string((const char *)ciphertextBytes, msg.length());
}
An image from the programs is at http://s21.postimg.org/wgfmkjcn9/encrypt.png
Explanation:
Step1 : plain text is encrypted (server-M to server-E)
Step2 : encrypted text is decrypted (Server-E to server-R and client-M to client-E.) These two should give the same result but don't
Step3 : client-E is run through again to check that it equals the msg the server sent.
There are a few problems with this code.
This line technically invokes Undefined Behavior:
byte* keyBytes = (byte *)key.substr(0, STREAM_KEY_LENGTH).c_str();
In this case, the substr() call returns a temporary std::string object containing the substring. The lifetime of this temporary std::string extends through the evaluation of the entire line (the full expression). The lifetime of the C string returned by std::string::c_str() is the same as the std::string, except that it is invalidated by a mutating operation. Thus, in this full expression, keyBytes is likely an invalid pointer once the line has executed.
You can fix the problem by overwriting key to the desired substring. In this case, assigning to key ensures that the lifetime is extended through where it is used:
key = key.substr(0, STREAM_KEY_LENGTH);
const byte* keyBytes = static_cast<const byte*>(key.c_str());
This salsaDo() function leaks memory. The byte arrays created by:
byte *ciphertextBytes = new byte[msg.length()];
byte *reversetextBytes = new byte[msg.length()];
.. are not freed. Consider using a std::unique_ptr<byte[]>:
std::unique_ptr<byte[]> ciphertextBytes(new byte[msg.length()]);
std::unique_ptr<byte[]> reversetextBytes(new byte[msg.length()]);
C++ does not technically support passing arrays to functions. The parameter byte iv[STREAM_IV_LENGTH] is actually treated as if you had written byte* iv instead.
You could pass a reference to the array. Also, for const-correctness, you should mark the initialization vector bytes const:
std::string salsaDo(std::string key, std::string msg, const byte (&iv)[STREAM_IV_LENGTH])
{
//...
}
I wouldn't use a std::string to store the key, or really any array of bytes such as the returned encrypted bytes. Consider using a std::unique_ptr<byte[]> or std::shared_ptr<byte[]>, or passing a reference to a const array, or passing a pointer and length (e.g. const byte* key and size_t keyLength).

c++ Remove everything in string prior to sequence including sequence

I've been writing a program that receives data from other sources across a network, and I need to sanitize the data before I send it to be processed. Previously, I had been doing it based on size, as below:
char data[max_length];
boost::system::error_code error;
size_t length = sock->read_some( boost::asio::buffer( data ), error );
std::stringstream ss;
for( int i = 0; i < max_length; i++ ) {
ss << data[i];
}
std::vector<int> idata;
std::string s2 = ss.str();
s2.erase( 0, 255 );
But the headers I need to remove are of variable length. So after doing some digging, I found I could remove them by finding the sequence of characters I know they'll end in - in this case \r\n\r\n - and removing everything up until then using size_t like so:
size_t p = s2.find( "\r\n\r\n" );
s2.erase( 0, p );
But that still leaves the \r\n\r\n at the beginning of my string which, at best, throws off my data handling later, and at worst, might cause issues down the line, as there are segments of my program that don't respond well to whitespace.
So my question is this: Is there a better way I could be doing this that will remove up to and including the specified sequence of characters? Can I just do p = p + 4; ? is that even possible with the size_t type?
Yes, you can write p + 4, since size_t is an (unsigned) integer type.
By the way, you might also want to pass data directly into a std::string constructor, rather than use std::stringstream ss.
Edit: To explain in more detail, it would look something like this:
char data[max_length];
// Read data and ensure that it is null-terminated ...
std::string s2(data); // Call the std::string constructor that inputs a null-terminated C string.
size_t p = s2.find("\r\n\r\n");
s2.erase(0, p + 4);