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;
Related
According to these answers a buffer of bytes should be unsigned char, either because of convention or maybe the padding guarantees, I'm not sure. I have a function that looks something like:
saveDataToFile(const unsigned char* data, size_t size);
I find that I keep having to cast when I have a vector of char or an std::string or a string literal or something, and my code ends up looking like:
const char* text = "text";
saveDataToFile(text, 4); // Argument of const char* is incompatible with parameter of type const unsigned char*
saveDataToFile(reinterpret_cast<const unsigned char*>(text), 4);
Is there a way to avoid doing this all the time? Someone once mentioned to make my function take const char* instead of unsigned, but that doesn't really as then I'd have to cast the other way. For example std::string has .c_str() and .data() that return signed and unsigned. I also thought about taking void*, maybe that's the best way?
Perhaps the simplest way, as you have suggested yourself, is to make the function's first argument a const void* and then cast that to whatever is needed inside the function. This way, you also avoid using a reinterpret_cast and can safely use a static_cast:
void saveDataToFile(const void* data, size_t size)
{
const uint8_t* local = static_cast<const uint8_t*>(data);
//.. do something with the cast pointer ...
}
int main()
{
double dData = 33.3;
int16_t sData = 42;
char cData[] = "Hello, World!";
saveDataToFile(&dData, sizeof(dData));
saveDataToFile(&sData, sizeof(sData));
saveDataToFile(cData, sizeof(cData));
return 0;
}
A more "Pure C++" way (in some folks' eyes, maybe) would be to make a templated function. However, the disadvantages here are: (a) you will need a reinterpret_cast in this case; and (b) the compiler will (probably) generate separate function code for each of the different argument types used:
template<typename T>
void saveDataToFile(const T* data, size_t size)
{
const uint8_t* local = reinterpret_cast<const uint8_t*>(data);
//.. do something with the cast pointer ...
}
I have an API which requests a char*, this is my API function:
CANMessage(unsigned _id, const char* _data, char _len = 8)
More information available here: https://os.mbed.com/docs/mbed-os/v5.11/mbed-os-api-doxy/classmbed_1_1_c_a_n_message.html
I would like to call this function from within another function, but I am getting confused about const char* and casting. I want to call this function from function foo(), like so:
void foo(unsigned int id, /*???*/ data, char len) {
CANMessage(id, data, len)
}
So I need to pass id, data and len to function foo. My problem is that the data coming in is a uint8_t type. I got a vector of uint8_t, where the address of the first element is the one I need to pass:
vector<uint8_t> dta;
Which I tried to pass as &dta[0]: foo(idNo, &dta[0], length)
With the foo function as so:
void foo(unsigned int id, uint8_t* data, char len) {
CANMessage(id, (char*)data, len)
}
But I get "Argument of type std::uint8_t * is incompatible with parameter of type char*
How do I pass it as const char* when function foo, which calls it, accepts uint8_t*?
Please note I can't change types, dta has to stay vector<uint8_t>.
std::uint8_t ιs equal to unsigned char.
This is different from plain char or signed char, but all of them are 8 bit, therefore casting would techically work.
It's common that many functions that would otherwise need a "buffer" have a char* in their definition instead of the proper unsigned char*. Therefore, casting would most probably be harmless.
In the case that the function actually wants characters but not a buffer, then you have a problem because the types are different, and whether you will have an issue or not is undefined.
Since you are in an environment where std::uint8_t is available, the char types must be max 8 bits, but just to make sure you're not on a machine with 7 bit char's, add a static_assert.
reinterpret_cast the uint8_t* to const char* and static_cast the size (size_t) of the vector to char.
void foo(unsigned _id, const std::vector<uint8_t>& dta) {
static_assert(CHAR_BIT == 8, "Strange char");
CANMessage(
_id,
reinterpret_cast<const char*>(dta.data()),
static_cast<char>(dta.size())
);
}
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]);
I transfer message trough a CAN protocol.
To do so, the CAN message needs data of uint8_t type. So I need to convert my char* to uint8_t. With my research on this site, I produce this code :
char* bufferSlidePressure = ui->canDataModifiableTableWidget->item(6,3)->text().toUtf8().data();//My char*
/* Conversion */
uint8_t slidePressure [8];
sscanf(bufferSlidePressure,"%c",
&slidePressure[0]);
As you may see, my char* must fit in sliderPressure[0].
My problem is that even if I have no error during compilation, the data in slidePressure are totally incorrect. Indeed, I test it with a char* = 0 and I 've got unknow characters ... So I think the problem must come from conversion.
My datas can be Bool, Uchar, Ushort and float.
Thanks for your help.
Is your string an integer? E.g. char* bufferSlidePressure = "123";?
If so, I would simply do:
uint8_t slidePressure = (uint8_t)atoi(bufferSlidePressure);
Or, if you need to put it in an array:
slidePressure[0] = (uint8_t)atoi(bufferSlidePressure);
Edit: Following your comment, if your data could be anything, I guess you would have to copy it into the buffer of the new data type. E.g. something like:
/* in case you'd expect a float*/
float slidePressure;
memcpy(&slidePressure, bufferSlidePressure, sizeof(float));
/* in case you'd expect a bool*/
bool isSlidePressure;
memcpy(&isSlidePressure, bufferSlidePressure, sizeof(bool));
/*same thing for uint8_t, etc */
/* in case you'd expect char buffer, just a byte to byte copy */
char * slidePressure = new char[ size ]; // or a stack buffer
memcpy(slidePressure, (const char*)bufferSlidePressure, size ); // no sizeof, since sizeof(char)=1
uint8_t is 8 bits of memory, and can store values from 0 to 255
char is probably 8 bits of memory
char * is probably 32 or 64 bits of memory containing the address of a different place in memory in which there is a char
First, make sure you don't try to put the memory address (the char *) into the uint8 - put what it points to in:
char from;
char * pfrom = &from;
uint8_t to;
to = *pfrom;
Then work out what you are really trying to do ... because this isn't quite making sense. For example, a float is probably 32 or 64 bits of memory. If you think there is a float somewhere in your char * data you have a lot of explaining to do before we can help :/
char * is a pointer, not a single character. It is possible that it points to the character you want.
uint8_t is unsigned but on most systems will be the same size as a char and you can simply cast the value.
You may need to manage the memory and lifetime of what your function returns. This could be done with vector< unsigned char> as the return type of your function rather than char *, especially if toUtf8() has to create the memory for the data.
Your question is totally ambiguous.
ui->canDataModifiableTableWidget->item(6,3)->text().toUtf8().data();
That is a lot of cascading calls. We have no idea what any of them do and whether they are yours or not. It looks dangerous.
More safe example in C++ way
char* bufferSlidePressure = "123";
std::string buffer(bufferSlidePressure);
std::stringstream stream;
stream << str;
int n = 0;
// convert to int
if (!(stream >> n)){
//could not convert
}
Also, if boost is availabe
int n = boost::lexical_cast<int>( str )
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).