Re: HMACs of files

Jeffrey Walton <[email protected]>
Newsgroups gmane.comp.encryption.cryptopp
Message-ID <CAH8yC8nio-zV0CTMp7ttUPCxL++fvbGOcJpZevHn_v7nq9G4mQ@mail.gmail.com>
On Tue, Sep 7, 2021 at 7:45 AM Tom <[email protected]> wrote:
>
> I can create HMACs of files using pipelines via filesources but... I can't seem to figure out to verify the HMAC without throwing the file into a string in memory.
>
> like this:
>
> StringSource(plain + mac, true, new HashVerificationFilter(hmac, NULL, flags) ); // StringSource
>
> Is there a way to use a FileSource without loading the file fully into memory?
>
> I think its possible but do I append the hmac if I use a file?

Yeah, that's a problem. We should have some documentation covering it.

I think you need a custom source that takes two sources - the existing
HMAC wrapped in a StringSource and the FileSource. The custom source
then pumps the data to the attached filter.

Another option is a HashVerificationFilter that takes two sources. It
could be tricky since the source is expected to pump its data. I did
not test this option.

Attached is an example. It uses a hash rather than HMAC to simplify the code.

The example has a bug, though. HashVerificationFilter is failing.
Instead of PUT_RESULT (or THROW), I used PUT_HASH to see the hash that
was calculated during verification. When using PUT_HASH, the
calculated digest has 32 0's appending to it. So the calculated digest
in the example program is
AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7
0000000000000000000000000000000000000000000000000000000000000000.

I'll add the example to the wiki once I get the problem sorted out.

Jeff

-- 
You received this message because you are subscribed to the Google Groups "Crypto++ Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion on the web visit https://groups.google.com/d/msgid/cryptopp-users/CAH8yC8nio-zV0CTMp7ttUPCxL%2B%2BfvbGOcJpZevHn_v7nq9G4mQ%40mail.gmail.com.
test.cxx (text/plain, 2.5 KB)
#include <iostream>
#include <string>

#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "sha.h"
#include "hex.h"

using namespace CryptoPP;

class CombinedSource : public Source
{
public:
    // Pumps s1 first, and then s2
    CombinedSource(Source& s1, Source& s2, bool pumpAll,
        BufferedTransformation* attachment)
        : Source(attachment), m_s1(s1), m_s2(s2) {
            if (pumpAll)
                PumpAll();
        }

    virtual size_t Pump2(lword &byteCount, bool blocking=true)
    {    
        std::cout << "Pump2: " << byteCount << std::endl;

        if (byteCount)
            m_s1.TransferTo2(*AttachedTransformation(), byteCount, DEFAULT_CHANNEL, blocking);

        if (byteCount)
            m_s2.TransferTo2(*AttachedTransformation(), byteCount, DEFAULT_CHANNEL, blocking);

        return static_cast<size_t>(byteCount);
    }

    virtual size_t PumpMessages2(unsigned int &messageCount, bool blocking=true)
    {
        std::cout << "PumpMessages2: " << messageCount << std::endl;

        if (messageCount)
            m_s1.TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);

        if (messageCount)
            m_s2.TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);

        return messageCount;
    }

    virtual bool SourceExhausted() const {
        return m_s1.SourceExhausted() && m_s2.SourceExhausted();
    }

private:
    Source &m_s1, &m_s2;
};

int main(int argc, char* argv[])
{
    // Create a file of all 0's with:
    // dd if=/dev/zero of=./zero.dat bs=4096 count=1

    std::string digest;
    SHA256 sha256;

    // Create the hash on the file
    FileSource("zero.dat", true, new HashFilter(sha256, new StringSink(digest)));

    std::cout << "Digest: ";
    StringSource(digest, true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    StringSource ss(digest, true);
    FileSource fs("zero.dat", true);

    byte result = 0;
    std::string digest2;
    CombinedSource cs(ss, fs, true,
        new HashVerificationFilter(sha256,
            // new ArraySink(&result, sizeof(result))));
            new StringSink(digest2), 4));

    std::cout << "Digest: ";
    StringSource(digest2, true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    if (result)
        std::cout << "Verified hash on file" << std::endl;
    else
        std::cout << "Failed to verify hash on file" << std::endl;

    return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.