Microsoft, Visual Studio, Version 6, C++ - Convert Byte* to Hex and reverse

I want to convert Byte* into Hex and vice versa. Attached is the example byte code sample, which is the output of CryptProtectData Encryption. The complete requirement is converted HEX value needs to be stored in an XML file visible to user for decrypting later. Please suggest if there are better ways of saving byte* output of CryptProtectData [http://msdn2.microsoft.com/en-us/library/aa380261.aspx] in XML format.

" ÐRß]Ç ÀOÂë þ­BkQ÷¤ÊÕÖF   T¬i0 s t¬e dPs0rp@iðn s@rnp. f ¨   ­VÿYË8ÊýÕ¤Ý6Å!à ¬     ï,ºÓ’äïO#zgc¼µ~ ^-åÔRôgÓ³Fkr Æuýá@ µ­DLøÝ´aÌÌgJÁd-\wÍLMEMà }á   ««««««««    !!áNàx¢ïîïîïî"
gaurav1408Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

evilrixSenior Software Engineer (Avast)Commented:
Are you saying you want to be able to BinHex the data and vice verca?
http://en.wikipedia.org/wiki/Binhex
0
Infinity08Commented:
BYTE *origData;   // <--- points to the BYTE array that contains the data
int origLen;          // <--- the length of the BYTE array that contains the data

for (int i = 0; i < origLen; ++i) {
    cout << hex << setfill('0') << setw(2) << (unsigned int) origData[i] << " ";
}
0
gaurav1408Author Commented:
I am looking for both the conversion byte* to hex and hex to byte*
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

evilrixSenior Software Engineer (Avast)Commented:
This should get you the other way...
#include <iostream>
#include <sstream>
#include <iomanip>
 
int main()
{
	// ABCDE in hex
	std::string hex("41424344453");
	std::string result;
	int byte;
 
	for(size_t idx = 0 ; idx < (hex.size()/2) ; ++idx)
	{
		std::stringstream ss(std::string(&hex[idx*2], 2));
		ss >> std::hex >> byte;
		result.append(1, (byte & 0xFF));
	}
 
	return 0;
}

Open in new window

0
Infinity08Commented:
>> I am looking for both the conversion byte* to hex and hex to byte*

as evilrix showed, you just have to do the same thing, but the other way around ;)
0
evilrixSenior Software Engineer (Avast)Commented:
Note, the extra 3 at the end of 41424344453 is not part of the byte sequence, it was placed there as a rogue value just to ensure the conversion process ignored it. Hex bytes come as a pair of course, so if the hex string has an odd number we just ignore the last one. This may or may not be the best way to handle this -- that's up to you I guess.
0
evilrixSenior Software Engineer (Avast)Commented:
>> Note, the extra 3 at the end of 41424344453 is not part of the byte sequence

i.e.

41 = 'A'
42 = 'B'
43 = 'C'
44 = 'D'
45 = 'E'
3 *ignored*
0
gaurav1408Author Commented:
I am very new to C++ when I am running evilrix: piece of code, I am getting <Bad Pointer> in result. So please help..
0
evilrixSenior Software Engineer (Avast)Commented:
>> I am very new to C++ when I am running evilrix: piece of code, I am getting <Bad Pointer> in result. So please help..

You are? It works fine for me. Did you let it run all the way to the end and then check result? The result variable is a string not a pointer. It is normal for it to show as containing a bad pointer until it's been given some initial value.

Try the code below, I've added output so you can see it works. It'll ask you to press any key at the end (assuming you are compiling this on a Windows platform).
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
 
int main()
{
	// ABCDE in hex
	std::string hex("41424344453");
	std::string result;
	int byte;
 
	for(size_t idx = 0 ; idx < (hex.size()/2) ; ++idx)
	{
		std::stringstream ss(std::string(&hex[idx*2], 2));
		ss >> std::hex >> byte;
		result.append(1, (byte & 0xFF));
	}
 
	std::cout << result << std::endl;
 
	system("pause"); // Windows only
 
	return 0;
}

Open in new window

0
evilrixSenior Software Engineer (Avast)Commented:
Below is expected (correct) values for result at various points in the code: -
Before it hits line 10
result	<Bad Ptr>		std::basic_string<char,std::char_traits<char>,std::allocator<char> >
 
After it hits like 10
result	""		std::basic_string<char,std::char_traits<char>,std::allocator<char> >
 
Once it hits line 22
result	"ABCDE"		std::basic_string<char,std::char_traits<char>,std::allocator<char> >

Open in new window

0
Infinity08Commented:
The inverse of my code would be (assuming that there is a space between every hex byte) :


BYTE *dest;      // <--- points to the target BYTE array
int destLen;     // <--- the length of the BYTE array
string src;      // <--- the string of hex bytes
 
stringstream ss(src);
for (int i = 0; i < destLen && ss.good(); ++i) {
    unsigned int val = 0;
    ss >> hex >> val;
    dest[i] = (BYTE) val;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
gaurav1408Author Commented:
Yep got it..
let me implement the piece of code in my project.. i hope this will solve the problem else i ll post the exact problem
0
evilrixSenior Software Engineer (Avast)Commented:
>> assuming that there is a space between every hex byte
I was working on the assumption this wouldn't be the case since it means the data will always be 33% bigger than it actually needs to be. Anyway, both solutions are perfectly valid, it really depends on what the actual requirement is, which isn't completely clear in the Q.

>> Please suggest if there are better ways of saving byte* output of CryptProtectData
Base64 would probably be a more efficient way to do this from a data size point of view.
http://en.wikipedia.org/wiki/Base64
0
evilrixSenior Software Engineer (Avast)Commented:
Encoding and decoding base64 with C++
http://www.adp-gmbh.ch/cpp/common/base64.html
0
evilrixSenior Software Engineer (Avast)Commented:
Online encoder/decoder so you can try it out for yourself to see if its a workable solution: -
http://www.motobit.com/util/base64-decoder-encoder.asp
0
Infinity08Commented:
>> Base64 would probably be a more efficient way

Leave out the "probably" ;) It's 1.5 times more efficient (when it comes to data size) than simply storing the bytes as a stream of hex characters.


