对称加密算法AES实践

对称加密算法

简单的来说,对称加密算法就是加密的密钥与解密的密钥是相同的。
常用对称加密算法

  • DES(Data Encryption Standard)
  • 3DES(DES加强版,使用3次DES计算,Triple DES,DESede)
  • AES(Advanced Encryption Standard,3DES加强版)

AES

AES的具体实现,在下面的参考文章中。
在这里了解到,AES的几个模式

  • ECB模式(电子密码本模式)
  • CBC模式(密码分组链接:Cipher-block chaining)
  • CFB模式(密文反馈:Cipher feedback)

在块加密中,通常要整数长度的数据,但用户输入的数据不一定是整数长度,所以要把数据进行填充,就有几种填充方式。
AES加密模式和填充方式(其实还有还几种填充方式没写上,开始时候也在这里绕了一下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
算法/模式/填充                16字节加密后数据长度        不满16字节加密后长度
AES/CBC/NoPadding 16 不支持
AES/CBC/PKCS5Padding 32 16
AES/CBC/ISO10126Padding 32 16
AES/CFB/NoPadding 16 原始数据长度
AES/CFB/PKCS5Padding 32 16
AES/CFB/ISO10126Padding 32 16
AES/ECB/NoPadding 16 不支持
AES/ECB/PKCS5Padding 32 16
AES/ECB/ISO10126Padding 32 16
AES/OFB/NoPadding 16 原始数据长度
AES/OFB/PKCS5Padding 32 16
AES/OFB/ISO10126Padding 32 16
AES/PCBC/NoPadding 16 不支持
AES/PCBC/PKCS5Padding 32 16
AES/PCBC/ISO10126Padding 32 16

几种AES 常见的加密套件

这是ss中可选的加密套件

  • “aes-128-cfb”
  • “aes-192-cfb”
  • “aes-256-cfb”
  • “aes-128-ofb”
  • “aes-192-ofb”
  • “aes-256-ofb”

中间的就初始化向量的长度,后面就是模式。

java代码的AES实现

测试代码

1
2
3
4
5
6
7
8
public static void main(String[] args) throws Exception {
String passwordkey= "123123";
String content= "The quick brown fox jumps over a lazy dog.";
byte[] encrypted = encrypt(content, passwordkey);
System.out.println("after encrypt: "+new String(encrypted));
String decrypted = decrypt(encrypted, passwordkey);
System.out.println("after decrypt: "+decrypted);
}

加密方法

主要步骤:

  • 生成初始化向量
  • 哈希 key(不是必须的,但是因为AES要一个16字节的密钥,把密码变成16字节)
  • 加密
  • 合并初始化向量IV 和加密部分
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
public static byte[] encrypt(String plainText, String key) throws Exception {
byte[] clean = plainText.getBytes();

// 随机生成从初始化向量 IV.
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

// 哈希 key.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes("UTF-8"));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

// 加密
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(clean);

// 合并初始化向量IV 和加密部分
byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];
System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);

return encryptedIVAndText;
}

解密部分

与加密部分相反

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
 public static String decrypt(byte[] encryptedIvTextBytes, String key) throws Exception {
int ivSize = 16;
int keySize = 16;

// 取出初始化向量 IV.
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

// 取出加密部分
int encryptedSize = encryptedIvTextBytes.length - ivSize;
byte[] encryptedBytes = new byte[encryptedSize];
System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);

// 哈希密码
byte[] keyBytes = new byte[keySize];
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes());
System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

// 解密
Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);

return new String(decrypted);
}

总结

对称加密算法有五个关键因素:算法、工作模式、填充模式、初始化向量、密钥。

  • “算法、工作模式、填充模式”在Cipher获取实例时进行指定,如Cipher.getInstance("AES/CBC/PKCS5Padding");
  • “密钥、初始化向量”在Cipher初始化时,进行指定,如cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
  • doFinal进行具体的处理
  • 密钥由字节变对像要经过SecretKeySpec包装
  • 初始化向量由字节变为对像要经过IvParameterSpec包装,初始化向量长度,AES是16位,DES是8位。

如果做验证,推荐一个在线加解密的站点,用是JSEncrypt。
https://blog.zhengxianjun.com/online-tool/rsa/

参考