Base32HexDecoder
Documentation |
#include <cryptopp/base32.h>
|
The Base32HexDecoder converts base 32 encoded data into binary data. Base32HexDecoder
uses the extended hex alphabet specified in RFC 4648, The Base16, Base32, and Base64 Data Encodings. The partner encoder is a Base32HexEncoder.
The Base32HexEncoder
and Base32HexDecoder
alphabet is 0123456789ABCDEFGHIJKLMNOPQRSTUV
. 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 Base32HexDecoder
takes a pointer to a BufferedTransformation
. Because a pointer is taken, the Base32HexDecoder
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 decoder, like a Base32Decoder
instead of a Base32HexDecoder
, then the mischosen decoder will silently skip unrecognized characters.
Documentation |
#include <cryptopp/base32.h>
|
Construction
Base32HexDecoder (BufferedTransformation *attachment=NULL)
attachment
is a BufferedTransformation, such as another filter or sink. If attachment
is NULL
, then the Base32HexDecoder
object will internally accumulate the output byte stream.
Sample Programs
The following is a collection of sample programs to demonstrate using the Base32HexDecoder
.
Decoding a String (Non-Filter)
The following demonstrates decoding a string using Put
and Get
.
string encoded = "VVNDRJ5RLACOGTR6AL2368GH00"; string decoded; Base32HexDecoder 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[0], decoded.size()); }
Note that Get
used &decoded[0]
. It is the C++ way to get the non-const pointer to the string's data from the string.
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 as shown below by taking advantage of Crypto++'s pipeline design.
string encoded = "VVNDRJ5RLACOGTR6AL2368GH00"; string decoded; StringSource ss(encoded, true, new Base32HexDecoder( new StringSink(decoded) ) // Base32HexDecoder ); // 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 = "VVNDRJ5RLACOGTR6AL2368GH00"; string decoded; Base32HexDecoder 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 Base64Encoder alphabet from the original to a web safe alphabet. The web safe alphabet is used by Base64URLEncoder and Base64URLDecoder.
// Encoder Base64Encoder encoder; const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET); encoder.IsolatedInitialize(params); // Decoder int lookup[256]; const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; Base32HexDecoder::InitializeDecodingLookupArray(lookup, ALPHABET, 64, false); Base32HexDecoder decoder; AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup); decoder.IsolatedInitialize(params);
Missing Padding
The Base32HexDecoder
is very tolerant, and it will happily decode an encoded string without padding characters.
string encoded = "VVNDRJ5RLACOGTR6AL2368GH00"; string decoded; Base32HexDecoder 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[0], decoded.size()); }
Note that Get
used &decoded[0]
. It is the C++ way to get the non-const pointer to the string's data from the string.
The program above will produce expected results:
(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 = 0x1004039f8 "???̻???wfUD3\"\021" } } (gdb) x/16b 0x1004039f8 0x1004039f8: 0xff 0xee 0xdd 0xcc 0xbb 0xaa 0x99 0x88 0x100403a00: 0x77 0x66 0x55 0x44 0x33 0x22 0x11 0x00
Wrong Decoder
Decoders skip characters that are not in the particular alphabet. If you incorrectly choose a Base64URLDecoder
instead of a Base32HexDecoder
, then the mischosen decoder will silently skip unrecognized characters. For example:
byte raw[] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 }; string encoded, decoded; StringSource ss1(raw, sizeof(raw), true, new Base64Encoder( new StringSink(encoded) ) // Base64Encoder ); // StringSource StringSource ss2(encoded, true, new Base64URLDecoder( new StringSink(decoded) ) // Base32HexDecoder ); // StringSource
Running the program produces the following results:
(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 = 0x100403d88 "??˺???veTC2!\020" } } (gdb) x/16b 0x100403d88 0x100403d88: 0xed 0xdc 0xcb 0xba 0xa9 0x98 0x87 0x76 0x100403d90: 0x65 0x54 0x43 0x32 0x21 0x10 0x00 0x00
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
In the case of a Base64 encoder, the filter will buffer the first two octets while waiting on a third 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