21

Declaration of a method are following:

//some.h
void TDES_Decryption(BYTE *Data, BYTE *Key, BYTE *InitalVector, int Length);

I am calling this method from the following code:

//some.c
extern "C" __declspec(dllexport) bool _cdecl OnDecryption(LPCTSTR stringKSN, LPCTSTR BDK){
    TDES_Decryption(m_Track1Buffer, m_cryptoKey, init_vector, len);
    return m_Track1Buffer;
}

Where as data type of m_Track1Buffer is BYTE m_Track1Buffer[1000]; Now i want to make some changes in above method i.e. want to return the String in hex instead of Byte. How should i convert this m_Track1buffer to Hex string

Karthik T
  • 31,456
  • 5
  • 68
  • 87
Amit Pal
  • 10,604
  • 26
  • 80
  • 160
  • What is `hexagonal` string? Did you mean `hex` string here? Please edit and clarify. Also, it is always helpful to give examples of input and expected output. – mvp Dec 27 '12 at 06:36

5 Answers5

32

As you have mentioned c++, here is an answer. Iomanip is used to store ints in hex form into stringstream.

#include <iomanip>
#include <sstream>
#include <string>

std::string hexStr(const uint8_t *data, int len)
{
     std::stringstream ss;
     ss << std::hex;

     for( int i(0) ; i < len; ++i )
         ss << std::setw(2) << std::setfill('0') << (int)data[i];

     return ss.str();
}
ankostis
  • 8,579
  • 3
  • 47
  • 61
2r2w
  • 1,384
  • 1
  • 12
  • 29
  • 11
    You need to pad with the '0' character using `setfill('0')`. – jww Nov 28 '14 at 23:22
  • 4
    I had also to add std::setw to have it works to output correctly 2 digit for each number. So now it looks like `ss << std::hex << std:.setfill ('0');` and `ss<(data[i]);` – IFeelGood May 31 '18 at 06:38
  • This answer would be perfect if the comments were implemented. – Steve Smith Apr 30 '19 at 15:33
  • 1
    But also, `static_cast(static_cast(data[i]))` to support negative numbers (char is signed on many platforms) – user1119279 May 09 '22 at 10:01
11

This code will convert byte array of fixed size 100 into hex string:

BYTE array[100];
char hexstr[201];
int i;
for (i=0; i<ARRAY_SIZE(array); i++) {
    sprintf(hexstr+i*2, "%02x", array[i]);
}
hexstr[i*2] = 0;
mvp
  • 111,019
  • 13
  • 122
  • 148
9

Here is a somewhat more flexible version (Use uppercase characters? Insert spaces between bytes?) that can be used with plain arrays and various standard containers:

#include <string>
#include <sstream>
#include <iomanip>

template<typename TInputIter>
std::string make_hex_string(TInputIter first, TInputIter last, bool use_uppercase = true, bool insert_spaces = false)
{
    std::ostringstream ss;
    ss << std::hex << std::setfill('0');
    if (use_uppercase)
        ss << std::uppercase;
    while (first != last)
    {
        ss << std::setw(2) << static_cast<int>(*first++);
        if (insert_spaces && first != last)
            ss << " ";
    }
    return ss.str();
}

Example usage (plain array):

uint8_t byte_array[] = { 0xDE, 0xAD, 0xC0, 0xDE, 0x00, 0xFF };
auto from_array = make_hex_string(std::begin(byte_array), std::end(byte_array), true, true);
assert(from_array == "DE AD C0 DE 00 FF");

Example usage (std::vector):

// fill with values from the array above
std::vector<uint8_t> byte_vector(std::begin(byte_array), std::end(byte_array));
auto from_vector = make_hex_string(byte_vector.begin(), byte_vector.end(), false);
assert(from_vector == "deadc0de00ff");
Max Truxa
  • 3,308
  • 25
  • 38
8

Using stringstream, sprintf and other functions in the loop is simply not C++. It's horrible for performance and these kind of functions usually get called a lot (unless you're just writing some things into the log).

Here's one way of doing it. Writing directly into the std::string's buffer is discouraged because specific std::string implementation might behave differently and this will not work then but we're avoiding one copy of the whole buffer this way:

#include <iostream>
#include <string>
#include <vector>

std::string bytes_to_hex_string(const std::vector<uint8_t> &input)
{
  static const char characters[] = "0123456789ABCDEF";

  // Zeroes out the buffer unnecessarily, can't be avoided for std::string.
  std::string ret(input.size() * 2, 0);
  
  // Hack... Against the rules but avoids copying the whole buffer.
  auto buf = const_cast<char *>(ret.data());
  
  for (const auto &oneInputByte : input)
  {
    *buf++ = characters[oneInputByte >> 4];
    *buf++ = characters[oneInputByte & 0x0F];
  }
  return ret;
}

int main()
{
  std::vector<uint8_t> bytes = { 34, 123, 252, 0, 11, 52 };
  std::cout << "Bytes to hex string: " << bytes_to_hex_string(bytes) << std::endl;
}
BJovke
  • 1,737
  • 15
  • 18
  • This is much better than the expected solution. You can also remove the vector type input and use a pointer array instead. That'll make it even more minimal (requiring few libraries) – Imtiaz Shakil Siddique Aug 10 '21 at 09:05
  • 2
    you can do this without violating the spec by using reserve and back_inserter std::string ret; ret.reserve(input.size() * 2); auto buf = std::back_inserter(ret); – Joseph Nov 18 '22 at 17:41
2

how about using the boost library like this (snippet taken from http://theboostcpplibraries.com/boost.algorithm ):

#include <boost/algorithm/hex.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::vector<char> v{'C', '+', '+'};
  hex(v, std::ostream_iterator<char>{std::cout, ""});
  std::cout << '\n';

  std::string s = "C++";
  std::cout << hex(s) << '\n';

  std::vector<char> w{'4', '3', '2', 'b', '2', 'b'};
  unhex(w, std::ostream_iterator<char>{std::cout, ""});
  std::cout << '\n';

  std::string t = "432b2b";
  std::cout << unhex(t) << '\n';
}
serup
  • 3,676
  • 2
  • 30
  • 34
  • 1
    I'm not sure if you got downvoted because of Boost, but I think your answer is acceptable and should not have a negative score. – Darrin Cullop Jan 05 '19 at 00:46
  • 1
    For Qt alternative: https://stackoverflow.com/questions/36603001/how-can-i-convert-a-qbytearray-into-a-hex-string – Anssi Feb 17 '20 at 10:52