AadSource

From Crypto++ Wiki
Jump to navigation Jump to search

AadSource is a quick and dirty implementation that allows you to pump both aad data and confidential data to an AuthenticatedEncryptionFilter or AuthenticatedDecryptionFilter. The source can be used with authenticated encryption modes like CCM, EAX and GCM.

Crypto++ 8.2 and earlier had a bug in AuthenticatedDecryptionFilter where using a FileSource would cause an exception; but a StringSource was OK. The bug was fixed at Commit ff110c6e183e. Also see Issue 817.

AadSource

The source code for the AadSource is shown below. It overrides the required members of Source. However, it lacks an IsolatedInitialize to reinitialize the object.

$ cat aad_source.cxx
#include "cryptlib.h"
#include "filters.h"

NAMESPACE_BEGIN(CryptoPP)

class AadSource : public Source
{
public:
    AadSource(BufferedTransformation *attachment = NULLPTR);
    AadSource(Source& aad, Source& data, bool PumpAll, BufferedTransformation *attachment = NULLPTR);

    virtual size_t Pump2(lword &byteCount, bool blocking=true);
    virtual size_t PumpAll2(bool blocking=true);
    virtual size_t PumpMessages2(unsigned int &messageCount, bool blocking=true);
    virtual bool SourceExhausted() const;

private:
    Source *m_aad, *m_data;
};

AadSource::AadSource(BufferedTransformation *attachment)
    : Source(attachment), m_aad(NULLPTR), m_data(NULLPTR), m_headerSet(false)
{
}

AadSource::AadSource(Source& aad, Source& data, bool pumpAll, BufferedTransformation *attachment)
    : Source(attachment), m_aad(&aad), m_data(&data), m_headerSet(false)
{
    if (pumpAll)
        PumpAll();
}

size_t AadSource::Pump2(lword &byteCount, bool blocking)
{
    lword transferCount, blockedBytes;

    transferCount = std::min(byteCount, m_aad->MaxRetrievable());
    blockedBytes = 0;

    if (transferCount)
    {
        blockedBytes = m_aad->TransferTo2(*AttachedTransformation(), transferCount, AAD_CHANNEL, blocking);
        byteCount -= transferCount - blockedBytes;
    }

    if (blockedBytes != 0)
        return blockedBytes;

    if (m_aad->SourceExhausted())
        AttachedTransformation()->ChannelMessageEnd(AAD_CHANNEL);

    transferCount = std::min(byteCount, m_data->MaxRetrievable());
    blockedBytes = 0;

    if (transferCount)
    {
        blockedBytes = m_data->TransferTo2(*AttachedTransformation(), transferCount, DEFAULT_CHANNEL, blocking);
        byteCount -= transferCount - blockedBytes;
    }

    if (blockedBytes != 0)
        return blockedBytes;

    if (m_data->SourceExhausted())
        AttachedTransformation()->ChannelMessageEnd(DEFAULT_CHANNEL);

    return byteCount;
}

size_t AadSource::PumpAll2(bool blocking)
{
    lword transferCount, blockedBytes;

    transferCount = m_aad->MaxRetrievable();
    blockedBytes = 0;

    if (transferCount)
    {
        blockedBytes = m_aad->TransferTo2(*AttachedTransformation(), transferCount, AAD_CHANNEL, blocking);
    }

    if (blockedBytes != 0)
        return blockedBytes;

    if (m_aad->SourceExhausted())
        AttachedTransformation()->ChannelMessageEnd(AAD_CHANNEL);

    transferCount = m_data->MaxRetrievable();
    blockedBytes = 0;

    if (transferCount)
    {
        blockedBytes = m_data->TransferTo2(*AttachedTransformation(), transferCount, DEFAULT_CHANNEL, blocking);
    }

    if (blockedBytes != 0)
        return blockedBytes;

    if (m_data->SourceExhausted())
        AttachedTransformation()->ChannelMessageEnd(DEFAULT_CHANNEL);

    return 0;
}

size_t AadSource::PumpMessages2(unsigned int &messageCount, bool blocking)
{
    size_t blockedBytes = 0;

    if (messageCount)
        blockedBytes = m_aad->TransferMessagesTo2(*AttachedTransformation(), messageCount, AAD_CHANNEL, blocking);

    if (blockedBytes != 0)
        return blockedBytes;

    if (m_aad->SourceExhausted())
        AttachedTransformation()->ChannelMessageEnd(AAD_CHANNEL);

    if (messageCount)
        blockedBytes = m_data->TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);

    if (blockedBytes != 0)
        return blockedBytes;

    if (m_data->SourceExhausted())
        AttachedTransformation()->ChannelMessageEnd(DEFAULT_CHANNEL);

    return 0;
}

bool AadSource::SourceExhausted() const
{
    return m_aad->SourceExhausted() && m_data->SourceExhausted();
}

NAMESPACE_END

StringSources

The code below uses two StringSources. The first is for aad data, and the second is for confidential data. confidential data is encrypted and authenticated. aad is authenticated only.

