Aes加解密

加解密概念

加密

通过一系列计算将明文转换成一个密文。

加密和解密的对象通常是字节数组(有的语言动态数组类比切片

加密后的数据,可能有很多是不可读字符。通常会将其转换为可见的字符串。

  • 直接将字节数组转为16进制的字符串(一个字节8位,4位表示一个16进制数据,因此转换后的数据是转换前字节数组的2倍长度,之所以采用16进制是因为其看起来更加紧凑)
  • 将字节数组进行Base64编码

AES加密

算法相关常量在类 Cipher的注释中有说明。

AES是一种对称加密算法。具体加密方式是以16字节一块 进行分块加密。

如果明文 长度不是16的倍数,那么则需要进行填充,这就引申出了填充模式。
其密钥长度要求为 128 位(16字节)、192(24字节) 位和 256(32字节) 位,三种,越长越安全,速度越慢

填充模式

常用填充模式:PKCS#5、PKCS#7 。在Java中已经将其行为统一了。

在模式的定义上:

  • PKCS#5用于8字节块为单位的加密场景
  • PKCS#7用于非8字节块 为单位的加密场景,在现代应用中更通用
    但是它们的实现方式都是类似的,剩余的字节数组长度距离加密块差几个字节,就填充几个字节,而且每一位值也是这个长度

比如剩下5字节,在AES中,是以16字节为单位 ,差11个字节。那么就会在这5个字节后面加11个项,而且每一项的值都是11

加密模式

AES中现在用得最多的就是CBC 模式.

这种方式在加密一个块时,需要使用上一个块加密后的数据与当前明文块 进行异或运算。也就是说每一个块的加密都不一样。
这就有一个点,第一个加密块前面没有数据块,所以我们需要指定一个初始向量(有的也称之为偏移量)(其长度就是一个数据块的长度)

示例

  • 加密(如果使用的是CBC模式,则需要指定初始向量(说白了就是手动创建加密块,因此也是长度为16的字节数组),
  1. 生成iv(如果是CBC模式,则需要。长度与加密块一致(16字节))
java 复制代码
// 如果是CBC模式 首先生成iv向量(本质就是一个长度为16的字节数组,随便怎么构建)
// 可以自行创建16字节的数组,但推荐生成随机iv
// 自行构建
String ivStr = "1111111111111111"
byte[] iv = ivStr.getBytes(StandardCharsets.UTF_8);

// 生成随机iv
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[16];
secureRandom.nextBytes(iv);

IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
  1. 生成密钥
    AES密钥支持16字节、24字节、32字节(越长越安全,运算速度越慢)
    与iv类似,可以自定义密钥串,然后构建密钥对象,也可以直接生成指定长度的随机密钥
java 复制代码
// 指定密钥串,构建密钥对象
String key = "0111111111111111";
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");

// 生成指定长度的密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
  1. 创建加密器,在java中通过聚合名称指定多项配置(AES/CBC/PKCS7Padding )它制定了加密算法、加密模式、填充模式
java 复制代码
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
  1. 初始化加密器。指定加密还是解密,密钥,初始向量
java 复制代码
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
  1. 执行加解密。参数和返回都是字节数组
java 复制代码
byte[] resByte = cipher.doFinal(s.getBytes(StandardCharsets.UTF_8));
  1. 以上加密结果可能会有一些不可读的字符,因此为了方便查看,存储,传输等,我们常常将字节数组转为16进制字符串 或者Base64 进行存储,传输。
    不仅是加密结果。随的的生成iv字节数组,随机生成密钥字节数组 等包含不可读字符的字节数组都可以采用这种方式进行分发,存储
  • Base64编解码
java 复制代码
// 字节数组编码为Base64字符串
String encodedKey = Base64.getEncoder().encodeToString(encoded);

// Base64字符串解码为字节数组
byte[] keyBytes = Base64.getDecoder().decode(encodedKey);
  • 16进制编解码
java 复制代码
// 字节数组编码为16进制字符串
public String byte2Hex(byte[] bytes) {
    int len = bytes.length;
    StringBuilder builder = new StringBuilder();
    for (int i = 0, j = 0; i < len; i++) {
        builder.append(Integer.toHexString((0xF0 & bytes[i]) >>> 4));
        builder.append(Integer.toHexString(0x0F & bytes[i]));
    }
    return builder.toString();
}

// 16进制字符串转字节数组
public byte[] hexToBytes(String s) {
    byte[] bytes = new byte[(s.length() + 1) >> 1];
    for (int i = 0, j = 0; i < bytes.length; i++) {
        int left = Character.digit(s.charAt(j++), 16) << 4;
        left = left | Character.digit(s.charAt(j++), 16);
        bytes[i] = (byte) (left & 0xff);
    }
    return bytes;
}
相关推荐
Gao_xu_sheng1 分钟前
Java程序打包成exe,无Java环境也能运行
java·开发语言
大卫小东(Sheldon)8 分钟前
Java的HTTP接口测试框架Gatling
java
谢家小布柔9 分钟前
java中的继承
java·开发语言
l1384942745115 分钟前
Java每日一题(2)
java·开发语言·游戏
苹果醋318 分钟前
SpringBoot快速入门
java·运维·spring boot·mysql·nginx
WANGWUSAN6629 分钟前
Python高频写法总结!
java·linux·开发语言·数据库·经验分享·python·编程
Yvemil729 分钟前
《开启微服务之旅:Spring Boot 从入门到实践》(一)
java
forNoWhat38 分钟前
java小知识点:比较器
java·开发语言
西洼工作室44 分钟前
【java 正则表达式 笔记】
java·笔记·正则表达式
40岁的系统架构师1 小时前
1 JVM JDK JRE之间的区别以及使用字节码的好处
java·jvm·python