package club.codeapes.common.utils;

import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger; /**
* @version V1.0
* @desc AES 加密工具类
*/
public class AESUtil { private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法
//自定义密码
private static final String ASSETS_DEV_PWD_FIELD = "xxxx"; public static String getAssetsDevPwdField() {
return ASSETS_DEV_PWD_FIELD;
} /**
* AES 加密操作
*
* @param content 待加密内容
* @param password 加密密码
* @return 返回Base64转码后的加密数据
*/
public static String encrypt(String content, String password) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器 byte[] byteContent = content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器 byte[] result = cipher.doFinal(byteContent);// 加密 return Base64Utils.encodeToString(result);//通过Base64转码返回
} catch (Exception ex) {
Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
} return null;
} /**
* AES 解密操作
*
* @param content
* @param password
* @return
*/
public static String decrypt(String content, String password) { try {
//实例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); //使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password)); //执行操作
byte[] result = cipher.doFinal(Base64Utils.decodeFromString(content));
String s = new String(result, "utf-8");
return s;
} catch (Exception ex) {
ex.printStackTrace();
Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
} return null;
} /**
* 生成加密秘钥
*
* @return
*/
private static SecretKeySpec getSecretKey(String password) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(password.getBytes());
//AES 要求密钥长度为 128
kg.init(128, random);
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
} public static void main(String[] args) {
String origin = "my test string";
String encrypt = AESUtil.encrypt(origin, AESUtil.ASSETS_DEV_PWD_FIELD);
String decrypt = AESUtil.decrypt(encrypt, AESUtil.ASSETS_DEV_PWD_FIELD);
System.out.println(origin);
System.out.println(encrypt);
System.out.println(decrypt);
} }
 

关于过程中,为什么可以用base64对产生的数组进行编码,以及解码。使用的时候可能产生异常:解密的字节数组必须是16的倍数

发现当把字节数组转为字符串后,在把字符串.getBytes()获得数组,发现两个字节数组前后不一样了

强调一下:new String(byte[]),和"str".getBytes(),两个方法使用的编码一样,然后换成其他编码也出现这样情况

原因:

1. 为什么数组转字符串,字符串然后转数组会出现,前后两个字节数组的值会不同,因为并不是每个字节数和编码集上的字符都有对应关系,如果一个字节数在编码集上没有对应,编码new String(byte[]) 后,往往解出来的会是一些乱码无意义的符号:例如:��,

但是解码的时候,�这个字符也是一个字符在编码表中也有固定的字节数用来表示,所有解码出来的值必定是编码表中对应的值,除非你的字节数组中的字节数正好在编码表中有对应的值,否则编码,解码后的字节数组会不一样

误区: 误以为所有的字节数组都可以new String(),然后在通过String.getBytes()还原

2.再说这个异常报:解密的字节数组必须是16的倍数,这得从AES的原理说起,AES是把数据按16字节分组加密的,所有如果数组长度不是16的倍数会报错

AES原理:AES是对数据按128位,也就是16个字节进行分组进行加密的,每次对一组数据加密需要运行多轮。而输入密钥的长度可以为128、192和256位,也就是16个字节、24个字节和32个字节,如果用户输入的密钥长度不是这几种长度,也会补成这几种长度。无论输入密钥是多少字节,加密还是以16字节的数据一组来进行的,密钥长度的不同仅仅影响加密运行的轮数。

可以用base64对参生的数组进行编码,然后在解码,这样不会像new String(byte[]),getBytes()那样造成数组前后不一致,一开始,我看到大部分人都是用base64,我也只是以为多一层编码看起来安全一些而已,没想到base64对数组的处理是不会造成误差的

 
 

