Base32Decoder

From Crypto++ Wiki
Jump to: navigation, search

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

The Base32Decoder 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.

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.


Base32Decoder
Documentation
#include <cryptopp/base32.h>

Construction

Base32Decoder (BufferedTransformation *attachment=NULL)

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

Base32 Formats

A Base32Decoder can parse many formats, including colon, comma, and whitespace delimited. Each of the example strings below will decode correctly using a Base32Decoder.

string str1 = "99ZP:5VF5:XKN2:S75G:KXCD:GIST";
string str2 = "99ZP 5VF5 XKN2 S75G KXCD GIST";
string str3 = "99ZP5VF5XKN2S75GKXCDGIST";

Sample Programs

The following is a small collection of example to demonstrate using the Base32Decoder.

Decoding a String (Non-Filter)

The following demonstrates decoding a string using Put and Get.

string encoded = "99ZP5VF5XKN2S75GKXCDGISTAA";
string decoded;
   
Base32Decoder decoder;

decoder.Put( (byte*)encoded.data(), encoded.size() );
decoder.MessageEnd();

word64 size = decoder.MaxRetrievable();
if(size && size <= SIZE_MAX)
{
    decoded.resize(size);		
    decoder.Get((byte*)decoded.data(), decoded.size());
}

Running the program under GDB shows the binary string contained in decoded.

(gdb) p decoded 
$1 = {
  static npos = <optimized out>, 
  _M_dataplus = {
    <std::allocator<char>> = {
      <__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
    members of std::basic_string<char>::_Alloc_hider: 
    _M_p = 0x100403a08 "???̻???wfUD3\"\021"
  }
}
(gdb) x/16b 0x100403a08
0x100403a08:	0xff	0xee	0xdd	0xcc	0xbb	0xaa	0x99	0x88
0x100403a10:	0x77	0x66	0x55	0x44	0x33	0x22	0x11	0x00

Decoding a String (Filter)

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

string encoded = "99ZP5VF5XKN2S75GKXCDGISTAA";
string decoded;
   
StringSource ss(encoded,
    new Base32Decoder(
        new StringSink(decoded)
    ) // Base32Decoder
); // StringSource

Attaching a BufferedTransformation

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

string encoded = "99ZP5VF5XKN2S75GKXCDGISTAA";
string decoded;
   
Base32Decoder decoder;
 
decoder.Attach( new StringSink( decoded ) );
decoder.Put( (byte*)encoded.data(), encoded.size() );
decoder.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);

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