base64是一種基於64個可列印字元來表示位元據的表示方法。由於26=64,所以每6位為一個單位,對應某個可列印字元。三個位元組共24位,對應於4個base64單位,即3個位元組需要用4個可列印字元來表示。它常用來作為電子郵件的傳輸編碼。在base64中的可列印字元包括大寫英文字母A-Z,小寫英文字母a-z、阿拉伯數字0-9,這樣共有62個字元,此外兩個可列印符號在不同的系統中而不同,通常用加號(+)和正斜杠(/)。外加“補全符號”,通常用等號(=)。
完整的base64定義可見RFC 1421和RFC 2045。編碼後的資料比未經處理資料略長,為原來的4/3。在電子郵件中,根據RFC 822的規定,每76個字元,還需要加上斷行符號符和分行符號。可以估算編碼後資料長度大約為原長的135.1%。
base64編碼的時候,將三個自己的資料,先後放入一個24位的緩衝區中,先來的自己占高位。資料不足3個位元組的話,在緩衝區中剩下的位用0補足。然後,每次取出6(因為26=64)位,按照其值選擇 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 中的字元作為編碼後的輸出。不斷進行,直到全部輸入資料轉換完成。如果最後剩下兩個輸入資料,在編碼結果後加1個“=”;如果最後剩下一個輸入資料,編碼結果後加2個“=”;如果沒有剩下任何資料,就什麼都不要加。這樣才可以保證資料還原的正確性。
C語言原始碼如下:
/** * base64編碼、解碼實現 * C語言原始碼 * * 葉劍飛 * * * * 使用說明: * 命令列參數說明:若有“-d”參數,則為base64解碼,否則為base64編碼。 * 輸入來自標準輸入stdin,輸出為標準輸出stdout。可重新導向輸入輸出資料流。 * * base64編碼:輸入任意二進位流,讀取到檔案讀完了為止(鍵盤輸入則遇到檔案結尾符為止)。 * 輸出純文字的base64編碼。 * * base64解碼:輸入純文字的base64編碼,讀取到檔案讀完了為止(鍵盤輸入則遇到檔案結尾符為止)。 * 輸出原來的二進位流。 * */#include <stdio.h>#include <stdlib.h>#include <string.h>const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";char * base64_encode( const unsigned char * bindata, char * base64, int binlength ){ int i, j; unsigned char current; for ( i = 0, j = 0 ; i < binlength ; i += 3 ) { current = (bindata[i] >> 2) ; current &= (unsigned char)0x3F; base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ; if ( i + 1 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; base64[j++] = '='; break; } current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ; if ( i + 2 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; break; } current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ; base64[j++] = base64char[(int)current]; } base64[j] = '\0'; return base64;}int base64_decode( const char * base64, unsigned char * bindata ){ int i, j; unsigned char k; unsigned char temp[4]; for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 ) { memset( temp, 0xFF, sizeof(temp) ); for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i] ) temp[0]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+1] ) temp[1]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+2] ) temp[2]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+3] ) temp[3]= k; } bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) | ((unsigned char)((unsigned char)(temp[1]>>4)&0x03)); if ( base64[i+2] == '=' ) break; bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) | ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F)); if ( base64[i+3] == '=' ) break; bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) | ((unsigned char)(temp[3]&0x3F)); } return j;}int main(int argc, char * argv[]){ int i; unsigned char bindata[2050]; char base64[4096]; size_t bytes; if ( argc == 1 ) { // encode while ( !feof( stdin ) ) { bytes = fread( bindata, 1, 2049, stdin ); base64_encode( bindata, base64, bytes ); printf( "%s", base64 ); } } else if ( argc == 2 && !strcmp(argv[1], "-d") ) { // decode while ( !feof( stdin ) ) { for ( i = 0 ; i < 2048 ; i ++ ) { base64[i] = getchar(); if ( base64[i] == EOF ) break; else if ( base64[i] == '\n' || base64[i] == '\r' ) i --; } bytes = base64_decode( base64, bindata ); fwrite( bindata, bytes, 1, stdout ); } } else { fprintf( stderr, "Usage: %s [-d]\n\t-d\tdecode data\n\n", argv[0] ); return EXIT_FAILURE; } return EXIT_SUCCESS;}