create and display hexadecimal string in c++ - c++

I've been reading many suggestions on the same topic, and tried to implement many of them, but it seems that none of them is actually working in my environment.
I'm using QT 5, but I think the problem is not related to QT but to how the hexadecimal character 0x00 is interpreted by the language.
What I have to achieve is to display a stream of unsigned char as hexadecimal values, eg:
Input bytes: 0x00 0x4E 0x01 0x00 0x17 0x00
Display as: 0x00:0x4E:0x01:0x00:0x17:0x00
it seems quite easy, but all I get is an empty string...
The functions I wrote:
QString getBufferAsHexStr(const unsigned char* buf, int buffsize) {
std::string finalstring("");
char tempbuff[5];
int n=0, index=0;
for (int c = 0; c < buffsize; c++) {
if(c == buffsize-1) {
n=sprintf(tempbuff, "0x%02X", buf[c]);
} else {
n=sprintf(tempbuff, "0x%02X:", buf[c]);
}
finalstring.append(tempbuff, n);
index += n;
}
QString resultStr(finalstring.c_str());
return resultStr;
}
QString getBufferAsHexStr(const unsigned char* buf, int buffsize) {
std::stringstream ss;
for (int c = 0; c < buffsize; c++) {
if(c == buffsize-1) {
ss << std::hex << std::showbase << buf[c];
} else {
ss << std::hex << std::showbase << buf[c] << ":";
}
}
const std::string finalstring = ss.str();
QString resultStr(finalstring.c_str());
return resultStr;
}

I don't know why you started to use C++ functions with C++ types when you have a much better alternative which is QString. Using QString you might implement it as follows:
QString getBufferAsHexStr(const unsigned char* buf, int buffsize) {
QString result;
for(int i = 0; i < buffsize; ++i)
result += "0x" + QString("%1:").arg(buf[i], 2, 16, QChar('0')).toUpper();
result.chop(1);
return result;
}

Another version using a QByteArray and a joined QStringList:
QString getBufferAsHexStr(QByteArray buf) {
QStringList byteStrings;
for (int i = 0; i < buf.size(); ++i)
byteStrings += QString("0x") + QString("%1").arg(buf[i], 2, 16, QChar('0')).toUpper();
return byteStrings.join(":");
}
It would by called using
QString result = getBufferAsHexStr(QByteArray(charArr, charArrSize));

Related

Convert HEX to printable string/char

