在编程领域,Base64 是一组二进制到文本的编码方案,通过将数据转换为基数为 64 的表示形式,以 ASCII 字符串格式来表示二进制数据(更确切地说,是一系列 8 位字节)。“Base64” 这一术语源自特定的多用途互联网邮件扩展(MIME)内容传输编码。每个非最后的 Base64 数字恰好代表 6 位数据。因此,三个 8 位字节(即总共 24 位)可以由四个 6 位的 Base64 数字来表示。
头文件与命名空间
#include <array> /// for `std::array`
#include <cassert> /// for `assert` operations
#include <iostream> /// for IO operations
引入了三个头文件:
-
<array>
:提供std::array
类型支持。 -
<cassert>
:提供断言功能,用于测试代码的正确性。 -
<iostream>
:用于输入输出操作。
namespace ciphers {
namespace base64_encoding {
定义了嵌套命名空间 ciphers::base64_encoding
,用于组织 Base64 编码和解码的函数。
Base64 编码表
const std::string chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
定义了一个字符串常量 chars
,包含 Base64 编码所需的字符集,按照 RFC4648 标准定义。
Base64 编码函数
std::string base64_encode(const std::string& input) {
std::string base64_string;
定义了 base64_encode
函数,接收一个 std::string
类型的输入参数 input
,返回其 Base64 编码后的字符串。
for (uint32_t i = 0; i < input.size(); i += 3) {
循环遍历输入字符串,每次处理 3 个字节。
char first_byte = input[i];
base64_string.push_back(chars[first_byte >> 2]);
提取第一个字节的前 6 位,并将对应的 Base64 字符添加到结果字符串中。
if (i + 1 < input.size()) {
char second_byte = input[i + 1];
base64_string.push_back(
chars[(((first_byte & 3) << 4) | ((second_byte & 0xF0) >> 4))]);
如果存在第二个字节,提取第一个字节的后 2 位和第二个字节的前 4 位,组合成一个新的 6 位值,并添加对应的 Base64 字符。
if (i + 2 < input.size()) {
char third_byte = input[i + 2];
base64_string.push_back(chars[((third_byte & 0xC0) >> 6) |
((second_byte & 0x0F) << 2)]);
base64_string.push_back(chars[(third_byte & 0x3F)]);
如果存在第三个字节,提取第二个字节的后 4 位和第三个字节的前 2 位,组合成一个新的 6 位值,并添加对应的 Base64 字符。然后提取第三个字节的后 6 位,添加对应的 Base64 字符。
else {
base64_string.push_back(chars[((second_byte & 0x0F) << 2)]);
base64_string.push_back('=');
}
如果不存在第三个字节,仅处理第二个字节,并添加一个填充字符 =
。
else {
base64_string.push_back(chars[((first_byte & 3) << 4)]);
base64_string.push_back('=');
base64_string.push_back('=');
}
如果输入字符串的长度不足 3 个字节,处理现有字节并添加两个填充字符 =
。
辅助函数
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;
}
定义了一个辅助函数 find_idx
,用于查找字符在 Base64 字符集中的位置。根据字符的类型(大写字母、小写字母、数字、+
或 /
),返回其对应的索引值。
Base64 解码函数
std::string base64_decode(const std::string& base64_str) {
std::string base64_decoded;
定义了 base64_decode
函数,接收一个 Base64 编码的字符串 base64_str
,返回解码后的原始数据。
for (uint32_t i = 0; i < base64_str.size(); i += 4) {
char first_byte = base64_str[i];
char second_byte = base64_str[i + 1];
char first_actual_byte = static_cast<char>(
(find_idx(first_byte) << 2) | ((find_idx(second_byte)) >> 4));
base64_decoded.push_back(first_actual_byte);
循环遍历 Base64 字符串,每次处理 4 个字符。提取前两个字符的 6 位值,组合成一个 8 位值,并添加到解码结果中。
if (i + 2 < base64_str.size() && base64_str[i + 2] != '=') {
char third_byte = base64_str[i + 2];
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);
如果存在第三个字符且不是填充字符 =
,提取第二个和第三个字符的 6 位值,组合成另一个 8 位值,并添加到解码结果中。
if (i + 3 < base64_str.size() && base64_str[i + 3] != '=') {
char fourth_byte = base64_str[i + 3];
char third_actual_byte =
static_cast<char>(((find_idx(third_byte) & 0x03) << 6) |
find_idx(fourth_byte));
base64_decoded.push_back(third_actual_byte);
}
如果存在第四个字符且不是填充字符 =
,提取第三个和第四个字符的 6 位值,组合成最后一个 8 位值,并添加到解码结果中。
测试函数
static void 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"
"RpIGEgY29tcHV0ZXIu";
assert(base64_str == verify);
std::string original_str =
ciphers::base64_encoding::base64_decode(base64_str);
assert(original_str == str);
第一个测试案例,对一个普通字符串进行 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=";
assert(base64_str == verify);
original_str = ciphers::base64_encoding::base64_decode(base64_str);
assert(original_str == str);
第二个测试案例,对一个较长的字符串(来自维基百科)进行 Base64 编码和解码,验证结果是否与原始字符串一致。
主函数
int main() {
test(); // run self-test implementations
return 0;
}
主函数调用测试函数 test
,运行自我测试以验证 Base64 编码和解码的实现是否正确。