ArraySource
Documentation |
#include <cryptopp/filters.h>
|
An ArraySource, introduced in version 5.6 of Crypto++, is a source for byte arrays. An ArraySource
is typedef'd from a StringSource
third constructor. Prior to version 5.6 of the library, use a StringSource
.
An ArraySource
functions like any other source in the library, including a FileSource
and StringSource
.
Constructor
ArraySource (const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment=NULL)
string
is a byte array.
length
is the length of the byte array.
pumpAll
is a boolean value indicating if the ArraySource
should pump all of the data immediately to its attached transformation.
attachment
is a BufferedTransformation, such as another filter or sink.
Sample Program
Below is an example of using ArraySource and ArraySink. 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; }
Missing Data
Its not uncommon to experience Missing Data in a pipeline. A source will send data through a pipeline but have nothing in the sink. This is usually due to the compiler matching the wrong function. For example:
string source = "FF 88 00", destination; StringSink ss(source, new HexDecoder( new StringSink(destination) ) // HexDecoder ); // StringSink
After the above code executes, destination
will likely be empty because the compiler coerces the HexDecoder
(the pointer) to a bool
(the pumpAll
parameter), which leaves the StringSource
's attached transformation NULL
. The compiler will do so without warning, even with -Wall -Wextra -Wconversion
. To resolve the issue, explicitly specify the pumpAll
parameter:
string source = "FF 88 00", destination; StringSink ss(source, true /*pumpAll*/, new HexDecoder( new StringSink(destination) ) // HexDecoder ); // StringSink
Another way data ends up missing is failing to call MessageEnd()
when pumping data. For example, the following may not produce expected results:
// The 4-bit nibble will be buffered waiting for another nibble string source = "FF 88 0", destination; HexDecoder decoder(new StringSink(destination)); decoder.Put(source.data(), source.size()); // Do something with destination
Be sure to call MessageEnd()
when data comes up missing:
string source = "FF 88 0", destination; HexDecoder decoder(new StringSink(destination)); decoder.Put(source.data(), source.size()); decoder.MessageEnd(); // Do something with destination