了解Base64编码算法:原理、应用与实现

677 阅读9分钟

在计算机编程和网络通信中,Base64编码是一种常见的数据编码方式。它被广泛应用于将二进制数据转换为可打印字符的场景,例如在电子邮件传输、URL编码、数据传输等方面。本文将介绍Base64编码的原理、应用和实现方式。

基础定义

base64,为啥是64?Base64是基于64个可打印字符来表示二进制数据的编解码方式。 哪64个字符? 大写字母A-Z、小写字母a-z 、数字0-9共62个,然后加上+ 和/,这样总共64个(其实还有一个作为后缀的”=“,一共65个字符)。

Base64是一种索引编码,每个字符都对应一个索引,具体的关系图,如下:

为什么要使用Base64

  1. 文本传输:

    许多传输协议和数据存储格式只支持文本数据。通过Base64编码,可以将二进制数据(如图片、音频、视频等)转换为文本数据,从而方便在文本环境中传输和存储。

  2. 字符安全性:

    Base64编码后的数据只包含A-Z、a-z、0-9、+、/等64个字符,避免了在传输过程中出现特殊字符造成的问题,提高了数据的安全性和可靠性。

  3. URL编码:

    在URL中包含特殊字符可能会导致解析错误,而Base64编码可以将特殊字符转换为URL安全的字符,从而避免URL传输中的问题。

4.数据加密

尽管Base64编码不是一种加密算法,但它可以对数据进行简单的“混淆”,使得原始数据不直接暴露在传输过程中,增加了数据的保密性。

简而言之,Base64编码是一种简单而有效的数据编码方式,适用于将二进制数据转换为文本数据,以便在各种环境中进行传输和存储。

Base64编码原理

由于64等于2的6次方,所以一个Base64字符实际上代表着6个二进制位(bit)。然而,二进制数据1个字节(byte)对应的是8比特(bit),因此,3字节(3 x 8 = 24比特)的字符串/二进制数据正好可以转换成4个Base64字符(4 x 6 = 24比特)。

为什么是3个字节一组呢?因为6和8的最小公倍数是24,24比特正好是3个字节。

Base64编码的原理很简单,它将原始数据(通常是二进制数据)转换为由64个字符组成的ASCII字符串。具体步骤如下:

  1. 将原始数据按照每3个字节一组进行分组。
  2. 将每组3个字节的数据转换为4个6位的数字(0-63之间的值)。
  3. 将这些6位的数字映射到Base64字符表中的对应字符。
  4. 如果原始数据的字节数不是3的倍数,则在末尾补充0,并在Base64编码的末尾添加1到2个“=”字符作为填充。

计算字节数时,会直接使用总长度除以3,如果余数为1则会直接在最后补一个“=”,如果余数为2则补两个“=”。

ASCII码

上面说到,我们最终是将原始数据转换为ASCII字符串,下面我们也简单讲一下ASCII。我们知道一个字节可表示的范围是 0 ~ 255(十六进制:0x00 ~ 0xFF), 其中 ASCII 值的范围为 0 ~ 127(十六进制:0x00 ~ 0x7F);而超过 ASCII 范围的128~255(十六进制:0x80 ~ 0xFF)之间的值是不可见字符。

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本延伸美国标准信息交换码则可以部分支持其他西欧语言,并等同于国际标准 ISO/IEC 646。

在 ASCII 码中 0 - 31和 127 是控制字符,共33 个。其余 95 个,即 32 - 126 是可打印字符,包括数字、大小写字母、常用符号等。

For example

说了那么多,那么最终的结果是怎么计算出来的呢?下面我们举一个简单的例子。

首先我们用fiddler简单编码一个字符串“ITPronHub”

1.  将字符串 "ITPronHub" 转换为 ASCII 码的二进制表示:

  • I:73  => 01001001
  • T:84  => 01010100
  • P:80  => 01010000
  • r:114 => 01110010
  • o:111 => 01101111
  • H:72 =>  01001000
  • u:117 => 01110101
  • b:98 => 01100010

