base64編碼原理和函式

52017發表於2024-06-12

目錄

目錄
  • 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;
}

相關文章