Mecanik
Mecanik

Reputation: 1051

Hash output as BYTE instead of std::string?

My question/problem might be a bit newbie regarding this field, but I cannot find any solution or clear explanation to achieve what I want.

The problem

I must store and use the hash values as BYTE instead of STRING because of the size. ( it causes me troubles in other areas )

The function generates an MD5 hash for a file, used on windows OS.

Current code

std::string MD5Checksum(const path &file)
{
    std::string result;
    try
    {
        CryptoPP::Weak::MD5 md5;

        CryptoPP::HashFilter f5(md5, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result)));

        CryptoPP::ChannelSwitch cs;
        cs.AddDefaultRoute(f5);

        CryptoPP::FileSource ss(file.string().c_str(), true /*pumpAll*/, new CryptoPP::Redirector(cs));
    }
    catch (CryptoPP::Exception const& exception)
    {
      // 
    }

    return result;
}

What I tested

std::string MD5Checksum(const path &file)
{
    std::string result;
    try
    {
        CryptoPP::Weak::MD5 md5;

        CryptoPP::HashFilter f5(md5, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result)));

        CryptoPP::ChannelSwitch cs;
        cs.AddDefaultRoute(f5);

        CryptoPP::FileSource ss(file.string().c_str(), true /*pumpAll*/, new CryptoPP::Redirector(cs));
    }
    catch (CryptoPP::Exception const& exception)
    {
        //
    }

    string decoded;
    CryptoPP::StringSource ss(result, true /*pumpAll*/, new CryptoPP::StringSink(decoded));
    const BYTE* data = reinterpret_cast<const BYTE*>(decoded.data());
    printf(L"sizeof result: %d, sizeof data: %d"), sizeof(result), sizeof(data));

    return result;
}

This seems to achieve the desired result, because the size of result string is 40 and the size of data is 8 which is a massive reduction in size for me.

However I do not see this as a good solution and I am pretty sure that there must but an easier and cleaner way of doing this.

Any examples are much appreciated.

Upvotes: 2

Views: 583

Answers (1)

jww
jww

Reputation: 102205

I must store and use the hash values as BYTE instead of STRING because of the size...

You are almost there.

Both StringSource and ArraySink can handle byte arrays. You just need to use alternate constuctors. Also see StringSource and ArraySink on the Crypto++ wiki.

I would modify the code similar to the following. I'm using C++11 so I don't have std::path:

$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "hex.h"

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "md5.h"

#include <iostream>

#if defined(CRYPTOPP_NO_GLOBAL_BYTE)
using CryptoPP::byte;
#endif

bool MD5Checksum(const std::string &file, byte* digest, size_t size)
{
    using namespace CryptoPP;

    try
    {
        Weak::MD5 md5;
        FileSource(file.c_str(), true /*pumpAll*/,
            new HashFilter(md5, new ArraySink(digest, size)));
    }
    catch (Exception const& exception)
    {
        return false;
    }

    return true;
}

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    std::string filename = (argc >= 2 ? argv[1] : "./cryptlib.h");
    byte digest[Weak::MD5::DIGESTSIZE];

    if (MD5Checksum(filename, digest, sizeof(digest)))
    {
        std::cout << "Filename: " << filename << std::endl;
        std::cout << "Digest: ";
        StringSource(digest, sizeof(digest), true, new HexEncoder(new FileSink(std::cout)));
        std::cout << std::endl;
    }
    else
    {
        std::cerr << "Failed to calculate digest of " << filename << std::endl;
        std::exit(1);
    }

    return 0;
}

And then compile. I'm working from the cryptopp/ directory in my home directory:

$ g++ ./test.cxx ./libcryptopp.a -o test.exe
$

And finally:

$ ./test.exe
Filename: ./cryptlib.h
Digest: 626047BC8770BE942B26B3AD6CBD3781

In the code above, here are the sources and sinks wrapping the byte array:

StringSource(digest, sizeof(digest) ...);
ArraySink(digest, size);

If you were storing into a std::string like in How to easily apply Crypto++ hash functions?, here are the sources and sinks wrapping the std::string. They are different constructors.

std::string digest;
...

StringSource(digest, ...);
StringSink(digest);

Upvotes: 2

Related Questions