从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

    • 我的 Java 学习路线
    • 安装 Java
    • Java 数据类型

    • Java 多版本配置
    • 面向对象

    • Java 核心类

    • IO

    • Java 与时间

    • 异常处理

    • 哈希和加密算法

      • 什么是哈希算法
      • 第三方库的哈希算法
      • MAC 算法
      • 加密算法介绍
      • 对称加密算法
        • 对称加密算法的应用
        • 常见的对称加密算法
        • 在 Java 中使用 AES 加密
        • 使用 CBC 模式
        • 对称加密算法的缺点
        • 参考
      • 口令加密算法
      • 非对称加密算法介绍
      • RSA 算法原理(一):数学知识
      • RSA算法原理(二):概述
      • RSA 算法原理(三):补充知识
      • Java 中的 RSA 算法
      • DH 算法
      • 数字签名
      • SSL 和 TLS 协议介绍
    • Java8 新特性

    • 网络编程

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSE
  • 哈希和加密算法
2023-03-20
目录

对称加密算法

# 对称加密算法

对称加密算法就是传统的用一个密码进行加密和解密。

# 对称加密算法的应用

例如我们用压缩包工具,对文件进行压缩时,可以选择用一个密码进行加密(加密算法选默认的即可):

而解压压缩包的时候,我们需要输入密码,才能解压缩。

从程序的角度来看,可以简单地认为,加密就是通过加密算法和密码(密钥),对文件进行操作,生成加密后的文件(也叫密文)

secret = encrypt(key, message);
1

而解密则相反,它接收密码和密文,然后输出明文:

plain = decrypt(key, secret);
1

由于加密和解密使用同样的规则和"密钥",这被称为"对称加密算法"(Symmetric-key algorithm)。

# 常见的对称加密算法

在软件开发中,常用的对称加密算法有:

算法名称 密钥长度 工作模式 填充模式
DES 56/64 ECB/CBC/PCBC/CTR/... NoPadding/PKCS5Padding/...
AES 128/192/256 ECB/CBC/PCBC/CTR/... NoPadding/PKCS5Padding/PKCS7Padding/...
IDEA 128 ECB PKCS5Padding/PKCS7Padding/...

密钥长度直接决定加密强度,而工作模式和填充模式可以看成是对称加密算法的参数和格式选择。

加密数据的时候,我们通常会对数据进行分组(例如 128bit 一组),然后再进行加密。因为要加密的数据可大可小(例如一个蓝光电影和一个小的 txt 文件),分组后方便处理。而工作模式就是如何处理这些分组,常见的工作模式如下(了解即可):

  • ECB(Electronic CodeBook)模式,即电子密码本模式。该模式是将明文分组,加密后直接成为密文分组,分组之间没有关系。
  • CBC(Cipher Block Chaining)模式,即密码分组链接模式。该模式首先将明文分组与前一个密文分组进行 XOR 运算,然后再进行加密。只有第一个明文分组特殊,需要提前为其生成一个与分组长度相同的比特序列,进行 XOR 运算,这个比特序列称为初始化向量(Initialization Vector),简称 IV。
  • CFB(Cipher FeedBack)模式,即密文反馈模式。该模式首先将前一个密文分组进行加密,再与当前明文分组进行 XOR 运算,来生成密文分组。CFB 模式也需要一个 IV。
  • CTR(CounTeR)模式,即计数器模式。该模式也会产生一个密钥流,它通过递增一个计数器来产生连续的密钥流。对该计数器进行加密,再与明文分组进行 XOR 运算,计算得出密文分组。
  • ...............

注意,ECB 模式是最简单的加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密方式会导致安全性降低,更好的方式是通过 CBC 模式,它需要一个随机数作为 IV 参数,这样对于同一份明文,每次生成的密文都不同。

分组后(例如 128bit 一组),可能会出现最后一组不符合分组长度,此时需要按一定的方式,将尾部明文分组进行填充,这种将尾部分组数据填满的方法称为填充(Padding)。常见的填充模式如下(了解即可):

  • No Padding:即不填充,要求明文的长度,必须是加密算法分组长度的整数倍。
  • ANSI X9.23:在填充字节序列中,最后一个字节填充为需要填充的字节长度,其余字节填充 0。
  • PKCS5 和 PKCS7:在填充字节序列中,每个字节填充为需要填充的字节长度。
  • .....

Java 标准库提供的算法实现并不包括所有的工作模式和所有填充模式,但是通常我们只需要挑选常用的使用就可以了。

注意,DES 算法由于密钥过短,以目前的计算机水平可以在短时间内暴力破解密文,所以现在已经不安全了。

# 在 Java 中使用 AES 加密

Java 标准库提供的对称加密接口非常简单,使用时按以下步骤编写代码:

  1. 根据算法名称/工作模式/填充模式获取 Cipher 实例;
  2. 根据算法名称初始化一个 SecretKey 实例,密钥必须是指定长度;
  3. 使用 SerectKey 初始化 Cipher 实例,并设置加密或解密模式;
  4. 传入明文或密文,获得密文或明文。

