Inputting data to stringstream with hexadecimal representation

1k Views Asked by At

I am attempting to extract a hash-digest in hexadecimal via a stringstream, but I cannot get it to work when iterating over data.

Using std::hex I can do this easily with normal integer literals, like this:

#include <sstream>
#include <iostream>

std::stringstream my_stream;
my_stream << std::hex; 
my_stream << 100;

std::cout << my_stream.str() << std::endl; // Prints "64"

However when I try to push in data from a digest it just interprets the data as characters and pushes them into the stringstream. Here is the function:

#include <sstream>
#include <sha.h> // Crypto++ library required

std::string hash_string(const std::string& message) {
    using namespace CryptoPP;

    std::stringstream buffer;

    byte digest[SHA256::DIGESTSIZE]; // 32 bytes or 256 bits
    static SHA256 local_hash;

    local_hash.CalculateDigest(digest, reinterpret_cast<byte*>(
        const_cast<char*>(message.data())),
        message.length());

    // PROBLEMATIC PART
    buffer << std::hex; 
    for (size_t i = 0; i < SHA256::DIGESTSIZE; i++) {
        buffer << *(digest+i);
    }

    return buffer.str();
}

The type byte is just a typedef of unsigned char so I do not see why this would not input correctly. Printing the return value using std::cout gives the ASCI mess of normal character interpretation. Why does it work in the first case, and not in the second case?

Example:

std::string my_hash = hash_string("hello");
std::cout << hash << std::endl; // Prints: ",≥M║_░ú♫&Φ;*┼╣Γ₧←▬▲\▼ºB^s♦3bôïÿ$"
1

There are 1 best solutions below

1
On BEST ANSWER

First, the std::hex format modifier applies to integers, not to characters. Since you are trying to print unsigned char, the format modifier is not applied. You can fix this by casting to int instead. In your first example, it works because the literal 100 is interpreted as an integer. If you replace 100 with e.g. static_cast<unsigned char>(100), you would no longer get the hexadecimal representation.

Second, std::hex is not enough, since you likely want to pad each character to a 2-digit hex value (i.e. F should be printed as 0F). You can fix this by also applying the format modifiers std::setfill('0') and std::setw(2) (reference, reference).

Applying these modifications, your code would then look like this:

#include <iomanip>

...

    buffer << std::hex << std::setfill('0') << std::setw(2);
    for (size_t i = 0; i < SHA256::DIGESTSIZE; i++) {
        buffer << static_cast<int>(*(digest+i));
    }