C語言實現Base64編碼/解碼

2020-08-11 14:13:35

Bse64是一種以64個可列印字元對二進制數據進行編碼的編碼演算法。base64在對數據進行編碼時以三個8位元字元型數據爲一組,取這三個字元型數據的ASCII碼,然後以6位爲一組組成4個新的數據,這4個新的數據有6位,所以它的最大值爲2^6=64。我們以4個6位數據的十進制數從base64表中得到最終編碼後的字元。

Base64 編碼表

Value Char  Value Char  Value Char  Value Char 
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 /

由於base64編碼是將編碼前的3*8位元數據,分解成4個6位的數據,所以經過base64編碼後的字串長度是4的倍數。但往往我們進行編碼的數據長度並不是3的倍數,這就造成了「編碼」後的位數不爲4的倍數,比如Brisk共5×8=40位,以6位爲一組可以分爲7組,這樣「編碼」後就有7個字元,但base64編碼後的字元長度應該是4的倍數,顯然這裏就出問題了,那麼怎麼辦呢?前面的不可以拋棄掉,所以就只有「追加」了,所以Brisk經過base64編碼後的長度應該是8個字元,而第8個編碼後的字元是'=',再比如對單個字元a進行base64編碼,由於它的長度不是3的倍數,以3個位元組爲一組它只能分一組,再以6位爲一位它只能分兩組,所以經過「編碼」後它的長度是2,但base64編碼後的個數應該是4的倍數,所以它的長度應該是4,所以在後面補上兩個‘=’,由於一個數求餘3後有三個不同的結果,0、1、2,所以在對一個數據進行base64進行編碼後它的長度爲: 

(1)當進行編碼的數據長度是3的倍數時,len=strlen(str_in)/3*4;

(2)當進行編碼的數據長度不是3的倍數時,len=(strlen(str_in)/3+1)*4;

我們以Brisk這個例子來說明一下base64編碼的過程。首先我們以3個字元爲一組將Brisk進行分組,Brisk被氛圍兩組:Bri 和 sk;然後我們取出這兩個分組中每個位元組的ASCII碼,B:66 r:114 i:105 s:115 k:107。它們對應的二進制數爲  B:01000010 r:01110010 i:01101001 s:01110011 k:01101011;

第一組,我們以6位爲一組對每一個3位元組分組進行再分組就變成了010000 100111 001001 101001。所對應的十進制數是16 39 9 41,對應base64表中的結果是 Q n J p;

       第二組,011100 110110 101100(不夠補0),所以對應的十進制數是 28 54 44,對應base64表中的結果是 c 2 s,最終結果爲QnJpc2s=(因爲第二組「編碼」後只有三個位元組)。

解碼的過程是一個逆過程,我們將經過編碼後的字元按4個字元爲一組,然後對照base64表得到相應的十進制數,再將其通過拆分和組合,組成3個8位元數據,這個數據就是解碼後的數據,下面 下麪給一個c語言實現編碼和解碼的程式碼。

1、base64.h

/*base64.h*/  
#ifndef _BASE64_H  
#define _BASE64_H  
  
#include <stdlib.h>  
#include <string.h>  
  
unsigned char *base64_encode(unsigned char *str);  
  
unsigned char *bae64_decode(unsigned char *code);  
  
#endif  

2、base64.c 

/*base64.c*/  
#include "base64.h"  
  
unsigned char *base64_encode(unsigned char *str)  
{  
    long len;  
    long str_len;  
    unsigned char *res;  
    int i,j;  
//定義base64編碼表  
    unsigned char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
  
//計算經過base64編碼後的字串長度  
    str_len=strlen(str);  
    if(str_len % 3 == 0)  
        len=str_len/3*4;  
    else  
        len=(str_len/3+1)*4;  
  
    res=malloc(sizeof(unsigned char)*len+1);  
    res[len]='\0';  
  
//以3個8位元字元爲一組進行編碼  
    for(i=0,j=0;i<len-2;j+=3,i+=4)  
    {  
        res[i]=base64_table[str[j]>>2]; //取出第一個字元的前6位並找出對應的結果字元  
        res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; //將第一個字元的後位與第二個字元的前4位元進行組合並找到對應的結果字元  
        res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; //將第二個字元的後4位元與第三個字元的前2位組合並找出對應的結果字元  
        res[i+3]=base64_table[str[j+2]&0x3f]; //取出第三個字元的後6位並找出結果字元  
    }  
  
    switch(str_len % 3)  
    {  
        case 1:  
            res[i-2]='=';  
            res[i-1]='=';  
            break;  
        case 2:  
            res[i-1]='=';  
            break;  
    }  
  
    return res;  
}  
  
unsigned char *base64_decode(unsigned char *code)  
{  
//根據base64表,以字元找到對應的十進制數據  
    int table[]={0,0,0,0,0,0,0,0,0,0,0,0,
             0,0,0,0,0,0,0,0,0,0,0,0,
             0,0,0,0,0,0,0,0,0,0,0,0,
             0,0,0,0,0,0,0,62,0,0,0,
             63,52,53,54,55,56,57,58,
             59,60,61,0,0,0,0,0,0,0,0,
             1,2,3,4,5,6,7,8,9,10,11,12,
             13,14,15,16,17,18,19,20,21,
             22,23,24,25,0,0,0,0,0,0,26,
             27,28,29,30,31,32,33,34,35,
             36,37,38,39,40,41,42,43,44,
             45,46,47,48,49,50,51
               };  
    long len;  
    long str_len;  
    unsigned char *res;  
    int i,j;  
  
//計算解碼後的字串長度  
    len=strlen(code);  
//判斷編碼後的字串後是否有=  
    if(strstr(code,"=="))  
        str_len=len/4*3-2;  
    else if(strstr(code,"="))  
        str_len=len/4*3-1;  
    else  
        str_len=len/4*3;  
  
    res=malloc(sizeof(unsigned char)*str_len+1);  
    res[str_len]='\0';  
  
//以4個字元爲一位進行解碼  
    for(i=0,j=0;i < len-2;j+=3,i+=4)  
    {  
        res[j]=((unsigned char)table[code[i]])<<2 | (((unsigned char)table[code[i+1]])>>4); //取出第一個字元對應base64表的十進制數的前6位與第二個字元對應base64表的十進制數的後2位進行組合  
        res[j+1]=(((unsigned char)table[code[i+1]])<<4) | (((unsigned char)table[code[i+2]])>>2); //取出第二個字元對應base64表的十進制數的後4位元與第三個字元對應bas464表的十進制數的後4位元進行組合  
        res[j+2]=(((unsigned char)table[code[i+2]])<<6) | ((unsigned char)table[code[i+3]]); //取出第三個字元對應base64表的十進制數的後2位與第4個字元進行組合  
    }  
  
    return res;  
  
}  

 

3、test.c

/*一個測試程式*/  
#include "base64.h"  
#include <stdio.h> 
#include <string.h>   
  
int main(int argc,char **argv)  
{  
    unsigned char *buf =NULL;
    if(strcmp(argv[1],"-d") == 0) 
    { 
    buf = base64_decode(argv[2]);
        printf("%s\n",buf);  
    }
    else  
    {
    buf = base64_encode(argv[1]);
        printf("%s\n",buf);   
    }
 
    free(buf);
  
    return 0;  
} 

4、執行編譯

編譯  
gcc -o test test.c base64.c
 
./test a123456
YTEyMzQ1Ng==
 
 
./test -d YTEyMzQ1Ng==
a123456

C語言實現Base64編碼/解碼介紹到此結束。