From ea13dea70de8fb64da1655f5944a6a1e50d3c16c Mon Sep 17 00:00:00 2001 From: its Date: Fri, 26 Apr 2024 11:39:00 +0800 Subject: [PATCH] =?UTF-8?q?[feat]=20=E5=A2=9E=E5=8A=A0AES=E5=8A=A0?= =?UTF-8?q?=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UPDATE.md | 2 +- .../java/com/yexuejc/base/encrypt/AES.java | 179 ++++++++++++++++++ .../com/yexuejc/base/encrypt/AESTest.java | 55 ++++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/yexuejc/base/encrypt/AES.java create mode 100644 src/test/java/com/yexuejc/base/encrypt/AESTest.java diff --git a/UPDATE.md b/UPDATE.md index 2190d61..f07c629 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -5,7 +5,7 @@ yexuejc-base 更新记录 **branch:** jre8
**update:**
1. [FileUtil.java](src/main/java/com/yexuejc/base/util/FileUtil.java)增加读取大文件自定义方法和单纯读取方法 -2. +2. 增加AES加解密: [com.yexuejc.base.encrypt.AES](src/main/java/com/yexuejc/base/encrypt/AES.java) --- #### version :1.5.2-jre8 diff --git a/src/main/java/com/yexuejc/base/encrypt/AES.java b/src/main/java/com/yexuejc/base/encrypt/AES.java new file mode 100644 index 0000000..3e7781c --- /dev/null +++ b/src/main/java/com/yexuejc/base/encrypt/AES.java @@ -0,0 +1,179 @@ +package com.yexuejc.base.encrypt; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * AES加解密 + * + * @author maxf + * @class-name AES + * @description + * @date 2022/11/11 15:36 + */ +public class AES { + public static AES builder() { + return Instace.aes; + } + + private static class Instace { + private static AES aes = new AES(); + } + + public static final String AES_ALGORITHM = "AES"; + + /** + * 加密模式 + */ + public static enum ALGORITHM { + //算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度 + //AES/CBC/NoPadding 16 不支持 + AES_CBC_NoPadding("AES/CBC/NoPadding"), + //AES/CBC/PKCS5Padding 32 16 + AES_CBC_PKCS5Padding("AES/CBC/PKCS5Padding"), + //AES/CBC/ISO10126Padding 32 16 + AES_CBC_ISO10126Padding("AES/CBC/ISO10126Padding"), + //AES/CFB/NoPadding 16 原始数据长度 + AES_CFB_NoPadding("AES/CFB/NoPadding"), + //AES/CFB/PKCS5Padding 32 16 + AES_CFB_PKCS5Padding("AES/CFB/PKCS5Padding"), + //AES/CFB/ISO10126Padding 32 16 + AES_CFB_ISO10126Padding("AES/CFB/ISO10126Padding"), + //AES/ECB/NoPadding 16 不支持 + AES_ECB_NoPadding("AES/ECB/NoPadding"), + //AES/ECB/PKCS5Padding 32 16 + AES_ECB_PKCS5Padding("AES/ECB/PKCS5Padding"), + //AES/ECB/ISO10126Padding 32 16 + AES_ECB_ISO10126Padding("AES/ECB/ISO10126Padding"), + //AES/OFB/NoPadding 16 原始数据长度 + AES_OFB_NoPadding("AES/OFB/NoPadding"), + //AES/OFB/PKCS5Padding 32 16 + AES_OFB_PKCS5Padding("AES/OFB/PKCS5Padding"), + //AES/OFB/ISO10126Padding 32 16 + AES_OFB_ISO10126Padding("AES/OFB/ISO10126Padding"), + //AES/PCBC/NoPadding 16 不支持 + AES_PCBC_NoPadding("AES/PCBC/NoPadding"), + //AES/PCBC/PKCS5Padding 32 16 + AES_PCBC_PKCS5Padding("AES/PCBC/PKCS5Padding"), + //AES/PCBC/ISO10126Padding 32 16 + AES_PCBC_ISO10126Padding("AES/PCBC/ISO10126Padding"); + public String name; + + ALGORITHM(String name) { + this.name = name; + } + } + + private ALGORITHM algorithm = ALGORITHM.AES_CBC_NoPadding; + private String key = "hj7x89H$yuBI0456"; + private String iv = "NIfb&95GUY86Gfgh"; + private Charset charset = StandardCharsets.UTF_8; + + /** + * 加密 + * + * @param data 明文 + * @return 密文 + * @Description AES算法加密明文 + */ + public String encrypt(String data) throws Exception { + try { + + Cipher cipher = Cipher.getInstance(algorithm.name); + int blockSize = cipher.getBlockSize(); + byte[] dataBytes = data.getBytes(charset); + int plaintextLength = dataBytes.length; + if (plaintextLength % blockSize != 0) { + plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); + } + byte[] plaintext = new byte[plaintextLength]; + System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); + SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(charset), AES_ALGORITHM); + IvParameterSpec ivspec = null; + if (!algorithm.name.contains("ECB")) { + ivspec = new IvParameterSpec(iv.getBytes(charset)); + } + cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); + byte[] encrypted = cipher.doFinal(plaintext); + return Base64.getEncoder().encodeToString(encrypted); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 解密 + * + * @param data 密文 + * @return 明文 + * @Description AES算法解密密文 + */ + public String decrypt(String data) throws Exception { + try { + byte[] encrypted = Base64.getDecoder().decode(data); + Cipher cipher = Cipher.getInstance(algorithm.name); + SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(charset), AES_ALGORITHM); + IvParameterSpec ivspec = null; + if (!algorithm.name.contains("ECB")) { + ivspec = new IvParameterSpec(iv.getBytes(charset)); + } + cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); + byte[] original = cipher.doFinal(encrypted); + return new String(original, charset).trim(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +// +// public static void main(String[] args) throws Exception { +// String str = " 奥萨蒂 asd8阿斯顿8asd "; +// AES.builder().setAlgorithm(ALGORITHM.AES_CBC_ISO10126Padding); +// AES.builder().setKey("DEsx89H$yuBI0456"); +// String encrypt = AES.builder().encrypt(str); +// System.out.println(encrypt); +// String decrypt = AES.builder().decrypt(encrypt); +// System.out.println(">>>" + decrypt + "<<<"); +// } + + public ALGORITHM getAlgorithm() { + return algorithm; + } + + public AES setAlgorithm(ALGORITHM algorithm) { + this.algorithm = algorithm; + return this; + } + + public String getKey() { + return key; + } + + public AES setKey(String key) { + this.key = key; + return this; + } + + public String getIv() { + return iv; + } + + public AES setIv(String iv) { + this.iv = iv; + return this; + } + + public Charset getCharset() { + return charset; + } + + public AES setCharset(Charset charset) { + this.charset = charset; + return this; + } +} diff --git a/src/test/java/com/yexuejc/base/encrypt/AESTest.java b/src/test/java/com/yexuejc/base/encrypt/AESTest.java new file mode 100644 index 0000000..63cbf60 --- /dev/null +++ b/src/test/java/com/yexuejc/base/encrypt/AESTest.java @@ -0,0 +1,55 @@ +package com.yexuejc.base.encrypt; + +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +public class AESTest { + + @Test + public void testEncrypt() throws Exception { + String data = "Hello World!"; + AES aes = AES.builder() + .setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding) + .setKey("hj7x89H$yuBI0456") + .setIv("NIfb&95GUY86Gfgh") + .setCharset(StandardCharsets.UTF_8); + String encrypted = aes.encrypt(data); + assertNotNull(encrypted); + assertFalse(encrypted.isEmpty()); + } + + @Test + public void testDecrypt() throws Exception { + String data = "SGVsbG8gV29ybGQh"; + AES aes = AES.builder() + .setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding) + .setKey("hj7x89H$yuBI0456") + .setIv("NIfb&95GUY86Gfgh") + .setCharset(StandardCharsets.UTF_8); + String decrypted = aes.decrypt(data); + assertNotNull(decrypted); + assertFalse(decrypted.isEmpty()); + assertEquals("Hello World!", decrypted); + } + + @Test + public void testEncryptAndDecrypt() throws Exception { + String data = "张三"; + AES aes = AES.builder() + .setAlgorithm(AES.ALGORITHM.AES_OFB_ISO10126Padding) + .setKey("hj7x89H$yuBI0456") + .setIv("NIfb&95GUY86Gfgh") + .setCharset(StandardCharsets.UTF_8); + String encrypt = aes.encrypt(data); + System.out.println("加密:" + encrypt); + String decrypt = aes.decrypt(encrypt); + System.out.println("解密:" + decrypt); + } + +}