Base 64 Encoding

/**
 * @brief [Base64 Encoding and
 * Decoding](https://en.wikipedia.org/wiki/Base64)
 * @details In programming, [Base64](https://en.wikipedia.org/wiki/Base64) is a
 * group of binary-to-text encoding schemes that represent binary data (more
 * specifically, a sequence of 8-bit bytes) in an ASCII string format by
 * translating the data into a radix-64 representation. The term Base64
 * originates from a specific MIME content transfer encoding. Each non-final
 * Base64 digit represents exactly 6 bits of data. Three 8-bit bytes (i.e., a
 * total of 24 bits) can therefore be represented by four 6-bit Base64
 * digits.
 * @author [Ashish Daulatabad](https://github.com/AshishYUO)
 */
#include <array>     /// for `std::array`
#include <cassert>   /// for `assert` operations
#include <iostream>  /// for IO operations

/**
 * @namespace ciphers
 * @brief Cipher algorithms
 */
namespace ciphers {
/**
 * @namespace base64_encoding
 * @brief Functions for [Base64 Encoding and
 * Decoding](https://en.wikipedia.org/wiki/Base64) implementation.
 */
namespace base64_encoding {
// chars denoting the format for encoding and decoding array.
// This array is already decided by
// [RFC4648](https://tools.ietf.org/html/rfc4648#section-4) standard
const std::string chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
 * @brief Base64 Encoder
 * @details Converts the given string to Base64 equivalent.
 * @param input Input as a string
 * @returns Base64 encoded string
 */
std::string base64_encode(const std::string &input) {
    std::string base64_string;  /// Output of this function: base64 string
    // base64 deals with 6-bit chars encoded as per chars, so
    // we will always filter 6-bits from input.
    for (uint32_t i = 0; i < input.size(); i += 3) {
        char first_byte = input[i];  /// First byte of the iteration
        // Take first six bits of first character.
        // Encode the first six bits with character defined in string `chars`
        base64_string.push_back(chars[first_byte >> 2]);

        if (i + 1 < input.size()) {
            char second_byte = input[i + 1];  /// Second byte of the iteration
            // Take remaining two bits of first character, and four first bits
            // from second character Combine two numbers as 6-bit digits and
            // encode by array chars (first two bits of first byte and next four
            // of second byte)
            base64_string.push_back(
                chars[(((first_byte & 3) << 4) | ((second_byte & 0xF0) >> 4))]);

            if (i + 2 < input.size()) {
                char third_byte = input[i + 2];  /// Third byte of the iteration
                // Take remaining four bits of second character, and first two
                // bits from third character Combine two numbers as 6-bit digits
                // and encode by array chars (remaining four bits of second byte
                // and first two of third byte)
                base64_string.push_back(chars[((third_byte & 0xC0) >> 6) |
                                              ((second_byte & 0x0F) << 2)]);
                // Encode remaining 6-bit of third byte by array chars
                base64_string.push_back(chars[(third_byte & 0x3F)]);
            } else {
                // Take remaining four bits of second character as 6-bit number
                base64_string.push_back(chars[((second_byte & 0x0F) << 2)]);
                base64_string.push_back('=');  // padding characters
            }
        } else {
            // Take remaining two bits of first character as 6-bit number
            base64_string.push_back(chars[((first_byte & 3) << 4)]);
            base64_string.push_back('=');  // padding characters
            base64_string.push_back('=');  // padding characters
        }
    }
    return base64_string;
}
/**
 * @brief Utility function for finding index
 * @details Utility function for finding the position of a character in array
 * `chars`
 * @param c character to search in array `chars`
 * @returns integer denoting position of character in array `chars`
 */
uint8_t find_idx(const char c) {
    if (c >= 'A' && c <= 'Z') {
        return c - 'A';
    } else if (c >= 'a' && c <= 'z') {
        return c - 'a' + 26;
    } else if (c >= '0' && c <= '9') {
        return c - '0' + 52;
    } else if (c == '+') {
        return 62;
    } else if (c == '/') {
        return 63;
    }
    return -1;
}
/**
 * @brief Base64 Decoder
 * @details Decodes the Base64 string
 * @param base64_str Input as a Base64 string
 * @returns Base64 decoded string
 */
std::string base64_decode(const std::string &base64_str) {
    std::string
        base64_decoded;  /// Output of this function: base64 decoded string
    for (uint32_t i = 0; i < base64_str.size(); i += 4) {
        /// First 6-bit representation of Base64
        char first_byte = base64_str[i];
        /// Second 6-bit representation of Base64
        char second_byte = base64_str[i + 1];
        // Actual str characters are of 8 bits (or 1 byte):
        // :: 8 bits are decode by taking 6 bits from 1st byte of base64 string
        // and first 2 bits from 2nd byte of base64 string.
        char first_actual_byte = static_cast<char>(
            (find_idx(first_byte) << 2) | ((find_idx(second_byte)) >> 4));
        base64_decoded.push_back(first_actual_byte);
        if (i + 2 < base64_str.size() && base64_str[i + 2] != '=') {
            /// Third 6-bit representation of Base64
            char third_byte = base64_str[i + 2];
            // :: Next 8 bits are decode by taking remaining 4 bits from 2nd
            // byte of base64 string and first 4 bits from 3rd byte of base64
            // string.
            char second_actual_byte =
                static_cast<char>(((find_idx(second_byte) & 0x0F) << 4) |
                                  (find_idx(third_byte) >> 2));
            base64_decoded.push_back(second_actual_byte);

            if (i + 3 < base64_str.size() && base64_str[i + 3] != '=') {
                /// Fourth 6-bit representation of Base64 string
                char fourth_byte = base64_str[i + 3];
                // :: Taking remaining 2 bits from 3rd byte of base64 string
                // and all 6 bits from 4th byte of base64 string.
                char third_actual_byte =
                    static_cast<char>(((find_idx(third_byte) & 0x03) << 6) |
                                      find_idx(fourth_byte));
                base64_decoded.push_back(third_actual_byte);
            }
        }
    }
    return base64_decoded;
}
}  // namespace base64_encoding
}  // namespace ciphers

