Filter
Documentation |
#include <cryptopp/filters.h>
|
In the Pipelining paradigm, a Filter is an object which transform data. Filters are derived from a BufferedTransformation
. At the beginning of a filter chain is a Source, and at end of a filter chain is a Sink.
Sources, filters and sinks are discussed at Pipelining. The pipeline article explains the design and shows you how to use them.
Constructor
Filter (BufferedTransformation *attachment=NULL)
attachment
is a BufferedTransformation
, such as another Filter or a Sink. If attachment
is NULL
, then the Filter
object will internally accumulate the output byte stream.
A pointer to an attached object becomes owned by the attached-to object. The attached object will automatically be freed when the attached-to object is destructed. See ownership for details.
If no attachment
is specified when constructing an object derived from filter, or if a null pointer is used, then a default MessageQueue
created to accumulate the output byte stream.
Methods
Attach
Attaches a new transformation to the object and returns the previous attached transformation. The caller is responsible for deleting the previous filter if its non-NULL. If you want to attach a new transformation and delete the current one, then use the Detach
method. Detach
will free the currently attached filter, and add the new transformation.
Detach
Deletes the current attachment, destructing and freeing all objects it consists of; then, attaches the specified object. If a null pointer is passed, an attachment object of the default type is created.
Attachable
To distinguish between a filter and a BufferedTransformation
object, call its Attachable
method. If the object is a filter, the method will return true; if it is a BufferedTransformation
, it will return false.
AttachedTransformation
Returns a pointer to the currently attached transformation object. AttachedTransformation
should never be null because a MessageQueue
is used internally to buffer the output stream if no attached is present.
Sample Programs
Source to Sink
The first sample is very basic: the contents of the first string are placed in second string. In this case, there is no filter in the pipeline. Note that the source (s1) is not drained. That is, s1 will still have the value of 'Filter'.
string s1 = "Filter", s2; StringSource(s1, new StringSink(s2)); cout << s2 << endl;
Output: Filter
ArraySource and HexEncoder
The second sample adds a ArraySource
and HexEncoder
to the pipeline. In versions prior to Crypto++ 5.6, use a StringSource
instead of an ArraySource
.
byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; string encoded; ArraySource as(data, sizeof(data), true, new HexEncoder( new StringSink(encoded) ) );
Redirector
The third sample uses a Redirector
. A Redirector
will end an attachment chain, but still pass the data it has received to another filter. The behavior is useful when an intermediate result from a filter is required (the filter would otherwise be destroyed, and the result would be lost). Most notable is the DecodingResult
from a HashVerificationFilter
. In this situation, we do not want the StringSource to own the AuthenticatedDecryptionFilter since the StringSource will destroy the filter. To accomplish the task, a Redirector
would be used.
Notice the Redirector
takes a reference to an object, and not a pointer to an object. That's the ownership rule discussed at Pipelining | Ownership.
CCM< AES, TAG_SIZE >::Decryption d; d.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); ... AuthenticatedDecryptionFilter df(d, new StringSink(recovered) ); // AuthenticatedDecryptionFilter // Cipher text includes the MAC tag StringSource ss(cipher, true, new Redirector(df) ); // StringSource // If the object does not throw, here's the only // opportunity to check the data's integrity bool b = df.GetLastResult(); if(b) cout << recovered << endl;
MeterFilter
The fourth sample demonstrates use of a Redirector
and MeterFilter
to count the number of bytes output by the HexEncoder
and subsequently input to the StringSink
.
byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; string encoded; MeterFilter meter(new StringSink(encoded)); ArraySource as(data, sizeof(data), true, new HexEncoder( new Redirector(meter), true /*UCase*/, 2 /*Group*/ ) ); cout << "processed " << meter.GetTotalBytes() << " bytes" << endl; cout << encoded << endl;
Output: Processed 23 bytes
00:01:02:03:04:05:06:07
Recall that the data in the MeterFilter
would not be available if using a stock pipeline since the meter would be destroyed when the ArraySource
destructor was invoked. The following code, which will surreptitiously produce correct results most of the time, is broken. The pointer ot meter
is invalid once the line ArraySource
is destroyed.
// !!!!! Do NOT do this !!!!! MeterFilter* meter = NULL; ArraySource as(data, sizeof(data), true, meter = new MeterFilter( new StringSink(encoded) ) ); cout << "processed " << meter->GetTotalBytes() << " bytes" << endl;
HexEncoder and Attach
The fifth sample attaches a HexEncoder
and then encodes the binary data. The binary data is manually input to the filter using the Put
method. To signal the end of input, MessageEnd
is called.
To format the data for pretty printing, the code below uses " 0x" as a separator. Because "0x" is a separator, the first byte encoded will lack "0x" (there's no need for a separator for the first byte). To work around the behavior, the sink is assigned "0x" before inputting any data.
byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; string encoded = "0x"; HexEncoder encoder(NULL, true, 2, " 0x"); encoder.Attach(new StringSink(encoded)); encoder.Put(data, sizeof(data)); encoder.MessageEnd(); cout << encoded << endl;
Output: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07