I've been working with OpenSSL library in C for a long time, but now I need to migrate to C++. OpenSSL's docs describe MD5 function like this.
unsigned char *MD5(const unsigned char *d, unsigned long n,
unsigned char *md);
I want to pass variable of type string to that function, but it accepts only char *.
Is it possible to pass string to parameter of type char * directly in C++? (I don't want to use extra manipulation with variable of type string)
You could use the c_str member function that std::string sports. Example
std::string data;
// load data somehow
unsigned char md[16] = { };
unsigned char *ret = MD5(reinterpret_cast<const unsigned char*>(data.c_str()),
data.size(),
md);
If you want to do away with the ugly cast operator, define a string class that holds unsigned chars instead of chars and use that.
typedef std::basic_string<unsigned char> ustring;
ustring data;
unsigned char *ret = MD5(data.c_str(), data.size(), md);
just a little note, which may save you a headache later on. MD5 takes an unsigned char pointer as a parameter. This is a clue that it's actually not a string, but a pointer to bytes.
In your program if you start storing byte vectors in a std::string, you're eventually going to initialise a string with a byte vector containing a zero, which opens the possibility of a bug that's difficult to detect down the line.
It is safer to store all your byte vectors in a std::vector<unsigned char> (or std::vector<uint8_t> because this forces safe initialisation.
std::vector<unsigned char> plaintext;
// initialise plaintext here
std::vector<unsigned char> my_hash(16);
MD5(plaintext.data(), plaintext.size(), &my_hash[0]);
Related
I want to create a std::istream object with a stream buffer object that can take raw byte data from array of unsigned char. I searched and found this Link
However they create the stream buffer based on array char:
struct membuf : std::streambuf
{
membuf(char* begin, char* end) {
this->setg(begin, begin, end);
}
};
I thought about type caste , but i don't want to modify the original data.So how i can it be done using unsigned char.
With std::istream you cannot use unsigned char explicitly, because it is a typedef for std::basic_istream<char> docs. You can cast your buffer pointers to char*
this->setg(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
Note that conversion of values greater than CHAR_MAX to char is implementaion defined (of course, only if you will actually use this values as char).
Or you can try to use std::basic_istream<unsigned char> (I have not tried it though).
I am a web developer and I am new to C++. I am using Qt C++. I was looking a way to generate a PBKDF2 key in Qt, but could not find a way to do that in pure C++. So looking on internet I have found this small C implementation https://github.com/ctz/fastpbkdf2. I need to use the following function
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
In my C++ file, I have
QString password = "password";
QString salt = "salt";
int iterations = 30000;
I know I can directly call any C function in C++, but I am not sure about how can I call that function with those parameters from my C++ file. An explanation of data type conversions would also be appreciated.
All you need to convert QString to char (or uint8_t):
QString passoword = "password";
QByteArray ba = password.toLatin1();
const uint8_t *pw = (const uint8_t*)ba.data();
And you can use this pw in the function. The same for "salt". You can use "iterations" as it is. For "out" parameter, allocate uint8_t with any method you prefer, could be malloc.
uint8_t is a typedef for an unsigned 8-bit integer, or in other words an unsigned char.
uint32_t is a typedef for an unsigned 32-bit integer, or in other words an unsigned int.
These typedefs are defined in stdint.h. These types were introduced to have well-defined (width-wise) integer types for portability.
size_t is typically an unsigned integer type as well. So the
prototype:
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
is equivalent to:
void fastpbkdf2_hmac_sha256(const unsigned char* pw, unsigned int npw,
const unsigned char* salt, unsigned int nsalt,
unsigned int iterations,
unsigned char* out, unsigned int nout);
Others have posted how to convert QString into a unsigned character array.
I am not too familiar with QT so I am looking at this page as a reference for a QString. It appears to be a managed string object while the function you want to call just wants a null terminated array of uint8_ts. I think it is wrapping std::string because there is a toStdString() member function. A std::string just manages a character array which is what your function wants so you can do this: password.toStdString().c_str() to get the char *.
Most platforms will implicitly convert uint8_t and char since they are almost always straight up 1 byte of memory.
There is also an output buffer and by the calling convention it looks like you have to manage that memory. From glancing at the docs of the github you linked it will output however much memory you tell it to using nout. In this example we create a 256 byte buffer for it to output to.
QString password = "password";
QString salt = "salt";
int iterations = 30000;
const size_t nout = 256;
uint8_t * out = new uint8_t[nout];
fastpbkdf2_hmac_sha256(password.toStdString().c_str(), password.toStdString().size(),
salt.toStdString().c_str(), salt.toStdString().size(),
iterations,
out, nout);
// use out
delete[] out;
I tried to convert QByteArray to std::vector<unsigned char> using this code:
unsigned char* buffer = (unsigned char*)byteArrayBuffer.constData();
std::vector<unsigned char>::size_type size = strlen((const char*)buffer);
std::vector<unsigned char> bufferToCompress(buffer, buffer + size);
but, assuming that byteArrayBuffer is a QByteArray filled with data, I think it doesn't work well on line unsigned char* buffer = (unsigned char*)byteArrayBuffer.constData(); because byteArrayBuffer.size() returns a different value than bufferToCompress.size().
How can I get it working?
I'm not familiar with Qt, but surely you just want
std::vector<unsigned char> bufferToCompress(
byteArrayBuffer.begin(), byteArrayBuffer.end());
Note: strlen is not particularly useful in C++; it tells you the length of a C-style null-terminated string (by searching memory until it either finds either finds a zero-valued byte, or falls off the end of accessible memory and crashes), but can't tell you the size of an array, which is what you'd need here. Also, using evil C-style casts to force invalid code to compile is never a good idea.
As I see here http://qt-project.org/doc/qt-4.8/qbytearray.html QByteArray does not have begin/end methods. But have data/length. Result code may be looks like this:
const unsigned char* begin = reinterpret_cast<unsigned char*>(byteArrayBuffer.data());
const unsigned char* end = begin + byteArrayBuffer.length();
std::vector<unsigned char> bufferToCompress( begin, end );
I can across reinterpret casts, and most of the time it was brought up, a warning was given, so I am wondering if there are other alternatives (or clean implementations of reinterpret cast of course)
You don't say what warning was given or what the problem was, but casting to char* with reinterpret_cast should work without warnings:
unsigned char *a;
const char *b = reinterpret_cast<char*>(a);
It depends on what you're trying to do.
If you just want to access the contents as char, then a simple
static_cast or using the value in a context where a char is expected
will do the trick.
If you need to pass the buffer to a function expecting a char const*,
a reinterpret_cast is about the only solution.
If you want a string, using the pointers into the buffer will be fine:
std::string
bufferToString( unsigned char const* buffer, size_t length )
{
return std::string( buffer, buffer + length );
}
or you can copy into an existing string:
myString.assign( buffer, buffer + length );
myString.append( buffer, buffer + length );
// etc.
Any string function (or algorithm, like std::copy) which takes two
iterators can be used. All that is required is that dereferencing the
iterator result in a type which converts implicitly to char, which is
the case of unsigned char.
(You cannot use the string functions which take a buffer address and a
length, as these are not templates, and require the buffer address to
have type char const*. And while unsigned char converts implicitly
to char, unsigned char* requires a reinterpret_cast to convert it
to char*.)
When I try the following, I get an error:
unsigned char * data = "00000000"; //error: cannot convert const char to unsigned char
Is there a special way to do this which I'm missing?
Update
For the sake of brevity, I'll explain what I'm trying to achieve:
I'd like to create a StringBuffer in C++ which uses unsigned values for raw binary data. It seems that an unsigned char is the best way to accomplish this. If there is a better method?
std::vector<unsigned char> data(8, '0');
Or, if the data is not uniform:
auto & arr = "abcdefg";
std::vector<unsigned char> data(arr, arr + sizeof(arr) - 1);
Or, so you can assign directly from a literal:
std::basic_string<unsigned char> data = (const unsigned char *)"abcdefg";
Yes, do this:
const char *data = "00000000";
A string literal is an array of char, not unsigned char.
If you need to pass this to a function that takes const unsigned char *, well, you'll need to cast it:
foo(static_cast<const unsigned char *>(data));
You have many ways. One is to write:
const unsigned char *data = (const unsigned char *)"00000000";
Another, which is more recommended is to declare data as it should be:
const char *data = "00000000";
And when you pass it to your function:
myFunc((const unsigned char *)data);
Note that, in general a string of unsigned char is unusual. An array of unsigned chars is more common, but you wouldn't initialize it with a string ("00000000")
Response to your update
If you want raw binary data, first let me tell you that instead of unsigned char, you are better off using bigger containers, such as long int or long long. This is because when you perform operations on the binary literal (which is an array), your operations are cut by 4 or 8, which is a speed boost.
Second, if you want your class to represent binary values, don't initialize it with a string, but with individual values. In your case would be:
unsigned char data[] = {0x30, 0x30, 0x30, 0x30, /* etc */}
Note that I assume you are storing binary as binary! That is, you get 8 bits in an unsigned char. If you, on the other hand, mean binary as in string of 0s and 1s, which is not really a good idea, but either way, you don't really need unsigned char and just char is sufficient.
unsigned char data[] = "00000000";
This will copy "00000000" into an unsigned char[] buffer, which also means that the buffer won't be read-only like a string literal.
The reason why the way you're doing it won't work is because your pointing data to a (signed) string literal (char[]), so data has to be of type char*. You can't do that without explicitly casting "00000000", such as: (unsigned char*)"00000000".
Note that string literals aren't explicitly of type constchar[], however if you don't treat them as such and try and modify them, you will cause undefined behaviour - a lot of the times being an access violation error.
You're trying to assign string value to pointer to unsigned char. You cannot do that. If you have pointer, you can assign only memory address or NULL to that.
Use const char instead.
Your target variable is a pointer to an unsigned char. "00000000" is a string literal. It's type is const char[9]. You have two type mismatches here. One is that unsigned char and char are different types. The lack of a const qualifier is also a big problem.
You can do this:
unsigned char * data = (unsigned char *)"00000000";
But this is something you should not do. Ever. Casting away the constness of a string literal will get you in big trouble some day.
The following is a little better, but strictly speaking it is still unspecified behavior (maybe undefined behavior; I don't want to chase down which it is in the standard):
const unsigned char * data = (const unsigned char *)"00000000";
Here you are preserving the constness but you are changing the pointer type from char* to unsigned char*.
#Holland -
unsigned char * data = "00000000";
One very important point I'm not sure we're making clear: the string "00000000\0" (9 bytes, including delimiter) might be in READ-ONLY MEMORY (depending on your platform).
In other words, if you defined your variable ("data") this way, and you passed it to a function that might try to CHANGE "data" ... then you could get an ACCESS VIOLATION.
The solution is:
1) declare as "const char *" (as the others have already said)
... and ...
2) TREAT it as "const char *" (do NOT modify its contents, or pass it to a function that might modify its contents).