/**
 * @brief Self test-implementations
 * @returns void
 */
static void test() {
    // 1st Test
    std::string str =
        "To err is human, but to really foul things up you need a computer.";
    std::string base64_str = ciphers::base64_encoding::base64_encode(str);
    std::string verify =
        "VG8gZXJyIGlzIGh1bWFuLCBidXQgdG8gcmVhbGx5IGZvdWwgdGhpbmdzIHVwIHlvdSBuZW"
        "VkIGEgY29tcHV0ZXIu";
    // verify encoding
    assert(base64_str == verify);
    std::string original_str =
        ciphers::base64_encoding::base64_decode(base64_str);
    // verify decoding
    assert(original_str == str);

    // 2nd Test from [Wikipedia](https://en.wikipedia.org/wiki/Base64)
    str =
        "Man is distinguished, not only by his reason, but by this singular "
        "passion from other animals, which is a lust of the mind, that by a "
        "perseverance of delight in the continued and indefatigable generation "
        "of knowledge, exceeds the short vehemence of any carnal pleasure.";

    base64_str = ciphers::base64_encoding::base64_encode(str);
    verify =
        "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieS"
        "B0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBh"
        "IGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodC"
        "BpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25v"
        "d2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbG"
        "Vhc3VyZS4=";
    // verify encoding
    assert(base64_str == verify);
    original_str = ciphers::base64_encoding::base64_decode(base64_str);
    // verify decoding
    assert(original_str == str);
}

/**
 * @brief Main function
 * @returns 0 on exit
 */
int main() {
    test();  // run self-test implementations
    return 0;
}
Algerlogo

Β© Alger 2022

About us

We are a group of programmers helping each other build new things, whether it be writing complex encryption programs, or simple ciphers. Our goal is to work together to document and model beautiful, helpful and interesting algorithms using code. We are an open-source community - anyone can contribute. We check each other's work, communicate and collaborate to solve problems. We strive to be welcoming, respectful, yet make sure that our code follows the latest programming guidelines.