2.  将这些二进制数按照每3个字节一组分组:

        3个字节作为1组,这样就有一共24个二进制位,然后这对这24个二进制位分为4组,每组6个二进制位

010010 010101 000101 010000 011110 010011 011011 011011 100100 100010

3.   根据base64索引表,我们将每组6位数字转换为对应的Base64字符:

这个例子刚好涉及了base64编码里面的两个特殊点:

  • 6个一组,最后还剩下4位“0010”。因此我们在后面补上2个0,结果为“001000”
  • 上面编码原理里面第4点说到了“=”的逻辑。这个例子中总长度为8*8=64,64除以3,余数为1。所以在最后我们加上1个“=”

4. 将转换后的Base64字符连接起来得到最终的Base64编码字符串:

SVRQcm9IdWI=

体积增大

当使用 Base64 编码将二进制数据转换为 ASCII 字符串时,会导致数据体积增大的主要原因是编码过程中引入了额外的字符。让我详细说明一下:

1. 数据扩展:

 在 Base64 编码中,每个原始数据字节会转换为相应的 Base64 字符。而原始数据是以 8 位(一个字节)为单位存储的,而 Base64 编码后的字符是以 6 位(不足一个字节)为单位表示的。这样,每 3 个原始数据字节(24 位)将编码为4 个 Base64 字符(24 位)。这导致了数据的膨胀。

2. 填充字符:

 如果原始数据的长度不是 3 的倍数,编码过程中需要填充额外的字符以使得每个片段都是完整的。通常使用的填充字符是 "="。虽然填充字符并不包含任何信息,但它们仍然增加了编码后数据的长度。

Base64的算法实现

下面给了一段简单的代码,实现base64的核心功能

using System;

class Program
{
    static void Main()
    {
        // 待编码的字符串
        string originalString = "Hello, world!";

        // 将字符串转换为字节数组
        byte[] bytesToEncode = System.Text.Encoding.UTF8.GetBytes(originalString);

        // 对字节数组进行Base64编码
        string encodedString = CustomBase64Encode(bytesToEncode);

        // 输出编码后的字符串
        Console.WriteLine("Base64 编码结果: " + encodedString);
    }

    // 自定义 Base64 编码函数
    static string CustomBase64Encode(byte[] input)
    {
        const string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        string result = "";
        int i = 0;
        int len = input.Length;
        byte[] block = new byte[3];
        int end = 0;

        while (i < len)
        {
            block[0] = input[i++];
            end = (i == len) ? 1 : 0;
            block[1] = (end != 1) ? input[i++] : (byte)0;
            end = (i == len) ? 1 : 0;
            block[2] = (end != 1) ? input[i++] : (byte)0;

            int b1 = block[0] >> 2;
            int b2 = ((block[0] & 0x03) << 4) | (block[1] >> 4);
            int b3 = ((block[1] & 0x0F) << 2) | (block[2] >> 6);
            int b4 = block[2] & 0x3F;

            if (end == 1)
            {
                if (i == len + 1)
                    b4 = 64;
                else
                    b4 = block[2] >> 2;
            }

            result += base64Chars[b1];
            result += base64Chars[b2];
            result += (end != 1) ? base64Chars[b3] : '=';
            result += (end != 1) ? base64Chars[b4] : '=';
        }

        return result;
    }
}

Base64编码应用

