Learn how to use Base64 in programming languages: C#, C++, C, Java
, ,

C++ Base64 Guide: Encoding and Decoding Explained (Popular & Simple Libraries)

Similar to C, C++ does not natively support Base64 decoding, so C++ developers working with Base64 decoding have two primary approaches:

  1. External Libraries: Several well-established C++ libraries specialize in Base64 encoding and decoding. These libraries provide user-friendly functions that streamline the process, saving you time and effort compared to manual implementation.
  2. Implementing Your Own Decoder: For developers seeking greater control or customization, writing their own Base64 decoder from scratch is a viable option. This approach requires a deeper understanding of the Base64 algorithm and its underlying principles.

This article will delve into both options, equipping you with the knowledge to leverage external libraries or build your own decoding solution as needed.

What is Base64?

Base64 is a widely utilized encoding method that serves the crucial purpose of converting binary data into a human-readable format. This conversion is particularly essential for seamless data exchange between diverse systems, as binary data, composed of sequences of 0s and 1s, can be challenging to transmit and interpret across different platforms.

Base64 cheat sheet, cheatsheet, infographic

Base64 encoding includes converting binary data, represented as byte sequences, into a set of ASCII letters. This transformation is critical for enabling interoperability with text-based platforms because data is exchanged primarily through human-readable characters. The original binary data is turned into a series of characters that can be easily shared, processed, and interpreted by computers with diverse architectures and data handling mechanisms by using Base64 encoding.

The resulting Base64-encoded data consists of a set of alphanumeric characters, including uppercase and lowercase letters, numerals, and two additional padding characters. This encoding scheme expands the range of data that can be effectively communicated, making it versatile for various applications such as data transmission in emails, storing complex data in XML or JSON files, and supporting secure communication protocols.

What is C++?

C++ is a jack-of-all-trades programming language. Developed as an extension of C, it offers both high-level features for clear program structure and low-level control for efficient memory management. This flexibility makes C++ popular for a wide range of applications.

C++, a versatile and powerful programming language, has found widespread use in various domains of software development. One of its primary applications is in building complex systems software and operating systems that necessitate fine-grained control. Additionally, C++ is a favorite choice for game development and high-performance applications due to its remarkable speed and efficiency.

Base64 Encoding and Decoding in C++

C++ does not natively support Base64 encoding and decoding functions. However, Base64 encoding and decoding can be achieved using standard library functions for character manipulation and arithmetic operations. This approach requires the development of custom code to divide binary data into groups, translate those groups into ASCII characters, and handle padding.

To simplify the process and improve code efficiency, many developers opt for third-party libraries that offer ready-made Base64 encoding and decoding functions. Here are some popular libraries to consider:

  1. Boost C++ Libraries: The Boost C++ Libraries include a base64 module that provides functions for encoding and decoding data. Boost is widely used and well-documented, making it a reliable choice.
  2. OpenSSL: While OpenSSL is primarily known for its cryptography features, it also includes functions for Base64 encoding and decoding. The library is widely used in security-sensitive applications and provides efficient solutions.
  3. Poco C++ Libraries: Poco is another set of C++ libraries that includes a Base64 class, making it easy to perform encoding and decoding operations.

When using third-party libraries, you typically follow these steps:

  1. Include the Library Headers: Include the appropriate header files from the library in your C++ source code using the #include directive.
  2. Linking: If the library is provided as a compiled object file or shared library, you need to link your code with it during the compilation process. Refer to the library’s documentation for specific linking instructions.
  3. Use Library Functions: Once the library is included and linked, you can use its functions to perform Base64 encoding and decoding operations on your data.

Here is a more detailed description.

Example: Base64 Encoding with OpenSSL

OpenSSL is a robust, open-source cryptography library that provides various encryption, decryption, and encoding functionalities, including Base64 encoding and decoding. The following example demonstrates how to use OpenSSL’s BIO functions to encode binary data into Base64 format in C++. The code begins by initializing the necessary variables and BIO objects, then performs the Base64 encoding, and finally outputs the encoded data.

Here’s a basic example in C++ that uses OpenSSL to encode binary data into Base64:

#include <openssl/bio.h>
#include <openssl/evp.h>
 
std::string Base64Encode(const std::string &input) {
    BIO *bio, *b64;
    BUF_MEM *bufferPtr;
 
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
 
    BIO_write(bio, input.c_str(), input.length());
    BIO_flush(bio);
    BIO_get_mem_ptr(bio, &bufferPtr);
 
    std::string encoded(bufferPtr->data, bufferPtr->length);
    BIO_free_all(bio);
 
    return encoded;
}
 
int main() {
    std::string data = "B64Encode.com";
    std::string encoded = Base64Encode(data);
    std::cout << "Encoded: " << encoded << std::endl;
 
    return 0;
}

In this example, the OpenSSL library is used to perform Base64 encoding on the input data. The Base64Encode function takes binary input data and returns its Base64-encoded version.

Example: Base64 Decoding with OpenSSL

Building upon the previous example of Base64 encoding using OpenSSL, the following demonstrates how to decode Base64-encoded data back into its original binary form in C++. The code initializes the necessary variables and BIO objects, performs the Base64 decoding, and finally outputs the decoded data.

#include <openssl/bio.h>
#include <openssl/evp.h>
 
std::string Base64Decode(const std::string &input) {
    BIO *bio, *b64;
    char *buffer = new char[input.size()];
 
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new_mem_buf(input.c_str(), -1);
    bio = BIO_push(b64, bio);
 
    BIO_read(bio, buffer, input.size());
    BIO_free_all(bio);
 
    std::string decoded(buffer);
    delete[] buffer;
 
    return decoded;
}
 