I'm using CNG to generate a hash.
Result of BCryptFinishHash call is MD5 of a input in hex form.
Example:
char *outHash = "\x02\x34\x75\01..."
I want to convert it to printable string: 02347501...
How can I do that?
To encode a byte array in hex and write the encoded data to a std::string, do this:
static inline char
hex_digit(unsigned int n)
{
if (n < 10) return '0' + n;
if (n < 16) return 'a' + (n - 10);
abort();
}
std::string
encode_bytes(const unsigned char *bytes, size_t len)
{
std::string rv;
rv.reserve(len * 2);
for (size_t i = 0; i < len; i++) {
rv.push_back(hex_digit((bytes[i] & 0xF0) >> 4));
rv.push_back(hex_digit((bytes[i] & 0x0F) >> 0));
}
return rv;
}
Note that you must know the length of the byte array. It is not safe to treat it as a NUL-terminated "C string", because binary data can contain internal zero bytes. To know the length of a hash generated by CNG, call BCryptGetProperty to get the BCRYPT_HASH_LENGTH property.
we can use CryptBinaryToString here with CRYPT_STRING_HEXASCII or CRYPT_STRING_HEX or CRYPT_STRING_HEXRAW or CRYPT_STRING_HEX | CRYPT_STRING_NOCRLF or CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF depen how you want format string. for example
void print(PUCHAR pbHash, ULONG cbHash, DWORD dwFlags = CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF)
{
ULONG cch = 0;
if (CryptBinaryToStringW(pbHash, cbHash, dwFlags, 0, &cch))
{
if (PWSTR sz = (PWSTR)_malloca(cch * sizeof(WCHAR)))
{
if (CryptBinaryToStringW(pbHash, cbHash, dwFlags, sz, &cch))
{
DbgPrint("%S\n", sz);
}
_freea(sz);
}
}
}
If you need an easy, one time solution, this is a useful tool:
https://codebeautify.org/hex-string-converter
However, if you're looking to do this within your code itself, I found this from an earlier thread (AKA, this is not my work but that of #KEINE LUST from here )
int main(void)
{
unsigned char readingreg[4];
readingreg[0] = 0x4a;
readingreg[1] = 0xaa;
readingreg[2] = 0xaa;
readingreg[3] = 0xa0;
char temp[4];
sprintf(temp, "%x", readingreg[0]);
printf("This is element 0: %s\n", temp);
return 0;
}
You can print it like this:
for(const char *wsk=outHash; *wsk; ++wsk){
printf("%02hhx", *wsk);
}
Edit based that cstring can have 0x00 numbers.
C
const char outHash[] = "\x02\x34\x75";
const int size = sizeof(outHash)/sizeof(char) - 1;
for(int i = 0; i < size; ++i){
printf("%02hhx", outHash [i]);
}
C++
std::string outHash = "\x02\x34\x75";
for(int i = 0; i < outHash.size(); ++i) {
printf("%02hhx", outHash [i]);
}
Loop over the characters and print the numerical value (in hex).
#include <iostream>
#include <iomanip>
int main()
{
char* outHash = "\x02\x34\x75\x01\x23\xff"; // Get from your Hash function.
int sizeOfHash = 6; // Use appropriate size for BCryptFinishHash()
// Set up the characteristics of the stream.
// setw(2): Each printed object will use a min width of 2
// setfill('0'): If the object is less than 2 char then fill the space with '0'
// hex: Print numbers in hex.
std::cout << std::setw(2) << std::setfill('0') << std::hex;
// Create a view of the object.
// Makes it simpler to loop over.
std::string_view view(outHash, sizeOfHash);
// Loop over the string.
for(unsigned char val: view) {
// Convert to `unsigned char` to make sure you don't print
// negative numbers. Then convert from there to `int` so that
// the `std::hex will kick in and convert to hex value.
std::cout << static_cast<int>(val);
}
std::cout << "\n";
}
I am working on C++ wrapper around Windows Crypto API & CNG which I am using in my projects. I plan to move all of it to github but for now it is just a work in progress, but you can find it useful for Crypto basics like HEX / Base64 encode / decode etc.
https://github.com/m4x1m1l14n/Crypto
You can use Crypto::Hex::Encode() method to achieve what you want.
#include <Crypto\Hex.hpp>
#include <Crypto\Random.hpp>
using namespace m4x1m1l14n;
char arr[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0x99, 0x00 };
encoded = Crypto::Hex::Encode(arr, sizeof(arr));
/* encoded = "aabbccdd9900" */
Also you can use wrapper for MD5 which is located in Hash namespace, like this. (If you are not using large amount of data)
#include <Crypto\Hex.hpp>
#include <Crypto\Hash.hpp>
using namespace m4x1m1l14n;
encoded = Crypto::Hex::Encode(Crypto::Hash::MD5("Whatever you want to hash"));

Calculate RSA and save to file in HEX