The question is : are we talking about large amounts of binary data that needs to be put in an XML ? Is speed more important than compression ?
0
evilrixSenior Software Engineer (Avast)Commented:
>> Leave out the "probably" ;)
I was hedging my bets :)
0
evilrixSenior Software Engineer (Avast)Commented:
Below is the example base64 code from http:#20830976 built and tested (slightly modified so you can build it as one source file). As you can see it is trivial to use.

[output]
encoded: QURQIEdtYkgKQW5hbHlzZSBEZXNpZ24gJiBQcm9ncmFtbWllcnVuZwpHZXNlbGxzY2hhZnQgbWl0IGJlc2NocuRua3RlciBIYWZ0dW5n

decoded: ADP GmbH
Analyse Design & Programmierung
Gesellschaft mit beschrõnkter Haftung
[/output]

NB. Having a global std::string is a stupid idea! The constructor of a std::string can throw an exception and since you can't catch it you'll never know what happened. Fortunately, this is just test code :)
#include <iostream>
#include <string>
 
// RX: Really stupid idea this! This constructor can throw an exception.
static const std::string base64_chars = 
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789+/";
 
 
static inline bool is_base64(unsigned char c) {
  return (isalnum(c) || (c == '+') || (c == '/'));
}
 
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
  std::string ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];
 
  while (in_len--) {
    char_array_3[i++] = *(bytes_to_encode++);
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;
 
      for(i = 0; (i <4) ; i++)
        ret += base64_chars[char_array_4[i]];
      i = 0;
    }
  }
 
  if (i)
  {
    for(j = i; j < 3; j++)
      char_array_3[j] = '\0';
 
    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;
 
    for (j = 0; (j < i + 1); j++)
      ret += base64_chars[char_array_4[j]];
 
    while((i++ < 3))
      ret += '=';
 
  }
 
  return ret;
 
}
 
std::string base64_decode(std::string const& encoded_string) {
  int in_len = encoded_string.size();
  int i = 0;
  int j = 0;
  int in_ = 0;
  unsigned char char_array_4[4], char_array_3[3];
  std::string ret;
 
  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
    char_array_4[i++] = encoded_string[in_]; in_++;
    if (i ==4) {
      for (i = 0; i <4; i++)
        char_array_4[i] = base64_chars.find(char_array_4[i]);
 
      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 
      for (i = 0; (i < 3); i++)
        ret += char_array_3[i];
      i = 0;
    }
  }
 
  if (i) {
    for (j = i; j <4; j++)
      char_array_4[j] = 0;
 
    for (j = 0; j <4; j++)
      char_array_4[j] = base64_chars.find(char_array_4[j]);
 
    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 
    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
  }
 
  return ret;
}
 
int main() {
  const std::string s = "ADP GmbH\nAnalyse Design & Programmierung\nGesellschaft mit beschränkter Haftung" ;
 
  std::string encoded = base64_encode(reinterpret_cast<const unsigned char*>(s.c_str()), s.length());
  std::string decoded = base64_decode(encoded);
 
  std::cout << "encoded: " << encoded << std::endl;
  std::cout << "decoded: " << decoded << std::endl;
 
  return 0;
}

Open in new window

0
Infinity08Commented:
>> // RX: Really stupid idea this!

Lol, I love that comment. Why not just make it an array ?

static const char base64_chars[] =
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789+/";

;)


btw, that base64 code is somewhat inefficient if I may say so. Reminds me of this contest we had a while ago :

        http://www.experts-exchange.com/Programming/Languages/CPP/Q_21988706.html

We should really do something like that again ... It was fun heh :)
0
evilrixSenior Software Engineer (Avast)Commented:
>> Why not just make it an array ?
Hey, it's not my code -- I just posted it verbatim. As I said, since it's just a test harness I couldn't be bothered to fix it... I thought pointing it out would be good enough :)

>> that base64 code is somewhat inefficient if I may say so
Maybe, again not my code... there are plenty of other examples if you Google -- this just happened to be the first one I found that implemented a full solution that was simple enough for gaurav1408 to integrate cleanly.

>> We should really do something like that again ... It was fun heh :)
EE code offs :) I'd be no good... I'm not clever enough to do such things :(
0
Infinity08Commented:
>> EE code offs :) I'd be no good...

Well, it's still an interesting (albeit long) read heh.
0
Infinity08Commented:
May I ask why you gave a B grade ? That usually means that something was missing in the answer. And if that's the case, I'd like to know how I could have made it better (I'm constantly looking to improve myself ;) ). Also note that you can always ask for clarification if needed.
0
evilrixSenior Software Engineer (Avast)Commented:
Since this Q asked a number of things I am surprised at both the answer selected and the grade given, which doesn't really cover the original Q (at least not in full). A lot of effort and care was put into answering this by 2 experienced experts, it would be nice if the same effort and care was used when selecting and grading the answers given since experts will be less inclined to offer you assistance if they feel there efforts will likely go unacknowledged.

-Rx.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.