示例:

package chapter12Hash;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import java.util.Base64;

public class EncryptDemo1AES {
    public static void main(String[] args) throws Exception {

        // 原文
        String message = "Hello World!";
        System.out.println("message: " + message);

        // 128位密钥 = 16 bytes key
        byte[] key = "1234567890abcdef".getBytes("UTF-8");
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encryptedData = encrypt(key, data);
        System.out.println("Encrypted Data: " + Base64.getEncoder().encodeToString(encryptedData));

        // 解密
        byte[] decryptedData = decrypt(key, encryptedData);
        System.out.println("Decrypted Data: " + new String(decryptedData, "UTF-8"));

    }

    // 加密
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException{
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKey keySpce = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpce);
        return  cipher.doFinal(input);
    }

    //解密
    public static byte[] decrypt(byte[] key, byte[] input) throws  GeneralSecurityException{
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKey keySpce = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpce);
        return  cipher.doFinal(input);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

运行结果:

message: Hello World!
Encrypted Data: N0N4UtmbNnVfSdUE/Nk/rw==
Decrypted Data: Hello World!
1
2
3

# 使用 CBC 模式

由于 ECB 模式没那么安全,我们可以改为使用 CBC 模式,示例如下:

package chapter12Hash;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Base64;

public class EncryptDemo2CBC {
    public static void main(String[] args) throws Exception {

        // 原文
        String message = "Hello World!";
        System.out.println("message: " + message);

        // 256位密钥 = 32 bytes Key:
        byte[] key = "1234567890abcdef1234567890abcdef".getBytes("UTF-8");

        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encryptedData = encrypt(key, data);
        System.out.println("Encrypted Data: " + Base64.getEncoder().encodeToString(encryptedData));

        // 解密
        byte[] decryptedData = decrypt(key, encryptedData);
        System.out.println("Decrypted Data: " + new String(decryptedData, "UTF-8"));

    }

    // 加密
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKey keySpce = new SecretKeySpec(key, "AES");
        // CBC模式需要生成一个16 bytes的initialization vector:
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16);
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpce, ivps);
        byte[] data = cipher.doFinal(input);
        return join(iv, data);
    }

    //解密
    public static byte[] decrypt(byte[] key, byte[] input) throws  GeneralSecurityException{
        // 把input分割成IV和密文:
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        System.arraycopy(input, 0, iv, 0, 16);
        System.arraycopy(input, 16, data, 0, data.length);
        // 解密:
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        return cipher.doFinal(data);
    }

    public static byte[] join(byte[] bs1, byte[] bs2) {
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

在 CBC 模式下,需要一个随机生成的 16 字节 IV 参数,必须使用 SecureRandom 生成。因为多了一个 IvParameterSpec 实例,因此,初始化方法需要调用 Cipher 的一个重载方法并传入 IvParameterSpec。

观察输出,可以发现每次生成的 IV 不同,密文也不同。

# 对称加密算法的缺点

1976 年以前,所有的加密方法都是使用的的对称加密:

  1. 发送方选择某一种加密规则,对信息进行加密;
  2. 接收方使用同一种规则,对信息进行解密。

对称加密算法使用的是一个密钥,在单钥加密的情况下,密钥只有一把,所以密钥的保存变得很重要。一旦密钥泄漏,密码也就被破解。而我们想要接收方能解密的话,又必须给他密钥,那么问题来了,怎么保证密钥在保存和传输过程中不被泄漏呢?很难很难,因为我们要加密才能传送信息,但是在密钥给到对方之前,又不能加密。因此通常都是见面协商密钥。

多个密钥的管理也会带来巨大的成本。每和一个用户通信,就得用一个新的密钥。如果都用一个密钥会有什么后果?举例张三和李四用密钥 A,张三和王五也用密钥 A 的话,那么张三和王五的通信,可以被李四解密的。

现实生活中也有这样的例子:笔者有多个银行卡,每个银行卡的密码都是不同的,以至于笔者经常忘记一些少用的银行卡的密码;

此外,笔者使用过知乎,B 站,CSDN,GitHub,Gitee 等网站,这些网站的密码也是不同的…… 更别说手机上那一大堆 APP 了(当然,现在可以短信登录,方便了一点)。

# 参考

对称加密算法 - 廖雪峰的官方网站 (opens new window)

一文搞懂对称加密:加密算法、工作模式、填充方式、代码实现_教 IT 的无语强的博客-CSDN 博客 (opens new window)

上次更新: 2024/10/1 17:03:07
加密算法介绍
口令加密算法

← 加密算法介绍 口令加密算法→

最近更新
01
语雀文档一键下载至本地教程
07-04
02
要成功,就不要低估环境对你的影响
07-03
03
血泪教训:电子设备要定期开机
07-02
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式