i'm trying to to encrypt a buffer with rsa and then save the data in hex format to file. I'm using Crypto++ 5.6.5.
Loading keys (working):
try
{
// Read RSA public
FileSource fs1("public.pem", true);
PEM_Load(fs1, pubKey);
// Read RSA encrypted private
FileSource fs2("private.pem", true);
PEM_Load(fs2, privKey, "1234", 4);
}
catch(const Exception& ex)
{
cout << "ERROR: RSA:" << ex.what() << endl;
SystemLog_Print("RSA: Couldn't load keys");
}
Encrypt (ok?):
std::string RSA_Encrypt(unsigned char *buf, uint8_t len)
{
AutoSeededRandomPool rng;
std::string plain;
std::string cipher, recovered;
for(int i = 0; i < len; ++i) {
plain.push_back(buf[i]);
}
// Encryption
RSAES_OAEP_SHA_Encryptor e(pubKey);
StringSource ss1(plain, true, new PK_EncryptorFilter(rng, e, new StringSink(cipher)));
// Test Decryption
RSAES_OAEP_SHA_Decryptor d(privKey);
StringSource ss2(cipher, true, new PK_DecryptorFilter(rng, d, new StringSink(recovered)));
if(memcmp(plain.data(), recovered.data(), plain.size()) != 0) {
cout << "RSA Mismatch" << endl;
}
return cipher;
}
Now i'm stuck with writing the encrypted data to a file in readable HEX like:
AB123CDE456
Using stream operators like std::hex doesn't seem to work.
Could you give me any advice how to do this?
Not working:
unsigned char *buf[] = "123456789";
file << std::hex << RSA_Encrypt(buf, 9);
Prints only some unreadable binary data;
OK, for anyone interested...
I found a generic hex formatter here: Integer to hex string in C++
I slightly modified it like this:
template< typename T >
std::string int2hex(T i)
{
std::stringstream stream;
stream << std::setfill ('0') << std::setw(sizeof(T)*2)
<< std::hex << (int32_t)i;
return stream.str();
}
Now i call my routines like this:
buf = RSA_Encrypt(data, 32);
// Write hash to sig file
for(unsigned int i = 0 ; i < buf.size() ; ++i) {
uint8_t val = buf[i];
file << int2hex(val);
}
Now i get HEX chars in my file.
A hex output function could look like this:
void writeHex(std::ostream &out, const char *data, size_t len)
{
char digits[] = "0123456789ABCDEF";
for (size_t i = 0; i < len; ++i) {
unsigned byte = (unsigned)data[i];
out << digits[byte >> 4] << digits[byte & 0xf];
}
}
With a small sample to test it:
#include <iostream>
void writeHex(std::ostream &out, const char *data, size_t len)
{
char digits[] = "0123456789ABCDEF";
for (size_t i = 0; i < len; ++i) {
unsigned byte = (unsigned)data[i];
out << digits[byte >> 4] << digits[byte & 0xf];
}
}
int main()
{
// sample data
char data[] =
"This is some test data:\n"
"\x00\x01\x02\x03\0x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\0x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\0x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\0x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f";
// test writeHex()
writeHex(std::cout, data, sizeof data);
std::cout << std::endl;
// done
return 0;
}
Compiled and tested with VS2013 on Windows 10 (64 bit):
5468697320697320736F6D65207465737420646174613A0A000102030078303405060708090A0B0C0D0E0F101112130078313415161718191A1B1C1D1E1F202122230078323425262728292A2B2C2D2E2F303132330078333435363738393A3B3C3D3E3F00
The human-readable text at the begin of my test data[] can be checked using an ASCII table. I simply searched for "000102" and saw the "0A" (for \n) before. The "00" at the end of output is for the string 0-terminator (which is considered by sizeof also).
Now i'm stuck with writing the encrypted data to a file in readable
HEX like:
AB123CDE456
Add a HexEncoder and use a FileSink in the pipeline:
StringSource ss(plain, true, new PK_EncryptorFilter(rng, enc, new HexEncoder(new FileSink("file.enc"))));
With the change above, the data is hex encoded as it travels through the pipeline.
Later, when you are ready to read the data, you use a FileSource and add a HexDecoder in the pipeline. Ad the decoder is added before the decryptor, not afterwards like when encrypting.
FileSource fs("file.enc", true, new HexDecoder, new PK_DecryptorFilter(rng, dec, new StringSink(recovered))));
You should probably avoid this because its not a constant time compare:
if(memcmp(plain.data(), recovered.data(), plain.size()) != 0) {
cout << "RSA Mismatch" << endl;
}
Use VerifyBufsEqual instead:
bool equal = VerifyBufsEqual(plain.data(), recovered.data(), plain.size());
VerifyBufsEqual requires same size buffers, so maybe something like:
bool equal = (plain.size() == recovered.size());
size_t size = STDMIN(plain.size(), recovered.size());
equal = VerifyBufsEqual(plain.data(), recovered.data(), size) && equal;
This may help...
Instead of using an intermediate std::string:
std::string RSA_Encrypt(unsigned char *buf, uint8_t len)
{
...
for(int i = 0; i < len; ++i) {
plain.push_back(buf[i]);
}
...
StringSource ss(plain, true, new PK_EncryptorFilter(rng, enc, new StringSink(cipher)));
...
}
You can use the buf and len instead:
std::string RSA_Encrypt(unsigned char *buf, uint8_t len)
{
...
ArraySource as(buf, len, true, new PK_EncryptorFilter(rng, enc, new StringSink(cipher)));
...
}
An ArraySource is really a typedef of a StringSource using a constructor overload.

