Base32Encoder

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

The Base32Encoder encodes bytes into base 32 characters. The alphabet is specified in Differential Unicode Domain Encoding (DUDE). Unlike RFC 4648, DUDE does not use a pad character. The partner decoder is a Base32Decoder.

The Base32Encoder and Base32Decoder alphabet is ABCDEFGHIJKMNPQRSTUVWXYZ23456789. The decoder accepts both uppercase and lowercase values. The decoder ignores characters not in the alphabet.

If you need a different alphabet then you have three choices. First, you can visit the Category:Encoder page and see if the encoder already exists. Second, you can swap-in a different alphabet as detailed in Changing Alphabets. Third, you can create a new encoder based on an existing one, like Base64Encoder.

The Base32Encoder takes a pointer to a BufferedTransformation. Because a pointer is taken, the Base32Encoder owns the attached transformation, and therefore will destroy it. See ownership for more details.

If you need an encoder for web safe URLs and filenames, then see Base64URLEncoder.

Note well: decoders skip characters that are not in the particular alphabet. If you incorrectly choose the wrong encoder, like a Base64Encoder instead of a Base32Encoder, then the mischosen decoder will silently skip unrecognized characters.


Base32Encoder
Documentation
#include <cryptopp/base32.h>

Construction

Base32Encoder (BufferedTransformation *attachment=NULL,
               bool uppercase=true,
               int outputGroupSize=0,
               const std::string &separator=":",
               const std::string &terminator="")

attachment is a BufferedTransformation, such as another filter or sink. If attachment is NULL, then the Base32Encoder object will internally accumulate the output byte stream.

uppercase specifies whether the encoder should output uppercase (true) or lowercase (case) encodings.

outputGroupSize is an output formatting option and determines the number of hexadecimal digit groups. For example, if outputGroupSize = 4, then an output string is formatted as "99ZP:5VF5:XKN2:S75G:KXCD:GIST".

separator is a string used as a delimiter. The default is a colon, and a space (with a grouping of 4) will format the string as "99ZP 5VF5 XKN2 S75G KXCD GIST".

terminator appends the string to the output.

Sample Programs

The following is a small collection of sample programs to demonstrate using the Base32Encoder.

Encoding a Binary String (Non-Filter)

The following demonstrates decoding a string using Put and Get.

byte decoded[] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 };
string encoded;

Base32Encoder encoder;
encoder.Put(decoded, sizeof(decoded));
encoder.MessageEnd();

word64 size = encoder.MaxRetrievable();
if(size)
{
    encoded.resize(size);		
    encoder.Get((byte*)&encoded[0], encoded.size());
}

cout << encoded << endl;

Note that Get used &encoded[0]. It is the C++ way to get the non-const pointer to the string's data from the string.

A run of the above program produces the following output.

$ ./cryptopp-test.exe
99ZP5VF5XKN2S75GKXCDGISTAA

Encoding a Binary String (Filter)

Encoding a String (Non-Filter) performed a Put/Get sequence to transform the data. Crypto++ offers filters, which can simplify the process as shown below by taking advantage of Crypto++'s pipeline design.

byte decoded[] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 };
string encoded;

StringSource ss(decoded, sizeof(decoded), true,
    new Base32Encoder(
        new StringSink(encoded)
    ) // Base32Encoder
); // StringSource

cout << encoded << endl;

As with the previous example, a run produces the following output.

$ ./cryptopp-test.exe
99ZP5VF5XKN2S75GKXCDGISTAA

Attaching a BufferedTransformation

Sometimes its advantageous to attach (or change an attached) BufferedTransformation on the fly. The code below attaches a StringSink at runtime.

byte decoded[] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 };
string encoded;
   
Base32Encoder encoder;
 
encoder.Attach( new StringSink( encoded ) );
encoder.Put( decoded, sizeof(decoded) );
encoder.MessageEnd();

Attach 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.

Changing Alphabets

The following program changes the Base32Encoder alphabet from DUDE to RFC 4648 alphabet.

// Encoder
Base32Encoder encoder;
const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
encoder.IsolatedInitialize(params);

// Decoder
int lookup[256];
const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
Base64Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 32, true);

Base32Decoder decoder;
AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
decoder.IsolatedInitialize(params);

A more detailed example is provided in validat1.cpp in the test files. It creates a new encoder called MyEncoder with a MyDecoder class.

Missing Data

Its not uncommon to send data through a pipeline and then 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

In the case of a Base32 encoder, the filter will buffer the first three octets while waiting on a fourth octet. 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