小码农

好记性不如烂笔头....

Base64 编码解码初探

Base64编码过程初探

Base64 算法

Base64编码在数据传输过程中应用广泛,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就不能通过邮件传送。这样就受到了很大的限制,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了。正好Base64编码使用64个可见字符来表示二进制数据。

《Base64 编码解码初探》

由图中可以看出base64编码过程:

  • 取原文本二进制位
  • 对源文本二进制位按6位划分得到base64划分二进制位
  • 在base64划分二进制位前面添加两个0,得到base64字典索引
  • 查base64表,得到base64对应的值

附Base64表

0 A  17 R   34 i   51 z

1 B  18 S   35 j   52 0

2 C  19 T   36 k   53 1

3 D  20 U   37 l   54 2

4 E  21 V   38 m   55 3

5 F  22 W   39 n   56 4

6 G  23 X   40 o   57 5

7 H  24 Y   41 p   58 6

8 I  25 Z   42 q   59 7

9 J  26 a   43 r   60 8

10 K  27 b   44 s   61 9

11 L  28 c   45 t   62 +

12 M  29 d   46 u   63 /

13 N  30 e   47 v

14 O  31 f   48 w

15 P  32 g   49 x

16 Q  33 h   50 y

代码中声明的Base64表(NodeJS)

const base64EncodeDict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const baseDecodeDict = { '0': 52, '1': 53, '2': 54, '3': 55, '4': 56, '5': 57, '6': 58, '7': 59, '8': 60, '9': 61, A: 0, B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10, L: 11, M: 12, N: 13, O: 14, P: 15, Q: 16, R: 17, S: 18, T: 19, U: 20, V: 21, W: 22, X: 23, Y: 24, Z: 25, a: 26, b: 27, c: 28, d: 29, e: 30, f: 31, g: 32, h: 33, i: 34, j: 35, k: 36, l: 37, m: 38, n: 39, o: 40, p: 41, q: 42, r: 43, s: 44, t: 45, u: 46, v: 47, w: 48, x: 49, y: 50, z: 51, '+': 62, '/': 63 };

Base64 算法解析

我们通过上面的图可以看出,每3字节源文本会生成4字节base64编码("Nod" 生成 "Tm9k"),那么我们在编码的时候每次处理三个字节的数据(生成不足4字节的用"="补充),处理步骤如下:

  • 取第一个字节的前6位并在前面加上00,这里我们使用"右移"
    ‘N’ => ‘01001110’ => 右移两位 => ‘00010011’ => 19 => 查表 => ‘T’
  • 取第一个字节的后2位(用’与’和’左移’),加上第二个字节的前4位
    ‘N’ => ‘01001110’ => 与 ‘00000011’ => ‘00000010’ => 左移4位 => ‘00100000’
    ‘o’ => ‘01101111’ => 右移4位 => ‘00000110’ => ‘00100000’ 加上 ‘00000110’ => ‘00100110’ => 查表 => ‘m’
  • 后面的依次类推,使用"与","右移","左移"操作将3字节变成4字节

编码代码(NodeJS)

const Base64Encode = (source) => {
    const aim = [];
    for (var i = 0; i < source.length; i += 3) {
        // 获取第一个字符
        let cr = source[i].charCodeAt();
        aim.push(base64EncodeDict[cr >> 2]);
        // 获取第二个字符
        if (i + 1 >= source.length) {
            aim.push(base64EncodeDict[((cr & 3) << 4)])
            aim.push('=', '=');
            break
        } else {
            aim.push(base64EncodeDict[((cr & 3) << 4) + (source[i + 1].charCodeAt() >> 4)]);
        }
        // 获取第三个字符
        if (i + 2 >= source.length) {
            aim.push(base64EncodeDict[((source[i + 1].charCodeAt() & 15) << 2)])
            aim.push('=');
        } else {
            aim.push(base64EncodeDict[((source[i + 1].charCodeAt() & 15) << 2) + (source[i + 2].charCodeAt() >> 6)])
            aim.push(base64EncodeDict[source[i + 2].charCodeAt() & 63]);
        }
    }
    return aim.join('');
}

解码同理,我们需要将4个字节同时处理,也是用"与","左移","右移"来实现

解码代码(NodeJS)

const Base64Decode = (source) => {
    const aim = [];
    for (var i = 0; i < source.length; i += 4) {
        aim.push((baseDecodeDict[source[i]] << 2) + (baseDecodeDict[source[i + 1]] >> 4))
        if (source[i + 2] === '=') {
            break
        } else {
            aim.push(((baseDecodeDict[source[i + 1]] & 15) << 4) + (baseDecodeDict[source[i + 2]] >> 2))
        }
        if (source[i + 3] === '=') {
            aim.push((baseDecodeDict[source[i + 2]] & 3) << 6)
        } else {
            aim.push(((baseDecodeDict[source[i + 2]] & 3) << 6) + (baseDecodeDict[source[i + 3]]))
        }
    }
    let r = [];
    for (var item of aim) {
        r.push(String.fromCharCode(item))
    }
    return r.join('');
}

实验结果(NodeJS)

《Base64 编码解码初探》

后面的事

整个编码解码过程中,我们可以看出来,编码表起着重要的作用,我们可以通过修改编码表,可以生成变异的Base64编码。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注