(基礎篇 04) C++ base64 編解碼原理及實現

Base64原理

Base64 是一種基於 64 個可打印字符來表示二進制數據的表示方法。由於 2^6 = 64,所以每 6 個比特爲一個單元,對應某個可打印字符。3 個字節有 24 個比特,對應於 4 個 Base64 單元,即 3 個字節可由 4 個可打印字符來表示。它可用來作爲電子郵件的傳輸編碼。在 Base64 中的可打印字符包括字母 A-Za-z、數字 0-9+, /

Base64 常用於在通常處理文本數據的場合,表示、傳輸、存儲一些二進制數據,包括 MIME 的電子郵件及XML的一些複雜數據。

Base64 的索引表如下:

數值 字符 數值 字符 數值 字符 數值 字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

示例:將 Man 編碼得到 TWFu
在這裏插入圖片描述

如果要編碼的字節數不能被 3 整除,最後會多出 1 個或 2 個字節,那麼可以使用下面的方法進行處理:先使用 0 字節值在末尾補足,使其能夠被 3 整除,然後再進行 Base64 的編碼。在編碼後的 Base64 文本後加上一個或兩個 = 號,代表補足的字節數。也就是說,當最後剩餘兩個八位(待補足)字節(2 個 byte)時,最後一個 6 位的 Base64 字節塊有四位是 0 值,最後附加上兩個等號;如果最後剩餘一個八位(待補足)字節( 1 個 byte)時,最後一個 6 位的 base 字節塊有兩位是 0 值,最後附加一個等號。
在這裏插入圖片描述

C++ 代碼

base64 編解碼的 c++ 代碼如下所示,代碼來源:github

// https://github.com/ReneNyffenegger/cpp-base64
#include "base64.h"
#include <iostream>

// there are 64 characters
static const std::string base64_chars =
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		"abcdefghijklmnopqrstuvwxyz"
		"0123456789+/";


static inline bool is_base64(unsigned char c) {
	return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_encode(const char *bytes_to_encode, unsigned int in_len) {
	std::string ret;
	int i = 0;
	int j = 0;
	unsigned char char_array_3[3];  // store 3 byte of bytes_to_encode
	unsigned char char_array_4[4];  // store encoded character to 4 bytes

	while (in_len--) {
		char_array_3[i++] = *(bytes_to_encode++);  // get three bytes (24 bits)
		if (i == 3) {
			// eg. we have 3 bytes as ( 0100 1101, 0110 0001, 0110 1110) --> (010011, 010110, 000101, 101110)
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; // get first 6 bits of first byte,
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); // get last 2 bits of first byte and first 4 bit of second byte
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); // get last 4 bits of second byte and first 2 bits of third byte
			char_array_4[3] = char_array_3[2] & 0x3f; // get last 6 bits of third byte

			for (i = 0; (i < 4); i++)
				ret += base64_chars[char_array_4[i]];
			i = 0;
		}
	}

	if (i)
	{
		for (j = i; j < 3; j++)
			char_array_3[j] = '\0';

		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);

		for (j = 0; (j < i + 1); j++)
			ret += base64_chars[char_array_4[j]];

		while ((i++ < 3))
			ret += '=';

	}

	return ret;

}

std::string base64_decode(const std::string& encoded_string) {
	size_t in_len = encoded_string.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
		char_array_4[i++] = encoded_string[in_]; in_++;
		if (i == 4) {
			for (i = 0; i < 4; i++)
				char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff;

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

			for (i = 0; (i < 3); i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i) {
		for (j = 0; j < i; j++)
			char_array_4[j] = base64_chars.find(char_array_4[j]) & 0xff;

		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);

		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
	}

	return ret;
}
發佈了22 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章