ArraySink

From Crypto++ Wiki
Jump to navigation Jump to search
ArraySink
Documentation
#include <cryptopp/filters.h>

An ArraySink, introduced in version 5.6 of Crypto++, is a sink for byte arrays. An ArraySink is typedef'd from a StringSink's third constructor. Prior to version 5.6 of the library, use a StringSink.

An ArraySink functions like any other sinks in the library, including a FileSink and StringSink. However, since an array is fixed size, the ArraySink will effectively discard data once the array is full. The sink will signal the array is full by returning non-0 after a call to Put or Put2. Also see How to use Shamir's Secret Sharing to securely divide in memory byte blobs and then disperse the shares over network on the Crypto++ mailing list.

Sources, filters and sinks are discussed at Pipelining. The pipeline article explains the design and shows you how to use them.

Constructor

ArraySink (byte *buffer,
           size_t size)

buffer is a byte array.

size is the length of the byte array.

Sample Programs

Below is an example of storing Adler32 digest in a std::array using a pipeline.

Adler32 hash;
std::array<byte, Adler32::DIGESTSIZE> output;
StringSource ss("Wikipedia", true,
                   new HashFilter( hash, 
                       new ArraySink(output.data(), Adler32::DIGESTSIZE)
                   )
               );

for(auto &it: output)
{
    std::cout << std::hex << (int)it << " ";
}

The output is shown below.

11 E6 03 98

If you overcommit the size of the array, then you can get the size of the bytes written to the array with the following. Notice three things. First, a stack based ArraySink was used. Second, TotalPutLength was used to determine how many bytes were written to the array. Third, a Redirector was used to stop ownership so the ArraySink would survive to allow the call to TotalPutLength.

Adler32 hash;
byte output[1024];
ArraySink as(output, sizeof(output));

StringSource ss("Wikipedia", true,
                   new HashFilter( hash, 
                       new Redirector(as)
                   )
               );

for(size_t i = 0; i < as.TotalPutLength(); i++)
{
    std::cout << std::hex << (int)output[i] << " ";
}

Below is another example of using ArraySource and ArraySink in a pipeline. The Redirector ensures the ArraySink survives so you can call TotalPutLength.

#include <iostream>
#include <string>
using namespace std;

#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "modes.h"
#include "hex.h"
#include "aes.h"
using namespace CryptoPP;

int main(int argc, char* argv[])
{
  byte key[AES::MAX_KEYLENGTH];
  byte iv[AES::BLOCKSIZE];
  vector<byte> plain, cipher, recover;
  HexEncoder encoder(new FileSink(cout));

  memset(key, 0x00, sizeof(key));
  memset(iv, 0x00, sizeof(iv));

  string str("Attack at dawn!");
  std::copy(str.begin(), str.end(), std::back_inserter(plain));

  cout << "Plain text: ";
  encoder.Put(plain.data(), plain.size());
  encoder.MessageEnd();
  cout << endl;

  /////////////////////////////////////////////////////////////

  CBC_Mode<AES>::Encryption enc;
  enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

  // Make room for padding
  cipher.resize(plain.size()+AES::BLOCKSIZE);
  ArraySink cs(&cipher[0], cipher.size());

  ArraySource(plain.data(), plain.size(), true,
    new StreamTransformationFilter(enc, new Redirector(cs)));

  // Set cipher text length now that its known
  cipher.resize(cs.TotalPutLength());

  cout << "Cipher text: ";
  encoder.Put(cipher.data(), cipher.size());
  encoder.MessageEnd();
  cout << endl;

  /////////////////////////////////////////////////////////////

  CBC_Mode<AES>::Decryption dec;
  dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

  // Recovered text will be less than cipher text
  recover.resize(cipher.size());
  ArraySink rs(&recover[0], recover.size());

  ArraySource(cipher.data(), cipher.size(), true,
    new StreamTransformationFilter(dec, new Redirector(rs)));

  // Set recovered text length now that its known
  recover.resize(rs.TotalPutLength());

  cout << "Recovered text: ";
  encoder.Put(recover.data(), recover.size());
  encoder.MessageEnd();
  cout << endl;

  return 0;
}