zoukankan      html  css  js  c++  java
  • (基础篇 04) C++ base64 编解码原理及实现

    Base64原理

    Base64 是一种基于 64 个可打印字符来表示二进制数据的表示方法。由于 2^6 = 64,所以每 6 个比特为一个单元,对应某个可打印字符。3 个字节有 24 个比特,对应于 4 个 Base64 单元,即 3 个字节可由 4 个可打印字符来表示。它可用来作为电子邮件的传输编码。在 Base64 中的可打印字符包括字母 A-Za-z、数字 0-9+, /

    Base64 常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括 MIME 的电子邮件及XML的一些复杂数据。

    Base64 的索引表如下:

    数值 字符 数值 字符 数值 字符 数值 字符
    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 /

    示例:将 Man 编码得到 TWFu
    在这里插入图片描述

    如果要编码的字节数不能被 3 整除,最后会多出 1 个或 2 个字节,那么可以使用下面的方法进行处理:先使用 0 字节值在末尾补足,使其能够被 3 整除,然后再进行 Base64 的编码。在编码后的 Base64 文本后加上一个或两个 = 号,代表补足的字节数。也就是说,当最后剩余两个八位(待补足)字节(2 个 byte)时,最后一个 6 位的 Base64 字节块有四位是 0 值,最后附加上两个等号;如果最后剩余一个八位(待补足)字节( 1 个 byte)时,最后一个 6 位的 base 字节块有两位是 0 值,最后附加一个等号。
    在这里插入图片描述

    C++ 代码

    base64 编解码的 c++ 代码如下所示,代码来源:github

    // https://github.com/ReneNyffenegger/cpp-base64
    #include "base64.h"
    #include <iostream>
    
    // there are 64 characters
    static const std::string base64_chars =
    		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    		"abcdefghijklmnopqrstuvwxyz"
    		"0123456789+/";
    
    
    static inline bool is_base64(unsigned char c) {
    	return (isalnum(c) || (c == '+') || (c == '/'));
    }
    
    std::string base64_encode(const char *bytes_to_encode, unsigned int in_len) {
    	std::string ret;
    	int i = 0;
    	int j = 0;
    	unsigned char char_array_3[3];  // store 3 byte of bytes_to_encode
    	unsigned char char_array_4[4];  // store encoded character to 4 bytes
    
    	while (in_len--) {
    		char_array_3[i++] = *(bytes_to_encode++);  // get three bytes (24 bits)
    		if (i == 3) {
    			// eg. we have 3 bytes as ( 0100 1101, 0110 0001, 0110 1110) --> (010011, 010110, 000101, 101110)
    			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; // get first 6 bits of first byte,
    			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); // get last 2 bits of first byte and first 4 bit of second byte
    			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); // get last 4 bits of second byte and first 2 bits of third byte
    			char_array_4[3] = char_array_3[2] & 0x3f; // get last 6 bits of third byte
    
    			for (i = 0; (i < 4); i++)
    				ret += base64_chars[char_array_4[i]];
    			i = 0;
    		}
    	}
    
    	if (i)
    	{
    		for (j = i; j < 3; j++)
    			char_array_3[j] = '';
    
    		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    
    		for (j = 0; (j < i + 1); j++)
    			ret += base64_chars[char_array_4[j]];
    
    		while ((i++ < 3))
    			ret += '=';
    
    	}
    
    	return ret;
    
    }
    
    std::string base64_decode(const std::string& encoded_string) {
    	size_t in_len = encoded_string.size();
    	int i = 0;
    	int j = 0;
    	int in_ = 0;
    	unsigned char char_array_4[4], char_array_3[3];
    	std::string ret;
    
    	while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
    		char_array_4[i++] = encoded_string[in_]; in_++;
    		if (i == 4) {
    			for (i = 0; i < 4; i++)
    				char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff;
    
    			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
    			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
    			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
    
    			for (i = 0; (i < 3); i++)
    				ret += char_array_3[i];
    			i = 0;
    		}
    	}
    
    	if (i) {
    		for (j = 0; j < i; j++)
    			char_array_4[j] = base64_chars.find(char_array_4[j]) & 0xff;
    
    		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
    		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
    
    		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
    	}
    
    	return ret;
    }
    
  • 相关阅读:
    http编程中的get和post混合使用方式
    SQLServer实现作业依赖(非步骤)
    SQLServer实现两个库的字段长度自动更新
    Python+SQLite数据库实现服务端高并发写入
    sqlite数据库相关使用
    sqlite语法
    VBA关键字总结
    VS2005 .net2.0 TreeView.设置SelectedNodeStyle控制TreeView中选定节点的外观的
    SQLSERVER 2005 如何给sa用户设置空密码?
    解决超过远程连接数而无法连接服务器的问题 踢出已断开用户
  • 原文地址:https://www.cnblogs.com/busyboxs/p/12245419.html
Copyright © 2011-2022 走看看