All the rules of pumping data apply. Note the StringSources set pumpAll=true (the second argument in the constructor). If pumpAll=false, then MaxRetrievable()==0. If pumpAll=false, then there is no data to encrypt or authenticate.

std::string HexEncode(const std::string& str)
{
    using namespace CryptoPP;

    std::string ret;
    StringSource(str, true, new HexEncoder(new StringSink(ret)));
    return ret;
}

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

    std::string aad = "unique public data";
    std::string plain = "super secret data";
    std::string cipher, recover;

    SecByteBlock key(32), iv(16);
    std::memset(key, 0x00, key.size());
    std::memset( iv, 0x00,  iv.size());

    EAX<AES>::Encryption enc;
    enc.SetKeyWithIV(key, key.size(), iv, iv.size());

    StringSource s1(aad, true);
    StringSource s2(plain, true);
    AuthenticatedEncryptionFilter encryptor(enc, new StringSink(cipher));    
    AadSource(s1, s2, true, new Redirector(encryptor));

    EAX<AES>::Decryption dec;
    dec.SetKeyWithIV(key, key.size(), iv, iv.size());

    StringSource s3(aad, true);
    StringSource s4(cipher, true);
    AuthenticatedDecryptionFilter decryptor(dec, new StringSink(recover));    
    AadSource(s3, s4, true, new Redirector(decryptor));

    std::cout << "AAD: " << aad << std::endl;
    std::cout << "Plain: " << plain << std::endl;
    std::cout << "Cipher: " << HexEncode(cipher) << std::endl;
    std::cout << "Recover: " << recover << std::endl;

    return 0;
}

Running the program results in the following using AES/EAX authenticated encryption mode.

$ ./test.exe
AAD: unique public data
Plain: super secret data
Cipher: DF43F5E6CFC0727F580140D1376F37A4AE2FB0DEED82C0641085F76537A0FB1574
Recover: super secret data

FileSource

The code below uses a FileSource and a StringSource. The FileSource is for aad data, and the StringSource is for confidential data. confidential data is encrypted and authenticated. aad is authenticated only.

The AAD requires some random data larger than 4K. The command below creates a 16KB file of binary data. 4K is significant because it is the "chunk size" used by the library. That is, the library pumps in chunks of 4KB blocks.

All the rules of pumping data apply. Note the StringSource and FileSource set pumpAll=true (the second argument in the constructors). If pumpAll=false, then MaxRetrievable()==0. If pumpAll=false, then there is no data to encrypt or authenticate.

$ head -c 16384 /dev/urandom > aad.bin

$ hexdump -C aad.bin
00000000  ee 10 82 70 d7 2a 55 5d  e8 4b 92 fb 29 59 0c d7  |...p.*U].K..)Y..|
00000010  c4 67 1d 58 b1 ee 5c ea  25 7f 79 bb b4 c1 fe 77  |.g.X..\.%.y....w|
00000020  95 d7 f3 d8 ff f0 be 9a  09 d8 f7 d8 8f fc 51 0b  |..............Q.|
...
00003fd0  7d e1 7c 4c 91 b1 f9 94  c9 d9 e0 00 fa 07 dc 28  |}.|L...........(|
00003fe0  73 5d 55 36 d9 5a 1d 50  24 3a 7a fd ea 91 51 97  |s]U6.Z.P$:z...Q.|
00003ff0  ce 53 65 57 f0 9e 3b fe  95 ee dc 14 62 95 77 ff  |.SeW..;.....b.w.|

Then, use the FileSource as follows. The aad data is not printed since it is a large binary file.

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

    std::string aad_file = "aad.bin";
    std::string plain = "super secret data";
    std::string cipher, recover;

    SecByteBlock key(32), iv(16);
    std::memset(key, 0x00, key.size());
    std::memset( iv, 0x00,  iv.size());

    EAX<AES>::Encryption enc;
    enc.SetKeyWithIV(key, key.size(), iv, iv.size());

    FileSource s1(aad_file.c_str(), true);
    StringSource s2(plain, true);
    AuthenticatedEncryptionFilter encryptor(enc, new StringSink(cipher));
    AadSource(s1, s2, true, new Redirector(encryptor));

    EAX<AES>::Decryption dec;
    dec.SetKeyWithIV(key, key.size(), iv, iv.size());

    FileSource s3(aad_file.c_str(), true);
    StringSource s4(cipher, true);
    AuthenticatedDecryptionFilter decryptor(dec, new StringSink(recover));
    AadSource(s3, s4, true, new Redirector(decryptor));

    std::cout << "Plain: " << plain << std::endl;
    std::cout << "Cipher: " << HexEncode(cipher) << std::endl;
    std::cout << "Recover: " << recover << std::endl;

    return 0;
}

Running the program results in the following output. The encryption of confidential data is the same as the previous example, but the MAC is different due to the random AAD. The encrypted data is DF43F5E6CFC0727F580140D1376F37A4AE.

$ ./test.exe
Plain: super secret data
Cipher: DF43F5E6CFC0727F580140D1376F37A4AED0291903128B9389F66C4D508A519A45
Recover: super secret data