Base64编码在很多场景下都有应用:

  • 显示base64编码的图片:在编写 HTML 网页时,对于一些简单图片,通常会选择将图片内容直接内嵌在网页中,从而减少不必要的网络请求。

    <image id="icon-integrate-aly_r7m05e0de__image0_811_8579" width="212" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANQAAAAwCAMAAABe1aS+AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAA5UExURUdwTP9qAP9rAP9rAP9qAP9sAP9rAP9rAP9sAP9uAP96AP9sAP9qAP9rAP9qAP9rAP9wAP9rAP9qAKqb9/8AAAASdFJOUwDzg3nnUGWiPSMINLNajsQU04rSIgoAAAN9SURBVGje7ZrZlqMgEIZZZRU17/+w05IREAtER5N0zvynLzqCysdSUFUitEjxvsvUo1xEZHJUok/V6Nhjq217DVCLuXFTT2adoztY+vn2blfjcSaKgcY+CFCTQBUxzavZdTkaH7CebVWPXZmlV/Guns/UAnzOpCH+Aaxr9Yug5H5VBbQgtESBg6owTPVhUAQu6wpTtYOru4+CMuDUI6a4AA2Zaq+NUI7+yJsSpGkmP4sF1QmUC4XYr9NFbrWm2K5GcPINVO0YFkW3S2vYQKmlvbZgcPjyuGQtzGK+I1Baag4ZvmzosW20nmNvcXmoAlQ//0NfDUVTIsH1gVs1F7iwAwQoB+93N0Ml88iNJzZteP4FKL/89KuhpoL9alW0nQyA0t7qzFd4H6VAKBrKvaEIv+hxqDCBmD4FpeP5CoCSobfSYxgHoZpMepv+caDSodJbKN/L/fugupNQfQ0qrK03QfUnoXgNKi7574FKtt4ZChMylKEcWYSfdf/KfRhUF7deDxVh7jXpt0KJuPV+D5TfBKWUl0HJFpkylC7pABRbXI+LoPSjRVMZqnjPXVCUL/KGIvzqfjNUg0n/D3UXlBPeObkMCoV4ozdBTIAi90JFmIug1s4FPWzSRUnXQ41uJX/zsL6mgJfi8T1nvzYoKF5F911bh74KymQb21dAiUKM6jdDqT1v5KVQ4zNQk0PRH/Nj459fMNP62ipZ4TZxxjdClZxEu2/SUwSNK8N8jTvfvRyKhhDVynhwyaW6KPDiXg7FwDEgSbUQIsPjKaYYIsNQMHPEl0P1cEDPv+mvRxqDmeIUlKgFM9UzQTKX2CFK5scks5Ivc+trKtt4SdXOJ71kzWEkZathZw5m5MKkPWXSZWlaJa5mdyyJU0no0CIULZxzTkHZ4qyKJepAuq2eelMlqKF0zpEnoFT5hJSM4TaLzfYyOpoDXyhYVIASwBcJLEmOHoNylRNSXG1gZhrbvsjVC1xOimeGou/5uuUqeHixaS7zbXzbhoLHg8HC1HPUlcw02U0IVPLetjRHDPDtCWty0vd816wlDi6UlVP/RgIdhiLoHihb63wGTXk9NQ1rAxRBN0Et/cunht5HsFmZ8Tk6CIXTPfFaKBZeqzvo85y+ciRPNrdua1PUHP6FTI32gWG1KjJNwWTUFng2q0drZbZB6Y21zT/y6Pi5I+Ot+gNPpCJomQTojgAAAABJRU5ErkJggg=="></image>
    
  • 电子邮件传输:在电子邮件中,二进制数据(如图片、附件等)需要转换成文本格式才能进行传输,而Base64编码正好能够实现这一目的。

  • URL编码:在URL中包含特殊字符可能会引起解析错误,因此需要对特殊字符进行编码。Base64编码可以将特殊字符转换为安全的URL可用字符。

  • 数据传输:在网络通信中,一些数据格式可能不支持二进制传输,因此需要将其转换为Base64编码格式进行传输。

需要注意的是,大家都知道中文编码有很多种,例如**「GB2312、GBK、GB18030」。** 不同的汉字使用不同的编码格式进行编码后,它的二进制是不同的,所以在进行Base64编码后,他们的Base64编码的值也是不同的。这就要求我们在解码的时候需要注意原文的字符集格式,一定要保持一致才能正确解码。

结语

Base64编码是一种简单而有效的数据编码方式,广泛应用于数据传输和存储场景中。了解Base64编码的原理和应用能够帮助我们更好地理解网络通信和数据处理过程。

更多一手讯息,可关注公众号:ITProHub