天天看點

Base64編解碼Base64編解碼

Base64編解碼

1、應用目的

在計算機中任何資料都是按ascii碼存儲的,而ascii碼的128~255之間的值是不可見字元。将資料先做一個Base64編碼,統統變成可見字元,在多裝置資料傳輸的過程中,可以降低資料出錯的可能性。

2、解決問題

  • 使用Base64可以解決用戶端與伺服器資料傳輸中文本亂碼問題
  • 解決編解碼過程中,由于傳輸資料過程中資料轉化為二進制導緻文本資料長度改變,導緻簽名過程中

    RSA_verify

    函數出現段錯誤。
const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
           

3、算法原理

  • 把3個8位位元組(3*8=24)轉化為4個6位的位元組(4*6=24)
    • 假設有一個字元串, 需要對這個字元串分組, 每3個位元組為一組, 分成N組
    • 将每一組的3個位元組拆分, 拆成4個位元組, 每個位元組有6bit
  • 在6位的前面補兩個0,形成8位一個位元組的形式
    • 每個組就從3個位元組變成了4個位元組
    • 結論: base64編碼之後的字元串變大了,
  • 如果剩下的字元不足3個位元組,則用0填充,輸出字元使用’=’,是以編碼後輸出的文本末尾可能會出現1或2個’=’, 表示補了多少位元組,解碼的時候,會自動去掉。
Base64編解碼Base64編解碼
Base64編解碼Base64編解碼

4、openssl 中base64的使用

OpenSSL中文手冊之BIO庫詳解: https://blog.csdn.net/liao20081228/article/details/77193729

// 建立BIO對象
BIO *BIO_new(const BIO_METHOD *type);
// 封裝了base64編碼方法的BIO,寫的時候進行編碼,讀的時候解碼
BIO_METHOD* BIO_f_base64();
// 封裝了記憶體操作的BIO接口,包括了對記憶體的讀寫操作
BIO_METHOD* BIO_s_mem();

// 建立一個記憶體型的BIO對象
// BIO * bio = BIO_new(BIO_s_mem());
BIO *BIO_new_mem_buf(void *buf, int len);
// 建立一個磁盤檔案操作的BIO對象
BIO* BIO_new_file(const char* filename, const char* mode);

// 從BIO接口中讀出len位元組的資料到buf中。
// 成功就傳回真正讀出的資料的長度,失敗傳回0或-1,如果該BIO沒有實作本函數則傳回-2。
int BIO_read(BIO *b, void *buf, int len);
	- buf: 存儲資料的緩沖區位址
	- len: buf的最大容量
// 往BIO中寫入長度為len的資料。
// 成功傳回真正寫入的資料的長度,失敗傳回0或-1,如果該BIO沒有實作本函數則傳回-2。
int BIO_write(BIO *b, const void *buf, int len);
	- buf: 要寫入的資料, 寫入到b對應的裝置(記憶體/磁盤檔案)中
	- len: 要寫入的資料的長度
// 将BIO内部緩沖區的資料都寫出去, 成功: 1, 失敗: 0或-1
int BIO_flush(BIO *b);
	- 在使用BIO_write()進行寫操作的時候, 資料有時候在openssl提供的緩存中
	- 将openssl提供的緩存中的資料刷到裝置(記憶體/磁盤檔案)中

// 把參數中名為append的BIO附加到名為b的BIO上,并傳回b
// 連接配接兩個bio對象到連結清單中
// 在連結清單中的關系: b->append
BIO * BIO_push(BIO *b, BIO *append);
	- b: 要插入到連結清單中的頭結點
	- append: 頭結點的後繼
// 把名為b的BIO從一個BIO鍊中移除并傳回下一個BIO,如果沒有下一個BIO,那麼就傳回NULL。
BIO * BIO_pop(BIO *b);

typedef struct buf_mem_st BUF_MEM;
struct buf_mem_st {
    size_t length;              /* current number of bytes */
    char *data;
    size_t max;                 /* size of buffer */
    unsigned long flags;
};
// 該函數也是一個宏定義函數,它将b底層的BUF_MEM結構放在指針pp中。
BUF_MEM* ptr;
long BIO_get_mem_ptr(BIO *b, BUF_MEM **pp);
// 釋放整個bio鍊
void BIO_free_all(BIO *a);

           

BIO

内部維護了一條雙向連結清單,這使得構造好一個

BIO

連結清單之後,具體的業務操作會變的非常友善,整個

BIO

鍊會自動将資料進行指定操作的系列處理。

下圖描述了一條讀寫的

BIO

鍊。

Base64編解碼Base64編解碼

5、

BIO

鍊的寫操作

char* data = "hello, world";
// 建立base64編碼的bio對象
BIO* b64 = BIO_new(BIO_f_base64());
// 最終在記憶體中得到一個base64編碼之後的字元串
BIO* mem = BIO_new(BIO_s_mem());
// 将兩個bio對象串聯, 結構: b64->mem
BIO_push(b64, mem);
// 将要編碼的資料寫入到bio對象中
BIO_write(b64, data, strlen(data)+1);
// 将資料從bio對象對應的記憶體中取出 -> char*
BUF_MEM* ptr;
// 資料通過ptr指針傳出
long BIO_get_mem_ptr(b64, &ptr);
char* buf = new char[ptr->length];
memcpy(buf, ptr->data, ptr->length);
printf("編碼之後的資料: %s\n", buf);
           

6、

BIO

鍊的讀操作

// 要解碼的資料
char* data = "xxxxxxxxxxxxxxxxxxxx";
// 建立base64解碼的bio對象
BIO* b64 = BIO_new(BIO_f_base64());
#if 0
// 存儲要解碼的資料
BIO* mem = BIO_new(BIO_s_mem());
// 将資料寫入到mem對應的記憶體中
BIO_write(mem, data, strlen(data));
#else
BIO *mem = BIO_new_mem_buf(data, strlen(data));
#endif
 
// 組織bio鍊
BIO_push(b64, mem);
// 讀資料
char buf[1024];
int BIO_read(b64, buf, 1024);
printf("base64解碼的資料: %s\n", buf);
           

7、總結

  • Base64編解碼可以有效的降低資料傳輸中出錯的可能性
  • Base64編解碼可以解決資料傳輸過程中,資料長度發生變化,導緻

    Openssl

    庫中的接口

    API

    報錯的情況(作為函數參數傳遞)。
  • BIO

    内部維護了一條雙向連結清單,構造好一套

    BIO

    鍊之後,指定頭節點後,

    BIO

    鍊會自動将資料進行指定操作的系列處理。
  • 封裝Base64思想編解碼(待續)。

繼續閱讀