Hex manipulations

There are very nice Hex.Decode(string hexString) and Hex.ToHexString(byte[] hexArray) methods in BouncyCastle crypto library (C#, Java).
How to make the same conversions with CString variable, that stores hex-string for example "af010cdb" to unsigned char* and vice-versa in C++?
These are real easy to implement:
CString ToHexString(const CByteArray& Array)
{
CString sHexString;
for (int i=0; i<Array.GetSize(); i++)
sHexString.AppendFormat(_T("%02X"), Array[i]);
return sHexString;
}
void DecodeHexString(const CString& sHexString, CByteArray &Array)
{
if (sHexString.IsEmpty())
return;
int nLen = sHexString.GetLength();
if ((nLen % 2) != 0)
{
ASSERT(FALSE);
return;
}
Array.SetSize(nLen/2);
int nByte = 0;
for(int i=0; i<nLen; i += 2)
{
CString sByte = sHexString.Mid(i, 2);
BYTE byte = (BYTE)_tcstol(sByte, NULL, 16);
Array[nByte] = byte;
nByte++;
}
}
You can also use std::string and std::vector<unsigned char>
Edit: removed sscanf and sprintf
std::vector<unsigned char> str_to_byte(std::string str)
{
std::vector<unsigned char> bytes;
std::stringstream ss(str);
std::string part;
while (ss >> std::setw(2) >> part)
{
try {
int i = std::stoi(part, 0, 16);
bytes.push_back(static_cast<unsigned char>(i));
}
catch (...) {//error msg
}
}
return bytes;
}
std::string byte_to_str(std::vector<unsigned char> bytes)
{
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::uppercase;
for (auto c:bytes)
ss << std::setw(2) << static_cast<unsigned int>(c);
return ss.str();
}
int main()
{
std::vector<unsigned char> bytes = str_to_byte("EF010203A0A1FFz");
std::string str = byte_to_str(bytes);
cout << str << endl; //should print "EF010203A0A1FF"
return 0;
}

Is there a better way to search a file for a string?

I need to search a (non-text) file for the byte sequence "9µ}Æ" (or "\x39\xb5\x7d\xc6").
After 5 hours of searching online this is the best I could do. It works but I wanted to know if there is a better way:
char buffer;
int pos=in.tellg();
// search file for string
while(!in.eof()){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='9'){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='µ'){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='}'){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='Æ'){
cout << "found";
}
}
}
}
in.seekg((streampos) pos);
Note:
I can't use getline(). It's not a text file so there are probably not many line breaks.
Before I tried using a multi-character buffer and then copying the buffer to a C++ string, and then using string::find(). This didn't work because there are many '\0' characters throughout the file, so the sequence in the buffer would be cut very short when it was copied to the string.
Similar to what bames53 posted; I used a vector as a buffer:
std::ifstream ifs("file.bin");
ifs.seekg(0, std::ios::end);
std::streamsize f_size = ifs.tellg();
ifs.seekg(0, std::ios::beg);
std::vector<unsigned char> buffer(f_size);
ifs.read(buffer.data(), f_size);
std::vector<unsigned char> seq = {0x39, 0xb5, 0x7d, 0xc6};
bool found = std::search(buffer.begin(), buffer.end(), seq.begin(), seq.end()) != buffer.end();
If you don't mind loading the entire file into an in-memory array (or using mmap() to make it look like the file is in memory), you could then search for your character sequence in-memory, which is a bit easier to do:
// Works much like strstr(), except it looks for a binary sub-sequence rather than a string sub-sequence
const char * MemMem(const char * lookIn, int numLookInBytes, const char * lookFor, int numLookForBytes)
{
if (numLookForBytes == 0) return lookIn; // hmm, existential questions here
else if (numLookForBytes == numLookInBytes) return (memcmp(lookIn, lookFor, numLookInBytes) == 0) ? lookIn : NULL;
else if (numLookForBytes < numLookInBytes)
{
const char * startedAt = lookIn;
int matchCount = 0;
for (int i=0; i<numLookInBytes; i++)
{
if (lookIn[i] == lookFor[matchCount])
{
if (matchCount == 0) startedAt = &lookIn[i];
if (++matchCount == numLookForBytes) return startedAt;
}
else matchCount = 0;
}
}
return NULL;
}
.... then you can just call the above function on the in-memory data array:
char * ret = MemMem(theInMemoryArrayContainingFilesBytes, numBytesInFile, myShortSequence, 4);
if (ret != NULL) printf("Found it at offset %i\n", ret-theInMemoryArrayContainingFilesBytes);
else printf("It's not there.\n");
This program loads the entire file into memory and then uses std::search on it.
int main() {
std::string filedata;
{
std::ifstream fin("file.dat");
std::stringstream ss;
ss << fin.rdbuf();
filedata = ss.str();
}
std::string key = "\x39\xb5\x7d\xc6";
auto result = std::search(std::begin(filedata), std::end(filedata),
std::begin(key), std::end(key));
if (std::end(filedata) != result) {
std::cout << "found\n";
// result is an iterator pointing at '\x39'
}
}
const char delims[] = { 0x39, 0xb5, 0x7d, 0xc6 };
char buffer[4];
const size_t delim_size = 4;
const size_t last_index = delim_size - 1;
for ( size_t i = 0; i < last_index; ++i )
{
if ( ! ( is.get( buffer[i] ) ) )
return false; // stream to short
}
while ( is.get(buffer[last_index]) )
{
if ( memcmp( buffer, delims, delim_size ) == 0 )
break; // you are arrived
memmove( buffer, buffer + 1, last_index );
}
You are looking for 4 bytes:
unsigned int delim = 0xc67db539;
unsigned int uibuffer;
char * buffer = reinterpret_cast<char *>(&uibuffer);
for ( size_t i = 0; i < 3; ++i )
{
if ( ! ( is.get( buffer[i] ) ) )
return false; // stream to short
}
while ( is.get(buffer[3]) )
{
if ( uibuffer == delim )
break; // you are arrived
uibuffer >>= 8;
}
Because you said you cannot search the entire file because of null terminator characters in the string, here's an alternative for you, which reads the entire file in and uses recursion to find the first occurrence of a string inside of the whole file.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string readFile (char *fileName) {
ifstream fi (fileName);
if (!fi)
cerr << "ERROR: Cannot open file" << endl;
else {
string str ((istreambuf_iterator<char>(fi)), istreambuf_iterator<char>());
return str;
}
return NULL;
}
bool findFirstOccurrenceOf_r (string haystack, char *needle, int haystack_pos, int needle_pos, int needle_len) {
if (needle_pos == needle_len)
return true;
if (haystack[haystack_pos] == needle[needle_pos])
return findFirstOccurrenceOf_r (haystack, needle, haystack_pos+1, needle_pos+1, needle_len);
return false;
}
int findFirstOccurrenceOf (string haystack, char *needle, int length) {
int pos = -1;
for (int i = 0; i < haystack.length() - length; i++) {
if (findFirstOccurrenceOf_r (haystack, needle, i, 0, length))
return i;
}
return pos;
}
int main () {
char str_to_find[4] = {0x39, 0xB5, 0x7D, 0xC6};
string contents = readFile ("input");
int pos = findFirstOccurrenceOf (contents, str_to_find, 4);
cout << pos << endl;
}
If the file is not too large, your best solution would be to load the whole file into memory, so you don't need to keep reading from the drive. If the file is too large to load in at once, you would want to load in chunks of the file at a time. But if you do load in chucks, make sure you check to edges of the chunks. It's possible that your chunk happens to split right in the middle of the string you're searching for.

