Base64URLEncoder
Documentation |
#include <cryptopp/base64.h>
|
The Base64URLEncoder encodes bytes into URL or filename safe character strings. The alphabet is specified in RFC 4648, The Base16, Base32, and Base64 Data Encodings. The class is also helpful for web technologies, like JSON Web Encryption (JWE) and and JSON Web Keys (JWK). The partner decoder is a Base64URLDecoder.
The Base64URLEncoder
and Base64URLDecoder
alphabet is ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_
. It is a case sensitive alphabet. Notice the use of -
and _
. 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 Base32Encoder.
The Base64URLEncoder
takes a pointer to a BufferedTransformation
. Because a pointer is taken, the Base64URLEncoder
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 choose the wrong encoder, like a Base64Encoder
instead of a Base64URLEncoder
, then the mischosen decoder will silently skip unrecognized characters.
Note well: this class was added to Crypto++ at version 5.6.3 (SVN,GitHub). If using a downlevel version of the library, then you must download and apply the patch below.
Documentation |
#include <cryptopp/base64.h>
|
Construction
Base64URLEncoder(BufferedTransformation *attachment = NULL, bool insertLineBreaks = false, int maxLineLength = -1)
attachment
is a BufferedTransformation, such as another filter or sink. If attachment
is NULL
, then the Base64URLEncoder
object will internally accumulate the output byte stream.
insertLineBreaks
determines if the encoder should add line breaks.
maxLineLength
is the length of a line if insertLineBreaks
is true
. If insertLineBreaks
is false
, then the class discards maxLineLength
and sets it to 0.
Sample Programs
The following is a small collection of sample programs to demonstrate using the Base64URLEncoder
.
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; Base64URLEncoder 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 _-7dzLuqmYh3ZlVEMyIRAA==
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 Base64URLEncoder( new StringSink(encoded) ) // Base64URLEncoder ); // StringSource cout << encoded << endl;
As with the previous example, a run produces the following output.
$ ./cryptopp-test.exe _-7dzLuqmYh3ZlVEMyIRAA==
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; Base64URLEncoder 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.
Disabling Padding
The following program disables padding and line breaks from a Base64URLEncoder
. You have to use NameValuePairs
in this case because there is no way to disable padding through the constructor. If the use of MakeParameters
does not quite look right (it does not), then visit NameValuePairs
for a discussion.
using CryptoPP::Name::Pad; using CryptoPP::Name::InsertLineBreaks; byte raw[] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 }; string encoded, hexed; Base64URLEncoder encoder; AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false); encoder.IsolatedInitialize(params); encoder.Attach(new StringSink( encoded )); ArraySource as(raw, sizeof(raw), true, new Redirector(encoder)); cout << encoded << endl; StringSource ss(encoded, true, new Base64URLDecoder(new HexEncoder(new StringSink(hexed)))); cout << hexed << endl;
In the code above, the Base64Encoder
constructor sets up a standard object. Then the parameters are tuned for this particular use. In this case, the use is (1) no padding and (2) no line breaks.
The call to IsolatedInitialize
initializes or reinitializes the object. Under the covers, Base64URLEncoder
's override of IsolatedInitialize
uses CombinedNameValuePairs
to blend the library's default parameters with the caller's parameters (the caller's parameter's are preferred). That means parameters like the encoding alphabet will always be present so a caller does not have to specify it again (see base64.cpp).
A run of the program produces the following. The padding is not added to the tail of the encoded data (which would be ...VEMyIRAA==
).
$ ./cryptopp-test.exe _-7dzLuqmYh3ZlVEMyIRAP_u3cy7qpmId2ZVRDMiEQD_7t3Mu6qZiHdmVUQzIhEA_-7dzLuqmYh3ZlVEMyIRAA FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100
Changing Alphabets
The following program changes the Base64URLEncoder alphabet from a web safe alphabet to the original alphabet. The original alphabet is used by Base64Encoder and Base64Decoder.
// Encoder Base64URLEncoder encoder; const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET); encoder.IsolatedInitialize(params); // Decoder int lookup[256]; const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; Base64Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 64, false); Base64URLDecoder 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 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
Downloads
Base64.zip - Updated base64.h and base64.cpp to add a Base64URLEncoder and Base64URLDecoder class.