--- title: 编码和加密 date: 2021-05-24 15:41:47 order: 06 categories: - 设计 - 架构 - 安全 tags: - 架构 - 安全 - 加密 - 消息摘要 - 数字签名 - 对称加密 - 非对称加密 - MD5 - SHA - HMAC - AES - DES - RSA permalink: /pages/7684cf16/ --- # 编码和加密 > 关键词:`Base64`、`消息摘要`、`数字签名`、`对称加密`、`非对称加密`、`MD5`、`SHA`、`HMAC`、`AES`、`DES`、`DESede`、`RSA` ## Base64 编码 ### Base64 原理 Base64 内容传送编码是一种以任意 8 位字节序列组合的描述形式,这种形式不易被人直接识别。 Base64 是一种很常见的编码规范,其作用是将二进制序列转换为人类可读的 ASCII 字符序列,常用在需用通过文本协议(比如 HTTP 和 SMTP)来传输二进制数据的情况下。**Base64 并不是加密解密算法**,尽管我们有时也听到使用 Base64 来加密解密的说法,但这里所说的加密与解密实际是指**编码(encode)**和**解码(decode)**的过程,其变换是非常简单的,仅仅能够避免信息被直接识别。 Base64 算法主要是将给定的字符以字符编码(如 ASCII 码,UTF-8 码)对应的十进制数为基准,做编码操作: 1. 将给定的字符串以字符为单位,转换为对应的字符编码。 2. 将获得字符编码转换为二进制 3. 对二进制码做分组转换,每 3 个字节为一组,转换为每 4 个 6 位二进制位一组(不足 6 位时低位补 0)。这是一个分组变化的过程,3 个 8 位二进制码和 4 个 6 位二进制码的长度都是 24 位(3*8 = 4*6 = 24)。 4. 对获得的 4-6 二进制码补位,向 6 位二进制码添加 2 位高位 0,组成 4 个 8 位二进制码。 5. 对获得的 4-8 二进制码转换为十进制码。 6. 将获得的十进制码转换为 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 应用 Base64 编码可用于在 HTTP 环境下传递较长的标识信息。在其他应用程序中,也常常需要把二进制数据编码为适合放在 URL(包括隐藏表单域)中的形式。此时,采用 Base64 编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到,算是起到一个加密的作用。 然而,**标准的 Base64 并不适合直接放在 URL 里传输**,因为 URL 编码器会把标准 Base64 中的 `/` 和 `+` 字符变为形如 `%XX` 的形式,而这些 `%` 号在存入数据库时还需要再进行转换,因为 ANSI SQL 中已将 `%` 号用作通配符。 为解决此问题,可采用一种用于 URL 的改进 Base64 编码,它不仅在末尾填充 `=` 号,并将标准 Base64 中的“+”和“/”分别改成了 `-` 和 `_`,这样就免去了在 URL 编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。 另有一种用于正则表达式的改进 Base64 变种,它将 `+` 和 `/` 改成了 `!` 和 `-`,因为 `+`, `*` 以及前面在 IRCu 中用到的 `[` 和 `]` 在正则表达式中都可能具有特殊含义。 ## 消息摘要 ### 消息摘要概述 **消息摘要,其实就是将需要摘要的数据作为参数,经过哈希函数(Hash)的计算,得到的散列值**。 消息摘要是一个唯一对应一个消息或文本的固定长度的值,它由一个单向 Hash 加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向 Hash 函数将需加密的明文"摘要"成一串密文,这一串密文亦称为数字指纹(Finger Print)。它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。 ### 消息摘要特点 - 唯一性:数据只要有一点改变,那么再通过消息摘要算法得到的摘要也会发生变化。虽然理论上有可能会发生碰撞,但是概率极其低。 - 不可逆:消息摘要算法的密文无法被解密。 - 不需要密钥,可使用于分布式网络。 - 无论输入的明文有多长,计算出来的消息摘要的长度总是固定的。 ### 消息摘要常用算法 消息摘要算法包括**MD(Message Digest,消息摘要算法)**、**SHA(Secure Hash Algorithm,安全散列算法)**、**MAC(Message AuthenticationCode,消息认证码算法)**共 3 大系列,常用于验证数据的完整性,是数字签名算法的核心算法。 **MD5**和**SHA1**分别是**MD**、**SHA**算法系列中最有代表性的算法。 如今,MD5 已被发现有许多漏洞,从而不再安全。SHA 算法比 MD 算法的摘要长度更长,也更加安全。 ## 数字签名 数字签名算法可以看做是一种带有密钥的消息摘要算法,并且这种密钥包含了公钥和私钥。也就是说,**数字签名算法是非对称加密算法和消息摘要算法的结合体**。 数字签名算法要求能够验证数据完整性、认证数据来源,并起到抗否认的作用。 数字签名算法包含签名和验证两项操作,遵循私钥签名,公钥验证的方式。 签名时要使用私钥和待签名数据,验证时则需要公钥、签名值和待签名数据,其核心算法主要是消息摘要算法。 ![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/advanced/java-message-digest-process.jpg) 数字签名常用算法:**RSA**、**DSA**、**ECDSA** ## 对称加密 对称加密算法主要有 DES、3DES(TripleDES)、AES、IDEA、RC2、RC4、RC5 和 Blowfish 等。 对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yao)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。 对称加密特点: - 优点:计算量小、加密速度快、加密效率高。 - 缺点:算法是公开的,安全性得不到保证。 通信双方每次使用对称加密算法时,都需要使用其他人不知道的惟一密钥,这会使得通信双方所拥有的密钥数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。 而与公钥、密钥加密算法比起来,对称加密算法能够提供加密和认证却缺乏了签名功能,使得使用范围有所缩小。 ### 对称加密原理 对称加密要求加密与解密使用同一个密钥,解密是加密的逆运算。由于加密、解密使用同一个密钥,这要求通信双方必须在通信前商定该密钥,并妥善保存该密钥。 对称加密体制分为两种: 一种是对明文的单个位(或字节)进行运算,称为流密码,也称为序列密码; 一种是把明文信息划分为不同的组(或块)结构,分别对每个组(或块)进行加密、解密,称为分组密码。 ![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/advanced/symmetric-encryption.png) 假设甲乙方作为通信双方。假定甲乙双方在消息传递前已商定加密算法,欲完成一次消息传递需要经过如下步骤。 ![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/advanced/symmetric-encryption-progress.png) ### 对称加密工作模式 以 DES 算法的工作模式为例,DES 算法根据其加密算法所定义的明文分组的大小(56 位),将数据分割成若干 56 位的加密区块,再以加密区块为单位,分别进行加密处理。如果最后剩下不足一个区块的大小,称之为**短块**。短块的处理方法有填充法、流密码加密法、密文挪用技术。 根据数据加密时每个加密区块见得关联方式来区分,可以分为以下种工作模式: **(1) 电子密码本模式(Electronic Code Book, ECB)** 用途:适合加密密钥,随机数等短数据。例如,安全地传递 DES 密钥,ECB 是最合适的模式。 **(2) 密文链接模式(Cipher Booki Chaining, CBC)** 用途:可加密任意长度的数据,适用于计算产生检测数据完整性的消息认证 MAC。 **(3) 密文反馈模式(Cipher Feed Back, CFB)** 用途:因错误传播无界,可以用于检查发现明文密文的篡改。 **(4) 输出反馈模式(Output Feed Back, OFB)** 用途:使用于加密冗余性较大的数据,比如语音和图像数据。 AES 算法除了以上 4 中模式外,还有一种新的工作模式: **(5) 计数器模式(Counter, CTR)** 用途:适用于各种加密应用。 本文对于各种工作模式的原理展开描述。个人认为,作为工程应用,了解其用途即可。 ### 对称加密填充方法 Java 中对称加密对于短块的处理,一般是采用填充方式。 常采用的是:NoPadding(不填充)、Zeros 填充(0 填充)、PKCS5Padding 填充。 **ZerosPadding** 方式:全部填充为 0 的字节 结果如下: F1 F2 F3 F4 F5 F6 F7 F8 //第一块 F9 00 00 00 00 00 00 00 //第二块 **PKCS5Padding** 方式:每个填充的字节都记录了填充的总字节数 结果如下: F1 F2 F3 F4 F5 F6 F7 F8 //第一块 F9 07 07 07 07 07 07 07 //第二块 ### 基于口令加密的流程(PBE) DES、DESede、AES、IDEA 这几种算法的应用模型几乎如出一辙。 但是,并非所有对称加密算法都是如此。 基于口令加密(Password Based Encryption, PBE)是一种基于口令加密的算法。其特点是:口令由用户自己掌管,采用随机数(这里叫做盐)杂凑多重加密等方法保证数据的安全性。 PBE 没有密钥概念,密钥在其他对称加密算法中是经过计算得出的,PBE 则使用口令替代了密钥。 流程: ![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/advanced/password-based-encryption-progress.png) ## 非对称加密 非对称加密常用算法:DH(Diffie-Hellman,密钥交换算法)、RSA 非对称加密算法和对称加密算法的主要差别在于非对称加密算法用于加密和解密的密钥是不同的。一个公开,称为公钥(public key);一个保密,称为私钥(private key)。因此,非对称加密算法也称为双钥加密算法或公钥加密算法。 非对称加密特点: - 优点:非对称加密算法解决了对称加密算法的密钥分配问题,并极大地提高了算法安全性。 - 缺点:算法比对称算法更复杂,因此加密、解密速度都比对称算法慢很多。 ![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/advanced/asymmetric-encryption.png) 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。 另一方面,甲方可以使用乙方的公钥对机密信息进行签名后再发送给乙方;乙方再用自己的私匙对数据进行验证。 甲方只能用其私钥解密,由其公钥加密后的任何信息。 非对称加密算法的保密性比较好,它消除了最终用户交换密钥的需要。 ## 术语 - **明文(Plaintext)**:指待加密信息。明文可以是文本文件、图片文件、二进制数据等。 - **密文(Ciphertext)**:指经过加密后的明文。密文通常以文本、二进制等形式存在。 - **加密(Encryption)**:指将明文转换为密文的过程。 - **解密(Decryption)**:指将密文转换为明文的过程。 - **加密密钥(Encryption Key)**:指通过加密算法进行加密操作用的密钥。 - **解密密钥(Decryption Key)**:指通过解密算法进行解密操作用的密钥。 - **信道(Channel)**:通信的通道,是信号传输的媒介。 ## 参考资料 - [《Java 核心技术 卷 II 高级特性》](https://book.douban.com/subject/27165931/) - [《Java 加密与解密的艺术》](https://book.douban.com/subject/25861566/)