> I need to encrypt a stream (with a symmetric algorithm)
> and compute its HMAC at the same time.

You have to be careful here. Combining a confidentiality mode with an 
authenticity mode can cause some trouble if you combine them incorrectly. 
Its probably best to use a mode that does it for you, like EAX, CCM or GCM 
mode.

Getting authenticated encryption wrong is easy. SSL/TLS and SSH got them 
wrong, and they've been dealing with the associated bugs for decades. IPSec 
got it right with Encrypt-Then-Authenticate.

To have a chance at getting it right, you have to encrypt the data first 
and then MAC it. That's what IPSec does. See 
http://www.cryptopp.com/wiki/Authenticated_Encryption for more details.

> In Botan you do it with the Fork class.

Crypto++ has a ChannelSwitch which allows you to take data and send it to 
multiple sinks. But I don't think that's what you want in the is case.

If you were doing authenticated encryption using Encrypt-And-Authenticate 
(like SSH), then you could use the ChannelSwitch.

> Is there an easy way to do that in crypto++, without going through it 
twice

Yes, just pipeline the data. Have the output of the encryptor feed the HMAC.

You can read more about pipelining at http://www.cryptopp.com/wiki/Pipeline.

> without going through it twice

You will *always* have to touch the data twice. The only mode that supports 
touching the data once is CWC mode. Its patented, so everything else 
touches the data twice.

With that out of the way, below is a program that kind of does what you 
want. It streams plaintext data through and encryptor and then a HMAC. 
Unfortunately, it appears to have a bug. The unfortunate thing is the bug 
appears to be in the Crypto++ library (modulo me doing something dumb).

I have not analyzed the stack trace, yet. I'm tossing it out there in case 
someone else has time to look at it and develop a patch.

********

static const int DIGEST_SIZE = HMAC<SHA256>::DIGESTSIZE;

SecByteBlock keys(16 /*AES key*/ + 16 /*AES IV*/ + 16 /*HMAC key*/);
OS_GenerateRandomBlock(false, keys, keys.size());

CBC_Mode<AES>::Encryption encryptor;
encryptor.SetKeyWithIV(keys.data() + 0 /*key*/, 16, keys.data() + 16 
/*iv*/, 16);
CBC_Mode<AES>::Decryption decryptor;
encryptor.SetKeyWithIV(keys.data() + 0 /*key*/, 16, keys.data() + 16 
/*iv*/, 16);
HMAC<SHA256> hmac1;
hmac1.SetKey(keys.data() + 32, 16);
HMAC<SHA256> hmac2;
hmac2.SetKey(keys.data() + 32, 16);

HexEncoder encoder(new FileSink(cout));

cout << "AES key: ";
encoder.Put(keys.data() + 0, 16);
encoder.MessageEnd(); cout << endl;

cout << "AES IV: ";
encoder.Put(keys.data() + 16, 16);
encoder.MessageEnd(); cout << endl;

cout << "HMAC key: ";
encoder.Put(keys.data() + 32, 16);
encoder.MessageEnd(); cout << endl;

string plain = "Now is the time for all good men to come to the aide of 
their country";
string cipher, recover;

cout << plain << endl;

// Encrypt with HMAC

StringSource ss1(plain, true /*pumpAll*/,
             new StreamTransformationFilter(encryptor,
                                            new HashFilter(hmac1,
                                                           new 
StringSink(cipher),
                                                           true 
/*putMessage*/,
                                                           DIGEST_SIZE)));


cout << "Ciphertext+MAC: ";
encoder.Put((byte*)cipher.data(), cipher.size());
encoder.MessageEnd(); cout << endl;

// Decrypt with HMAC verification

StringSource ss2(cipher, true /*pumpAll*/,
             new HashVerificationFilter(hmac2,
                                        new 
StreamTransformationFilter(decryptor,
                                            new StringSink(recover)),
                                        HASH_AT_END | PUT_MESSAGE,
                                        DIGEST_SIZE));

cout << recover << endl;  

On Friday, April 3, 2015 at 6:59:19 PM UTC-4, Maricel Gregoraschko wrote:
>
>
>  
> Hi,
> I need to encrypt a stream (with a symmetric algorithm) and compute its 
> HMAC at the same time. Is there an easy way to do that in crypto++, without 
> going through it twice, short of reading and feeding the file manually into 
> the two filters? In Botan you do it with the Fork class. Thanks!
>
>  

-- 
-- 
You received this message because you are subscribed to the "Crypto++ Users" 
Google Group.
To unsubscribe, send an email to [email protected].
More information about Crypto++ and this group is available at 
http://www.cryptopp.com.
--- 
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].
For more options, visit https://groups.google.com/d/optout.

Reply via email to