Artema Hybrid communication with c++ on Linux

I am currently trying to integrate a POS system with an Artema Hybrid CC handheld. I am wondering if anyone else has worked on this or something similar.
I can read from the device, that is I receive the ENQ, and send back an ACK in a thread, and I keep it open for reading/writing, but everything I try to write from it simply does nothing.
Here is the code for the function to write the data:
void PayLife::sendPayLifeData(QString data) {
int len = data.length();
int i = 0;
char lrc = 0;
char stx = 0x02;
char etx = 0x03;
char ack = 0x06;
char * bytes;
int ret;
char buffer[132];
bytes = (char *) malloc(sizeof(char) * len + 10);
strcpy(bytes,data.toLatin1().data());
qDebug() << "PayLife Sending data: " << data << " of len " << QString::number(len) <<
" " << " Bytes is: " << bytes ;
while (i < len) {
lrc ^= bytes[i];
i++;
}
/* sprintf(buffer,"%c%c%s%c%c",ack,stx,bytes,etx,lrc);
for (i = 0; i < strlen(buffer); i++) {
printf("c: %X ", buffer[i]);
}
printf(" [[ %s ]] \n", buffer); */
qDebug() << "Starting";
write(this->descriptor,&ack,1);
usleep(100000);
write(this->descriptor,&stx,1);
usleep(100000);
ret = write(this->descriptor,bytes,132);
usleep(100000);
write(this->descriptor,&etx,1);
usleep(100000);
write(this->descriptor,&lrc,1);
qDebug() << "Done";
free(bytes);
}
The data argument is: E11U000008507000099VZ000000
Of course, the documentation is in German, which I don't speak, so this is as far as I have gotten. I've basically got 1 month to implement this then I have to give the device back.
If anyone has any pointers, or some example code that would be awesome.
/jason
The transport protocol looks like something standard, so maybe you should only send len bytes of the data not 132 and include the ETX character in the lrc summing ?
It might be easier and clearer to use QByteArray instead of malloc arrays or QString (QString are for user displayed strings which is not the case here):
void PayLife::sendPayLifeData(const QByteArray & data) {
static const char stx = 0x02;
static const char etx = 0x03;
static const char ack = 0x06;
QByteArray buffer = stx + data + etx;
// Calculate the xor sum on data + etx
char lrc = 0;
for(int i = 1; i < buffer.size(); ++i) {
lrc ^= buffer[i];
}
buffer += lrc;
qDebug() << "Starting";
write(this->descriptor, &ack, 1);
write(this->descriptor, buffer.data(), buffer.size());
qDebug() << "Done";
}
You should also have a look at QSerialDevice, it could allow you to implement the protocol in a more event driven way with signal and slots.