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個’=’, 表示補了多少位元組,解碼的時候,會自動去掉。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNyZuBnLwkDO3ATZhBzMlRTOmZTYiJ2YzQTYzMmZyQWO1YmM3UzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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
鍊。
5、 BIO
鍊的寫操作
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
鍊的讀操作
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思想編解碼(待續)。