AES加密解密工具类封装(AESUtil)的更多相关文章

  1. 自写AES加密解密工具类

    此类主要用于加密与解密,采用128位ECB模式,PKCS5Padding填充补位. 可使用方法为加密返回二进制encryptBin(content, key).加密返回十六进制encryptHex(c ...

  2. Java中的AES加解密工具类:AESUtils

    本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...

  3. AES加密解密 助手类 CBC加密模式

    "; string result1 = AESHelper.AesEncrypt(str); string result2 = AESHelper.AesDecrypt(result1); ...

  4. Base64加密解密工具类

    使用Apache commons codec类Base64进行加密解密 maven依赖 <dependency> <groupId>commons-codec</grou ...

  5. Java AES加密解密工具 -- GUI 、在线传输文件

    原理 对于任意长度的明文,AES首先对其进行分组,每组的长度为128位.分组之后将分别对每个128位的明文分组进行加密. 对于每个128位长度的明文分组的加密过程如下:     (1)将128位AES ...

  6. .Net(c#)加密解密工具类:

    /// <summary> /// .Net加密解密帮助类 /// </summary> public class NetCryptoHelper { #region des实 ...

  7. java加密解密工具类

    package com.founder.mrp.util; import java.nio.charset.StandardCharsets; import java.security.Key; im ...

  8. 加密解密工具类(Java,DES)

    一个Java版的DES加密工具类,能够用来进行网络传输数据加密,保存password的时候进行加密. import java.security.Key; import java.security.sp ...

  9. java 加密解密工具类(实用!!!)

    最近发现了一个加密解密的好例子,很方便使用,可以作为平时开发的工具集,记录一下. package com.sh.springboottdemo2.util; import com.sun.org.ap ...

随机推荐

  1. 洛谷 P1816 忠诚 题解

    P1816 忠诚 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意.但是由于一些人的挑拨,财 ...

  2. .NET三层架构开发初步

    转自:https://www.cnblogs.com/weilengdeyu/archive/2013/01/04/2844847.html 今天咱们来谈下三层架构.说到三层架构,搞过点程序的可能都知 ...

  3. Jmeter实现压力测试(多并发测试)

    一.http://jmeter.apache.org/ 二.点击Download Releases选择版本下载 三.下载解压: 将解压后的文档存盘-下载logkit-2.0.jar(汉化包)放到jme ...

  4. redis哨兵模式实现主从故障切换

    环境设定base2 172.25.78.12 masterbase3 172.25.78.13 slavebase4 172.25.78.14 slave1.配置一主二从环境在base2上[root@ ...

  5. vue package-lock.json

    npm5之后安装文件之后会多出一个package-lock.json的文件,它的作用是: 1. 安装之后锁定包的版本,手动更改package.json文件安装将不会更新包,想要更新只能使用 npm i ...

  6. 【技术博客】nginx服务器的https协议实现

    在本学期软件工程的Alpha和Beta阶段,我们的服务器部署都是使用基础的http协议,http在网络路由间的信息转发都为明文,这对我们网站的账户密码登录来说很不安全,因此在Gamma阶段我们实现了h ...

  7. Nginx 整合 Lua 实现动态生成缩略图

    原文地址:Nginx 整合 Lua 实现动态生成缩略图 博客地址:http://www.extlight.com 一.前提 最近在开发一个项目,涉及到缩略图的功能,常见的生成缩略图的方案有以下几个: ...

  8. Ladon内网渗透扫描器PowerShell版

    程序简介 Ladon一款用于大型网络渗透的多线程插件化综合扫描神器,含端口扫描.服务识别.网络资产.密码爆破.高危漏洞检测以及一键GetShell,支持批量A段/B段/C段以及跨网段扫描,支持URL. ...

  9. Lab_1:练习4——分析bootloader加载ELF格式的OS的过程

    一.实验内容 通过阅读bootmain.c,了解bootloader如何加载ELF文件.通过分析源代码和通过qemu来运行并调试bootloader&OS, bootloader如何读取硬盘扇 ...

  10. ES6中的关键字 - let

    let关键字 1.let关键字声明的变量仅仅在自己的块级作用域内起作用,出了块级作用域就不起作用了: var arr2 = []; for (let index = 0; index < 10; ...