HexDecoder
Documentation |
#include <cryptopp/hex.h>
|
The HexDecoder converts base 16 encoded data to bytes. The partner encoder is a HexEncoder.
The HexEncoder
and HexDecoder
alphabet is 0123456789ABCDEF
. The decoder accepts both uppercase and lowercase values. The decoder ignores characters not in the alphabet.
The HexDecoder
takes a pointer to a BufferedTransformation
. Because a pointer is taken, the HexDecoder
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 HexEncoder
, then the decoder will silently skip unrecognized characters.
Construction
HexDecoder (BufferedTransformation *attachment=NULL)
attachment
is a BufferedTransformation, such as another filter or sink. If attachment
is NULL
, then the HexDecoder
object will internally accumulate the output byte stream.
Hex Formats
A HexDecoder can parse many formats, including colon, comma, and whitespace delimited. Each of the example strings below will decode correctly using a HexDecoder.
string str1 = "FF, EE, DD, CC, BB, AA, 99, 88, 77, 66, 55, 44, 33, 22, 11, 00"; string str2 = "FF EE DD CC BB AA 99 88 77 66 55 44 33 22 11 00"; string str3 = "FF:EE:DD:CC:BB:AA:99:88:77:66:55:44:33:22:11:00"; string str4 = "FFEEDDCCBBAA99887766554433221100";
The HexDecoder cannot parse a string with a prefix or a suffix. For example, the string "0xFF 0xEE" will incorrectly parse to the bytes 0x0F, 0xF0, 0x0E, 0xE0 because the leading 0 in 0x is used as a hex digit instead of a prefix.
Sample Programs
The following is a small collection of sample programs to demonstrate using the HexDecoder
.
Decoding a String (Non-Filter)
The following demonstrates decoding a string using Put
and Get
.
string encoded = "FFEEDDCCBBAA99887766554433221100"; string decoded; HexDecoder 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.
Breakpoint 1, main (argc=1, argv=0x7fffffffe398) at cryptopp-test.cpp:44 (gdb) p encoded $1 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x60c078 "FFEEDDCCBBAA99887766554433221100"}} (gdb) p decoded $2 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x60c868 "\377\356\335̻\252\231\210wfUD3\"\021"}} (gdb) x/16b 0x60c868 0x60c868: 0xff 0xee 0xdd 0xcc 0xbb 0xaa 0x99 0x88 0x60c870: 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 = "FFEEDDCCBBAA99887766554433221100"; string decoded; StringSource ss(encoded, true, new HexDecoder( new StringSink(decoded) ) // HexDecoder ); // 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 = "FFEEDDCCBBAA99887766554433221100"; string decoded; HexDecoder 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.
Scripting and Strings
On occasion, the mailing list will receive questions on cross-validation. For example, see AES CTR Chiper. Different output between PHP-mcrypt and Crypto++. In the question, PHP-mcrypt strings are used as follows:
$key = "1234567890123456789012345678901234567890123456789012345678901234"; $key = pack("H".strlen($key), $key); $iv = "1111111111222222222233333333334444444444555555555566666666667777"; $iv = pack("H".strlen($iv), $iv);
One of the easiest ways to avoid typos is via Copy/Paste and a HexDecoder:
string encodedKey = "1234567890123456789012345678901234567890123456789012345678901234"; string encodedIv = "1111111111222222222233333333334444444444555555555566666666667777"; string key, iv; StringSource ssk(encodedKey, true /*pumpAll*/, new HexDecoder( new StringSink(key) ) // HexDecoder ); // StringSource StringSource ssv(encodedIv, true /*pumpAll*/, new HexDecoder( new StringSink(iv) ) // HexDecoder ); // StringSource
After running the above code, key and iv are hexadecimal (i.e., binary) strings rather than printable (i.e., ASCII) strings. The binary strings can be examined using GDB's x
command.
(gdb) p key $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 = 0x100403c18 "\0224Vx?\0224Vx?\0224Vx?\0224Vx?\0224Vx?\0224Vx?\0224" } } (gdb) x/16b 0x100403c18 0x100403c18: 0x12 0x34 0x56 0x78 0x90 0x12 0x34 0x56 0x100403c20: 0x78 0x90 0x12 0x34 0x56 0x78 0x90 0x12 (gdb) p iv $2 = { 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 = 0x100403cf8 "\021\021\021\021\021\"\"\"\"\"33333DDDDDUUUUUfffffww" } } (gdb) x/16b 0x100403cf8 0x100403cf8: 0x11 0x11 0x11 0x11 0x11 0x22 0x22 0x22 0x100403d00: 0x22 0x22 0x33 0x33 0x33 0x33 0x33 0x44
Finally, the strings key and iv can be used with Encryption or Decryption objects as follows.
CTR_Mode< AES >::Encryption enc; enc.SetKeyWithIV(key.data(), key.size(), iv.data());
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