本文介绍 Java 语言实现 AES 加密的方法。
目录
- AES 简介
- AES transformation
- 代码实现
- ECB
- NoPadding
- PKCS5Padding
- ISO10126Padding
- CBC
- CFB
- OFB
- PCBC
- ECB
AES 简介
AES,Advanced Encryption Standard,高级加密标准,密码学中又称为 Rijndael 加密法,是一种区块加密标准,用来替代原先的 DES。
AES 是一个迭代的、对称密钥分组的密码,可以使用 128
、192
和 256
位密钥,并且使用 128
位(16 字节)分组加密和解密数据。美国国家标准与技术局和 ANSI X9 已经设定了最小密钥长度的要求,对称密钥加密的密钥长度是至少 128 位,这样在 2030 年以前是安全的。
AES 加密有多轮重复和变幻,大致步骤如下:
- 密钥扩展(Key Expansion)
- 初始轮(Initial Round)
- 重复轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey
- 最终轮(Final Round),最终轮没有 MixColumns
AES transformation
算法/模式/填充 | 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 |
- 在原始数据长度为
16
的整数倍时,假如原始数据长度等于16*n
,则使用 NoPadding 时加密后数据长度等于16*n
,其它情况下加密数据长度等于16*(n+1)
。 - 在不足
16
的整数倍的情况下,假如原始数据长度等于16*n+m
[其中m
小于16
],除了 NoPadding 填充之外的任何方式,加密数据长度都等于16*(n+1)
,NoPadding 填充情况下,CBC、ECB 和 PCBC 三种模式是不支持的,CFB 和 OFB两种模式下则加密数据长度等于原始数据长度。
代码实现
ECB
NoPadding
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* AES 128 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt128(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 128);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.ECB.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
}
}
/**
* AES 128 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt128(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 128);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.ECB.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// NoPadding 填充模式下待加密原文长度必须是 16 的整数倍
String content = "AES Test Content";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt128(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt128(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
PKCS5Padding
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* AES 192 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt192(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 192);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.ECB.value + "/" + Padding.PKCS5_PADDING.value);
// 初始化密码生成器
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
}
}
/**
* AES 192 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt192(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 192);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.ECB.value + "/" + Padding.PKCS5_PADDING.value);
// 初始化密码生成器
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// PKCS5Padding 填充模式下待加密原文长度不要求必须是 16 的整数倍
String content = "AES Test X";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt192(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt192(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
ISO10126Padding
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* AES 256 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.ECB.value + "/" + Padding.ISO10126_PADDING.value);
// 初始化密码生成器
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
}
}
/**
* AES 256 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.ECB.value + "/" + Padding.ISO10126_PADDING.value);
// 初始化密码生成器
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding"),
ISO10126_PADDING("ISO10126Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// ISO10126Padding 填充模式下待加密原文长度不要求必须是 16 的整数倍
String content = "AES Test X";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt256(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt256(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
CBC
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* 偏移量
* 注意:
* 1.除 ECB 模式外,其它模式下加解密 Cipher 初始化必须传入同一个 IvParameterSpec 实例参数
* 2.IvParameterSpec 构造函数中参数字节数组长度必须是 16 位
*/
private static final IvParameterSpec IV_PARAMETER_SPEC =
new IvParameterSpec(new SecureRandom().generateSeed(16));
/**
* AES 256 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.CBC.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.ENCRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* AES 256 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.CBC.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.DECRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB"),
CBC("CBC");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding"),
ISO10126_PADDING("ISO10126Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// NoPadding 填充模式下待加密原文长度必须是 16 的整数倍
String content = "AES Test Content";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt256(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt256(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
CFB
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* 偏移量
* 注意:
* 1.除 ECB 模式外,其它模式下加解密 Cipher 初始化必须传入同一个 IvParameterSpec 实例参数
* 2.IvParameterSpec 构造函数中参数字节数组长度必须是 16 位
*/
private static final IvParameterSpec IV_PARAMETER_SPEC =
new IvParameterSpec(new SecureRandom().generateSeed(16));
/**
* AES 256 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.CFB.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.ENCRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* AES 256 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.CFB.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.DECRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB"),
CBC("CBC"),
CFB("CFB");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding"),
ISO10126_PADDING("ISO10126Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// NoPadding 填充模式下待加密原文长度必须是 16 的整数倍
String content = "AES Test Content";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt256(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt256(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
OFB
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* 偏移量
* 注意:
* 1.除 ECB 模式外,其它模式下加解密 Cipher 初始化必须传入同一个 IvParameterSpec 实例参数
* 2.IvParameterSpec 构造函数中参数字节数组长度必须是 16 位
*/
private static final IvParameterSpec IV_PARAMETER_SPEC =
new IvParameterSpec(new SecureRandom().generateSeed(16));
/**
* AES 256 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.OFB.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.ENCRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* AES 256 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.OFB.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.DECRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB"),
CBC("CBC"),
CFB("CFB"),
OFB("OFB");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding"),
ISO10126_PADDING("ISO10126Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// NoPadding 填充模式下待加密原文长度必须是 16 的整数倍
String content = "AES Test Content";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt256(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt256(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
PCBC
package tutorial.java.util;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
public class AesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_AES = "AES";
/**
* 偏移量
* 注意:
* 1.除 ECB 模式外,其它模式下加解密 Cipher 初始化必须传入同一个 IvParameterSpec 实例参数
* 2.IvParameterSpec 构造函数中参数字节数组长度必须是 16 位
*/
private static final IvParameterSpec IV_PARAMETER_SPEC =
new IvParameterSpec(new SecureRandom().generateSeed(16));
/**
* AES 256 位密钥加密
*
* @param content 待加密内容
* @param password 加密密码
* @return 加密后密文
*/
public static byte[] encrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.PCBC.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.ENCRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* AES 256 位密钥解密
*
* @param content 待解密内容
* @param password 解密密码
* @return 解密后原文
*/
public static byte[] decrypt256(byte[] content, byte[] password) {
try {
Key key = keyGenerator(password, 256);
// 构造密码生成器
Cipher cipher = Cipher.getInstance(ALGORITHM_AES + "/" + Mode.PCBC.value + "/" + Padding.NO_PADDING.value);
// 初始化密码生成器,注意除 ECB 模式外,其它模式初始化时必须指定偏移量
cipher.init(Cipher.DECRYPT_MODE, key, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Invalid Algorithm Parameter");
}
}
/**
* 生成 AES 密钥对象
*
* @param password 加密密码
* @param keyLength 密钥长度
* @return 密钥对象
* @throws NoSuchAlgorithmException 无相关算法
*/
private static Key keyGenerator(byte[] password, int keyLength) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
keyGenerator.init(keyLength, new SecureRandom(password));
SecretKey secretKey = keyGenerator.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
}
private enum Mode {
ECB("ECB"),
CBC("CBC"),
CFB("CFB"),
OFB("OFB"),
PCBC("PCBC");
private String value;
Mode(String value) {
this.value = value;
}
}
private enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding"),
ISO10126_PADDING("ISO10126Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
单元测试:
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class AesUtilsTest {
@Test
public void test() {
// NoPadding 填充模式下待加密原文长度必须是 16 的整数倍
String content = "AES Test Content";
String password = "AES Password";
byte[] encryptResult = AesUtils.encrypt256(content.getBytes(StandardCharsets.UTF_8),
password.getBytes(StandardCharsets.UTF_8));
byte[] decryptResult = AesUtils.decrypt256(encryptResult,
password.getBytes(StandardCharsets.UTF_8));
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
}
网友评论