目錄
- base64編碼
- 什麼是base64編碼
- Base64的編碼原理
- base編碼函式例子
- 主函式
base64編碼
什麼是base64編碼
Base64編碼是將字串以每3個8位元(bit)的位元組子序列拆分成4個6位元(bit)的位元組(6位元有效位元組,最左邊兩個永遠為0,其實也是8位元的位元組)子序列,再將得到的子序列查詢Base64的編碼索引表,得到對應的字元拼接成新的字串的一種編碼方式。
Base64的編碼原理
Base64的原理比較簡單,每當我們使用Base64時都會先定義一個類似這樣的陣列:
['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']
上面就是Base64的索引表,字元選用了"A-Z、a-z、0-9、+、/" 64個可列印字元,這是標準的Base64協議規定。在日常使用中我們還會看到“=”或“==”號出現在Base64的編碼結果中,“=”在此是作為填充字元出現,後面會講到。
具體轉換步驟
第一步,將待轉換的字串每三個位元組分為一組,每個位元組佔8bit,那麼共有24個二進位制位。
第二步,將上面的24個二進位制位每6個一組,共分為4組。
第三步,在每組前面新增兩個0,每組由6個變為8個二進位制位,總共32個二進位制位,即四個位元組。
第四步,根據Base64編碼對照表
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y
從上面的步驟我們發現:
Base64字元表中的字元原本用6個bit就可以表示,現在前面新增2個0,變為8個bit,會造成一定的浪費。因此,Base64編碼之後的文字,要比原文大約三分之一。
為什麼使用3個位元組一組呢?因為6和8的最小公倍數為24,三個位元組正好24個二進位制位,每6個bit位一組,恰好能夠分為4組。
兩個位元組:兩個位元組共16個二進位制位,依舊按照規則進行分組。此時總共16個二進位制位,每6個一組,則第三組缺少2位,用0補齊,得到三個Base64編碼,第四組完全沒有資料則用“=”補上。因此,上圖中“BC”轉換之後為“QKM=”;
一個位元組:一個位元組共8個二進位制位,依舊按照規則進行分組。此時共8個二進位制位,每6個一組,則第二組缺少4位,用0補齊,得到兩個Base64編碼,而後面兩組沒有對應資料,都用“=”補上。因此,上圖中“A”轉換之後為“QQ==”;
注意事項
大多數編碼都是由字串轉化成二進位制的過程,而Base64的編碼則是從二進位制轉換為字串。與常規恰恰相反,
Base64編碼主要用在傳輸、儲存、表示二進位制領域,不能算得上加密,只是無法直接看到明文。也可以透過打亂Base64編碼來進行加密。
中文有多種編碼(比如:utf-8、gb2312、gbk等),不同編碼對應Base64編碼結果都不一樣。
延伸
上面我們已經看到了Base64就是用6位(2的6次冪就是64)表示字元,因此成為Base64。同理,Base32就是用5位,Base16就是用4位。可以按照上面的步驟進行演化一下。
base編碼函式例子
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // base64中的64位排序,按照以上內容進行編碼
/********************************************************************
*
* name : base64_encode
* function : base64編碼機制將3個位元組轉換成4個部分,按6位位元進行拆分
* argument :
* @data :需要進行編碼的字串
* @input_length :字串的位元組大小
* retval : 呼叫成功返回生成檔案後的結果
* author : 17666589210@163.com
* date : 2024/06/11
* note : none
*
* *****************************************************************/
char *base64_encode(const unsigned char *data, size_t input_length)
{
size_t output_length = 4 * ((input_length + 2) / 3);//將三個位元組24位轉換為4個位元組32位
char *encoded_data = malloc(output_length + 1);
if (encoded_data == NULL)
return NULL;
for (size_t i = 0, j = 0; i < input_length;)
{
uint32_t octet_a = i < input_length ? data[i++] : 0;
uint32_t octet_b = i < input_length ? data[i++] : 0;
uint32_t octet_c = i < input_length ? data[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
encoded_data[j++] = base64_table[(triple >> 3 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 2 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 1 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 0 * 6) & 0x3F];
}
for (size_t i = 0; i < (3 - input_length % 3) % 3; i++)
{
encoded_data[output_length - 1 - i] = '=';
}
encoded_data[output_length] = '\0';
return encoded_data;
}
主函式
int main()
{
const char *input_string = "Hello, this is a test for Base64 encoding.";
char *encoded_string = base64_encode((const unsigned char *)input_string, strlen(input_string));
if (encoded_string)
{
printf("Encoded string: %s\n", encoded_string);
free(encoded_string);
}
else
{
printf("Error encoding the string.\n");
}
return 0;
}