AES代码演示
2022-12-18 本文已影响0人
滨岩
AES 分组核心原理参考:
https://www.jianshu.com/p/0c603e1c2fa7
package com.deepway.cryptology;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.SecureRandom;
import java.util.Arrays;
/**
* AES 工作模式 演示
* <p>
* AES默认加密模式 就是ECB
* 参考:https://blog.csdn.net/qq_41035588/article/details/121666788
*
* @author huyanbing
* @create 2022/12/17 4:01 下午
*/
public class AESModeTest extends BaseCipher {
private static final String ALGO = "AES";
private static final int IV_SIZE = 16;
//持有iv 不共享不更新
private byte[] iv;
//前一次计算状态的保持
private byte[] prevState;
private Cipher aes;
public AESModeTest(int keyLen, byte[] plainKey) {
super(keyLen, plainKey);
}
private void initialize() throws GeneralSecurityException {
//生成 iv
iv = generateIV();
//iv as prevState
//拷贝一份 prevState 这个 prevState 是要读写改变的
prevState = Arrays.copyOf(iv, iv.length);
//拿密码器
aes = Cipher.getInstance(ALGO);
aes.init(Cipher.ENCRYPT_MODE, key);
}
private byte[] generateIV() {
//填充
byte[] iv = new byte[IV_SIZE];
//随机生成 这里必须使用安全的随机数生成器 SecureRandom 不能使用其他的随机数生成器
new SecureRandom().nextBytes(iv);
return iv;
}
private void resetDecryptPrevState() {
try {
aes.init(Cipher.DECRYPT_MODE, key);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
//拷贝一份 prevState 这个 prevState 是要读写改变的
prevState = Arrays.copyOf(iv, iv.length);
}
/**
* ECB 模式加密
*
* @param plainText
* @return
*/
public byte[] encrypt_ECB(byte[] plainText) throws IllegalBlockSizeException, BadPaddingException {
// aes.update(plainText);
return aes.doFinal(plainText);
}
/**
* ECB 模式解密
*
* @param cipherText
* @return
*/
public byte[] decrypt_ECB(byte[] cipherText) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
aes.init(Cipher.DECRYPT_MODE, key);
//aes.update(cipherText);
return aes.doFinal(cipherText);
}
/***
* CBC 模式的逻辑演示
* prevCipherText=iv<==At first
* @param plainText
* @return
*/
public byte[] encrypt_CBC(byte[] plainText) throws IllegalBlockSizeException, BadPaddingException {
assert plainText.length == 128 >> 3;
byte[] x = new byte[16];
for (int i = 0; i < x.length; i++) {
//CBC模式 需要明文与上一轮结果做异或,然后再输入到加密算法中
//x 为异或结果 prevState 初始值是 IV
x[i] = (byte) (plainText[i] ^ prevState[i]);
}
//返回加密结果
// prevState = aes.update(x);
return prevState = aes.doFinal(x);
}
/**
* CBC 解密方法 解密方法 相当于加密方法的反向
*
* @param cipherText
* @return
*/
public byte[] decrypt_CBC(byte[] cipherText) throws IllegalBlockSizeException, BadPaddingException {
resetDecryptPrevState();
assert cipherText.length == 128 >> 3;
//加密 aes.update 是最后一步,解密 aes.update是第一步
// byte[] x = aes.update(cipherText);
byte[] x = aes.doFinal(cipherText);
for (int i = 0; i < x.length; i++) {
//x[] 刚开始并不是明文 还是密文,经过和prevState[i] 异或之后 写回 x[]
x[i] ^= prevState[i];
}
//同时要把当前密文数据 更新给 prevState
prevState = cipherText;
return x;
}
/**
* CFB 模式的逻辑演示
* prevCipherText=iv<==At first
*
* @param plainText
* @return
*/
private byte[] encrypt_CFB(byte[] plainText) throws IllegalBlockSizeException, BadPaddingException {
assert plainText.length == 128 >> 3;
byte[] y = aes.update(prevState);
//byte[] y = aes.doFinal(prevState);
for (int i = 0; i < y.length; i++) {
//CFB模式是用加密完的结果去异或明文
y[i] ^= plainText[i];
}
//并且它加密的不是明文数据,而是 IV
//然后加密之后 生成 y ,y 与明文异或 写回y[i]
//让后将prevState=y
return prevState = y;
}
/**
* CFB 解密
*
* @param cipherText
* @return
*/
public byte[] decrypt_CFB(byte[] cipherText) throws IllegalBlockSizeException, BadPaddingException {
resetDecryptPrevState();
assert cipherText.length == 128 >> 3;
//解密也是调用的加密方法
byte[] x = aes.update(prevState);
//byte[] x = aes.doFinal(prevState);
for (int i = 0; i < x.length; i++) {
//密文异或 并写回原文消息
x[i] ^= cipherText[i];
}
//并用当前密文消息 更新 prevState 当前状态
prevState = cipherText;
return x;
}
/**
* OFB 模式的逻辑演示
* prevCipherText=iv<==At frist
*
* @param plainText
* @return
*/
public byte[] encrypt_OFB(byte[] plainText) {
assert plainText.length == 128 >> 3;
byte[] y = aes.update(prevState);
// 和 CFB 区别 重点 块加密的的运算结果,需要保留下来到prevState
prevState = Arrays.copyOf(y, y.length);
for (int i = 0; i < y.length; i++) {
//和CFB比较类似
y[i] ^= plainText[i];
}
//CFB 是 在这
return y;
}
/**
* OFB 解密 与加密模式是一样的
*
* @param cipherText
* @return
*/
public byte[] decrypt_OFB(byte[] cipherText) {
return encrypt_OFB(cipherText);
}
/**
* CTR模式 加密
* prevCipherText =iv <==At frist
*
* @param plainText
* @return
*/
public byte[] encrypt_CTR(byte[] plainText) {
assert plainText.length == 128 >> 3;
byte[] x = aes.update(prevState);
for (int i = 0; i < x.length; i++) {
//异或明文 就可以得到加密x了
x[i] ^= plainText[i];
}
// increment :counter++
for (int i = 15; i >= 0; --i) {
//因为prevState是一个很大的数字,所以从地位到高位不断自增的一个小小的算法过程
//如果自增不为零 ++prevState[i]!=0 那么 i-- 向前一位
if (++prevState[i] != 0) {
break;
}
}
return x;
}
/**
* CTR模式 解密
* prevCipherText =iv <==At frist
* 解密操作和加密操作一样
*
* @param cipherText
* @return
*/
public byte[] decrypt_CTR(byte[] cipherText) {
return encrypt_CTR(cipherText);
}
public static void main(String[] args) throws GeneralSecurityException {
AESModeTest test = new AESModeTest(128, "0123456789012345".getBytes());
//打印当前的 key
String hex = HexCustomUtil.bytes2hex(test.key.getEncoded());
System.out.println("---------key----------------");
System.out.println(hex);
//明文 PlainText
byte[] plainText = "8888888888888888".getBytes();
//打印明文
System.out.println("---------明文----------------");
System.out.println(HexCustomUtil.bytes2hex(plainText));
System.out.println(new String(plainText));
//加密
test.initialize();
byte[] cipherText = test.encrypt_CBC(plainText);
//打印密文
System.out.println("---------密文----------------");
System.out.println(HexCustomUtil.bytes2hex(cipherText));
// System.out.println(new String(cipherText));
//解密
byte[] decryptArr = test.decrypt_CBC(cipherText);
System.out.println("---------解密后明文----------------");
System.out.println(HexCustomUtil.bytes2hex(decryptArr));
System.out.println(new String(decryptArr));
}
}