【密码学】一文读懂Base64

简介: 本文来聊一聊Base64, 我个人感觉这个不应该算是加密,而应该是编码,相比于加密算法和哈希函数而言,今天要聊的还是比较轻松的(个人感觉)。

一文读懂Base64


8I)$ZUL6HB00R0[E@~`DVO2.jpg一文读懂Base64

本文来聊一聊Base64, 我个人感觉这个不应该算是加密,而应该是编码,相比于加密算法和哈希函数而言,今天要聊的还是比较轻松的(个人感觉)。


什么是Base64?

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

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


Base64的工作原理

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

Base64索引表

P1O@2]9ZZ9B~YJJLNM{N]]3.jpg

image.gifBase64索引表

编码方案

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

[P9H9E6MXTREEKJWS9W27_R.png

image.gif编码方案

编码样例

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

MOA3J)NZ9`1@HW[{L@YT(%N.jpg

编码样例

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

B`40X5A]RY5``)@[9UXS3XG.jpgBase64Padding

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


编码实现

const BASE64_PADDING_CHAR: char = '=';
const BASE64_TABLE: [char; 64] = [
    '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] & 0xff) as u32) << 16 | ((data[i + 1] & 0xff) as u32) << 8 | (data[i + 2] & 0xff) as u32;
            result.push(BASE64_TABLE[((bits >> 18) & 0x3f) as usize]);
            result.push(BASE64_TABLE[((bits >> 12) & 0x3f) as usize]);
            result.push(BASE64_TABLE[((bits >> 6) & 0x3f) as usize]);
            result.push(BASE64_TABLE[(bits & 0x3f) as usize]);
        }
        // padding
        match data.len() % 3 {
            1 => {
                let bits: u32 = (((data[data.len() - 1] & 0xff) as u32) << 4) as u32;
                result.push(BASE64_TABLE[((bits >> 6) & 0x3f) as usize]);
                result.push(BASE64_TABLE[(bits & 0x3f) as usize]);
                result.push(BASE64_PADDING_CHAR);
                result.push(BASE64_PADDING_CHAR);
            }
            2 => {
                let bits = ((data[data.len() - 2] & 0xff) as u32) << 10 | ((data[data.len() - 1] & 0xff) as u32) << 2;
                result.push(BASE64_TABLE[((bits >> 12) & 0x3f) as usize]);
                result.push(BASE64_TABLE[((bits >> 6) & 0x3f) as usize]);
                result.push(BASE64_TABLE[(bits & 0x3f) as 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()));
    }
}


相关文章
|
存储 Rust 并行计算
【密码学】一文读懂XTS模式
这篇文章的灵感来源于我偶然翻到的一个某U盘有关磁盘加密的一个介绍(这一篇不是广告蛤), 然后发现这个模式我之前还真没遇到过,因此呢,就学习了一下,就出来了这一篇文章。
5155 0
【密码学】一文读懂XTS模式
|
Rust 算法 Go
【密码学】一文读懂MurMurHash3
本文应该是MurMurHash算法介绍的最后一篇,来一起看一下最新的MurMurHash算法的具体过程,对于最新的算法来说,整个流程和之前的其实也比较相似,这里从维基百科当中找到了伪代码,也就不贴出来Google官方给出的推荐代码了,先来看一下维基百科给出的伪代码,这里只有32位的伪代码。
2160 0
【密码学】一文读懂MurMurHash3
|
算法 数据安全/隐私保护
【密码学】一文读懂Whirlpool
首先呢,祝大家今晚节日快乐,Whirlpool是由Vincent Rijmen(高级加密标准的联合创始人)和Paulo S.L.M.Barreto设计的,后者于2000年首次提出了它。
1107 0
【密码学】一文读懂Whirlpool
|
Rust 算法 安全
【密码学】一文读懂MurMurHash2
上次我们聊过了一代的MurMurHash算法,是的,我又来水文章了,今天呢,接着来聊一下二代的MurMurHash算法,二代算法的整体结构实际上和一代算法差不太多,只是对于每一轮数据的处理过程当中的运算有一些差异,算法的来源依然是来自于Google官网给提供的源码,对着源码看的结构,对于这个算法呢,有两个版本,一个是32位的,一个是64位的,对于32位的算法和64位的算法,区别在于两个初始的魔数不同,整体运算过程还是十分相似的。
2204 0
【密码学】一文读懂MurMurHash2
|
Rust 算法 网络安全
【密码学】一文读懂CMAC
介于上一篇文章比较水,然后这个和上一篇也比较相似,CMAC是为了解决DAA当中安全性不足的问题而出现的,这个算法一共有三个密钥,K, K1, K2, 其中K1和K2可以由K导出,接下来就来一起看一下CMAC的具体过程吧,这一篇文章其实也不长。
3737 0
【密码学】一文读懂CMAC
|
Web App开发 Rust 算法
【密码学】一文读懂ChaCha20
好久没写新的加密算法的原理了, 这次所选取的加密算法结构比较简单, 一起来看一下吧。
7686 0
【密码学】一文读懂ChaCha20
|
算法 安全 Go
【密码学】一文读懂HKDF
我这又来水一篇文章,来聊一下HKDF(基于HMAC的密钥导出函数)。密钥派生函数是密钥管理的组成部分,他的目标是通过一些初始的数据派生出来密码学安全的随机密钥。
3085 1
【密码学】一文读懂HKDF
|
Rust 算法 数据安全/隐私保护
【密码学】一文读懂SM3
SM3是中华人民共和国政府采用的一种密码散列函数标准,前身为SCH4杂凑算法,由国家密码管理局于2010年12月17日发布,相关标准为&quot;GM/T 0004-2012 《SM3密码杂凑算法》&quot;。
3418 0
【密码学】一文读懂SM3
|
算法 数据安全/隐私保护
【密码学】一文读懂SHA-1
SHA-1(Secure Hash Algorithm 1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦资料处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。
1214 1
【密码学】一文读懂SHA-1
|
算法 搜索推荐 安全
【密码学】一文读懂CCM
本文简单介绍了CCM模式下的认证和加密机制,实际上这个是AES-CTR模式和CMAC的一个组合,如果理解了前面这两个,本文应该还是比较好理解的。
3396 0
【密码学】一文读懂CCM