【动画密码学】Base64编码&解码算法

admin 2024年10月7日20:44:18评论18 views字数 3393阅读11分18秒阅读模式

【动画密码学】Base64编码&解码算法

【动画密码学】Base64编码&解码算法

本文依然是一篇老的文章,我们还是直接来看动画了。

什么是Base64?

Base64(基底64)是一种基于64个可打印字符来表示二进制数据的表示方法。-- 维基百科

简单来说,小明和小红两个人想要互相传递信息,他们产生的数据只能是二进制的流数据(也就是01),但是小明和小红要想互相传递信息不能直接说,而要写在小纸条上,这个小纸条又无法承载01这时候今天的主角「Base64」就出现了,他可以吧二进制的数据流转换成为64个可见的字符。Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。

Base64的工作原理

首先要有一个索引表,标准 Base64 里的 64 个可打印字符是 A-Za-z0-9+/,分别依次对应索引值 0-63,标准的索引表如下:

Base64索引表

【动画密码学】Base64编码&解码算法
Base64索引表

编码方案

编码过程中,每三个字节(8bit * 3 = 24bit)一组进行编码,因为2^6 = 64因此每组有4个索引与之对应,如下图所示:

【动画密码学】Base64编码&解码算法
编码方案

编码样例

上面的图可能不是很清晰,下面来看一个具体的例子,如下图所示:

【动画密码学】Base64编码&解码算法
编码样例

可以发现,对于ABC的Base64编码为QUJD,这时候细心的读者可能发现了,如果输入的长度不是3的整数倍或者二进制流的数据不是24的整数倍那么将要如何处理呢。这里Base64采用的是直接Padding0的方案,也就是不足24bit最后一个分组直接Padding0。注意如果是Padding的数据,那么不能按照索引表去查0位置的索引,而是直接用=填充。下面还是来看一个例子吧:

【动画密码学】Base64编码&解码算法
Base64Padding

也就是说,如果剩余两个字节那么将会填充两个=, 如果剩余一个字节那么填充一个=

编码实现

const BASE64_PADDING_CHAR: char = '=';

const BASE64_TABLE: [char64] = [
    'A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P',
    'Q''R''S''T''U''V''W''X''Y''Z''a''b''c''d''e''f',
    'g''h''i''j''k''l''m''n''o''p''q''r''s''t''u''v',
    'w''x''y''z''0''1''2''3''4''5''6''7''8''9''+''/',
];

struct Base64 {}

impl Base64 {
    pub fn encode(data: &[u8]) -> String {
        if data.is_empty() {
            return String::new();
        }
        // 计算padding长度
        let encode_length = match (data.len() / 3, (data.len() % 3) != 0) {
            (data_length, true) => 4 * data_length + 4,
            (data_length, false) => 4 * data_length,
        };
        let mut result = String::with_capacity(encode_length);

        // 编码
        for i in (0..(data.len() / 3 * 3)).step_by(3) {
            let bits = ((data[i] & 0xffas u32) << 16 | ((data[i + 1] & 0xffas u32) << 8 | (data[i + 2] & 0xffas u32;
            result.push(BASE64_TABLE[((bits >> 18) & 0x3fas usize]);
            result.push(BASE64_TABLE[((bits >> 12) & 0x3fas usize]);
            result.push(BASE64_TABLE[((bits >> 6) & 0x3fas usize]);
            result.push(BASE64_TABLE[(bits & 0x3fas usize]);
        }

        // padding
        match data.len() % 3 {
            1 => {
                let bits: u32 = (((data[data.len() - 1] & 0xffas u32) << 4as u32;
                result.push(BASE64_TABLE[((bits >> 6) & 0x3fas usize]);
                result.push(BASE64_TABLE[(bits & 0x3fas usize]);
                result.push(BASE64_PADDING_CHAR);
                result.push(BASE64_PADDING_CHAR);
            }
            2 => {
                let bits = ((data[data.len() - 2] & 0xffas u32) << 10 | ((data[data.len() - 1] & 0xffas u32) << 2;
                result.push(BASE64_TABLE[((bits >> 12) & 0x3fas usize]);
                result.push(BASE64_TABLE[((bits >> 6) & 0x3fas usize]);
                result.push(BASE64_TABLE[(bits & 0x3fas usize]);
                result.push(BASE64_PADDING_CHAR);
            }
            _ => {}
        }
        return result;
    }
}

#[cfg(test)]
mod test {
    use crate::base64::Base64;

    #[test]
    fn test() {
        println!("Base64(ABC) = {}", Base64::encode("ABC".as_bytes()));
        println!("Base64(A) = {}", Base64::encode("A".as_bytes()));
        println!("Base64(AB) = {}", Base64::encode("AB".as_bytes()));
    }
}

参考资料

  • Base64 - 维基百科,自由的百科全书[1]
  • rfc1421[2]

Reference

[1]

Base64 - 维基百科,自由的百科全书: https://zh.wikipedia.org/wiki/Base64

[2]

rfc1421: https://datatracker.ietf.org/doc/html/rfc1421

原文始发于微信公众号(Coder小Q):【动画密码学】Base64编码&解码算法

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月7日20:44:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【动画密码学】Base64编码&解码算法https://cn-sec.com/archives/1990537.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息