int main() {
    std::string encodedData = "QjY0RW5jb2RlLmNvbQ==";
    std::string decoded = Base64Decode(encodedData);
    std::cout << "Decoded: " << decoded << std::endl;
 
    return 0;
}

In this example, the Base64Decode function decodes a Base64-encoded string into its original binary form using OpenSSL. The function receives the specified encoded string and returns the decoded binary data.

Implementing Base64 Encoding Algorithm in Pseudocode

For those who prefer not to rely on external libraries or want to better understand the inner workings of Base64 encoding and decoding, it is possible to implement these functions yourself. The good news is that Base64 is not a particularly complex method, making it manageable to program in any language.

The following example demonstrates a language-independent technique for implementing Base64 encoding, which can be adapted to any programming language.

If you want more details, this article explains Base64 in more detail.

Here’s an example of a language-agnostic algorithm in pseudocode:

function base64_encode(input)
    // The base character set
    const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 
    // The length of the input
    let input_length = length(input)
 
    // The output
    let output = ""
 
    // Process the input in 3-byte blocks
    for i from 0 to input_length - 1 step 3
        // The value of the block
        let block_value = (input[i] << 16) + (input[i + 1] << 8) + input[i + 2]
 
        // Encode the block into 4 characters
        for j from 0 to 3
            let index = (block_value >> ((3 - j) * 6)) & 0x3F
            output += BASE64_CHARS[index]
        end for
    end for
 
    // Pad the output length with '=' characters if necessary
    let padding = input_length % 3
    if padding > 0
        for i from 0 to (3 - padding)
            output[output.length - i - 1] = '='
        end for
    end if
 
    return output
end function

Here is an explanation of the code, broken down into a list:

  1. The binary data to be encoded is passed as an input parameter to the base64_encode function.
  2. The basic character set for the encoding, which consists of 64 characters, is designated by the constant BASE64_CHARS.
  3. The length of the input data is used to calculate the input_length variable.
  4. The output variable, which will hold the result of the encoding, is initially set to an empty string.
  5. A for loop that iterates from 0 to input_length – 1 with a step of 3 processes the input data in 3-byte blocks.
  6. The first byte is shifted left by 16 bits for each block, the second byte is shifted left by 8 bits, and the third byte is added to determine the block_value variable for each block.
  7. A second for loop that iterates from 0 to 3 is then used to encode the block into 4 characters.
  8. For each character, an index is calculated by shifting the block_value to the right by a multiple of 6 bits and masking it with 0x3F.
  9. The character at this index in the BASE64_CHARS constant is then appended to the output string.
  10. After all blocks have been processed, the output length is padded with ‘=’ characters if necessary.
  11. To accomplish this, the padding is determined by dividing the input_length by 3.
  12. A for loop iterates from 0 to (3 – padding) and replaces the final characters of the output string with ‘=‘ characters if padding is higher than 0.
  13. The function then returns the result that was encoded and saved in the output variable.

Implementing Base64 Decoding Algorithm in Pseudocode

Building upon our understanding of language-independent Base64 encoding, let’s explore how to decode Base64-encoded data without relying on any specific programming language.

function base64_decode(input)
    // The base character set
    const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 
    // The length of the input
    let input_length = length(input)
 
    // The output
    let output = []
 
    // Process the input in 4-character blocks
    for i from 0 to input_length - 1 step 4
        // The value of the block
        let block_value = (index_of(BASE64_CHARS, input[i]) << 18) + (index_of(BASE64_CHARS, input[i + 1]) << 12) + (index_of(BASE64_CHARS, input[i + 2]) << 6) + index_of(BASE64_CHARS, input[i + 3])
 
        // Decode the block into 3 bytes
        for j from 0 to 2
            let byte = (block_value >> ((2 - j) * 8)) & 0xFF
            output.append(byte)
        end for
    end for
 
    // Remove any padding bytes from the output
    let padding = count(input, '=')
    if padding > 0
        output = output[0:output.length - padding]
    end if
 
    return output
end function

A short and simple explanation:

  • The base64_decode function takes an input parameter, which is the string of characters to be decoded.
  • The BASE64_CHARS constant is defined as the base character set for the decoding, which consists of 64 characters.
  • The length of the input string is used to calculate the input_length variable.
  • The output variable, which will hold the result of the decoding, is initialized as an empty array.
  • The input data is processed in 4-character blocks using a for loop that iterates from 0 to input_length - 1 with a step of 4.
  • For each block, the block_value variable is calculated by shifting the index of each character in the BASE64_CHARS constant to the left by a multiple of 6 bits and adding them together.
  • Then, a second for loop iterating from 0 to 2 decodes the block into 3 bytes.
  • By moving the block_value to the right by a multiple of 8 bits and masking it with 0xFF, a value is computed for each byte. This value is then appended to the output array.
  • If necessary, any padding bytes are taken out of the output once all blocks have been processed. The count function is used to determine how many padding characters (‘=‘) are present in the input, and then the appropriate number of bytes are subtracted from the end of the output array.
  • Finally, the function returns the decoded result stored in the output array.

The language-independent technique for Base64 decoding, as demonstrated above, can be adapted to any programming language. By mastering the underlying principles of Base64 encoding and decoding, you can create a custom implementation tailored to your unique requirements and constraints. This approach allows for greater flexibility and control over the encoding and decoding processes, making it a valuable skill for developers working in various domains.