全文目录,一步到位
1.加密/解密方式一:
AES
本篇文章介绍的是 对称加密 AES
插一句
:
非对称加密比对称加密更安全。
- 对称加密: 安全性要求一般、且数据量较大的场景 对称加密那样在通信之前要先同步秘钥
- 非对称性加密: 对于安全性要求高、且数据量不大的场景 非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存
1.1 AES
加密
简介
AES(Advanced Encryption Standard)是一种对称加密算法,也是目前最常用的加密方式之一。它在国际上被广泛使用,并且被应用于保护各种机密信息,如密码、信用卡信息、银行账户信息、电子邮件等。
AES加密算法使用的加密密钥和解密密钥都是相同的,并且加密和解密使用的算法方法也是相同的,因此称为对称加密算法。AES算法的密钥长度可以是
128位、192位或256位
,其中256位的密钥长度提供了最高的安全性,但同时也需要更高的计算能力。
一般128位(bit) 即可 16字节
AES算法在加密时主要是通过替换、置换和异或等方式进行操作,具体过程包括四个步骤:密钥扩展、初始轮、重复轮和最后的输出。密钥扩展是根据输入的密钥生成相关的轮密钥,用于后续的加密过程中。初始轮是将输入数据进行基本的置换和异或操作。重复轮是将初始轮的结果进行多轮替换、置换和异或操作。最后的输出是将最后的结果输出为密文。
总体来说,AES加密算法具有可靠性高、安全性强的特点,被广泛使用于各种安全系统中。
1.2 AES
解密
简介
AES(Advanced Encryption Standard)解密操作是将加密过的数据使用相同的加密密钥进行解密操作,还原成原始数据的过程。AES解密算法使用的过程和加密算法相同,只是操作的顺序和方法稍有不同。
在AES解密过程中,需要使用相同的密钥才能成功解密数据。因此,需要确保密钥的安全性,防止被泄露。解密过程和加密过程是相反的,首先需要对密文进行逆向操作,还原经过置换和代换操作后的数据,然后进行逆向的轮操作,得到最终的明文。
具体的AES解密步骤如下:
密钥扩展
:使用相同的加密密钥生成相应的轮密钥,用于后续的解密过程中。逆向的输出
:首先对密文进行逆向的输出,还原经过置换和代换操作后的数据。逆向的重复轮
:对还原的数据进行逆向的重复轮操作,还原初始轮和重复轮操作中的所有代换和置换操作。最终输出
:得到最终的明文,即加密前的数据。
需要注意的是,解密过程需要使用相同的密钥和相同的加密算法,否则将无法还原原始数据。同时,AES解密算法仅对数据进行加密和解密操作,不包括数据传输和存储的安全性问题。因此,在实际的应用中,还需要其他的安全机制来保障数据的安全。
1.3 AES细致介绍(
外链
)
介绍的相当全面(
外链
)
===> 传送门: aes加密原理及优势与劣势
2. AES加密解密使用
2.1 应用场景
应用于保护各种机密信息,如密码、信用卡信息、银行账户信息、电子邮件等
2.2 工具包使用方式
javax包下的javax.crypto.Cipher;
2.2.0 (关键)生成一个
秘钥
(16位)
这个密钥需要是
16位
- 对应128bit
原因
: 128的密钥长度是目前能对
安全性和性能
的一种比较理想的
折中
选择
可以放到nacos等配置中心中
也可以随机生成(很关键)
//示例: publicstaticfinalStringKEY_DES="pzy0123456789pzy";
2.2.1 AES加密文本
/**
* AES加密文本
*
* @param content 明文
* @param encryptKey 秘钥,必须为16个字符组成
* @return 密文
*/publicstaticStringaesEncryptForFront(String content,String encryptKey){if(StringUtils.isEmpty(content)||StringUtils.isEmpty(encryptKey)){returnnull;}try{Cipher cipher =Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(encryptKey.getBytes(),"AES"));byte[] encryptStr = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));returnBase64.getEncoder().encodeToString(encryptStr);}catch(Exception e){
e.printStackTrace();returnnull;}}
2.2.2 AES解密文本
/**
* AES解密文本
*
* @param encryptStr 密文
* @param decryptKey 秘钥,必须为16个字符组成
* @return 明文
*/publicstaticStringaesDecryptForFront(String encryptStr,String decryptKey){if(StringUtils.isEmpty(encryptStr)||StringUtils.isEmpty(decryptKey)){returnnull;}try{byte[] encryptByte =Base64.getDecoder().decode(encryptStr);Cipher cipher =Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,newSecretKeySpec(decryptKey.getBytes(),"AES"));byte[] decryptBytes = cipher.doFinal(encryptByte);returnnewString(decryptBytes);}catch(Exception e){
e.printStackTrace();returnnull;}}
2.2.3 AES加密文件(源)
/**
* AES加密文件
*
* @param bytes 字节
* @param encryptKey 秘钥key
* @return 字节byte
*/publicstaticbyte[]aesEncryptForFront(byte[] bytes,String encryptKey){if(StringUtils.isEmpty(bytes)||StringUtils.isEmpty(encryptKey)){returnnull;}try{Cipher cipher =Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(encryptKey.getBytes(),"AES"));return cipher.doFinal(bytes);}catch(Exception e){
e.printStackTrace();returnnull;}}
2.2.4 AES解密文件(源)
/**
* AES解密文件
*
* @param bytes 字节
* @param decryptKey 解密key
* @return 解密字节
*/publicstaticbyte[]aesDecryptForFront(byte[] bytes,String decryptKey){if(StringUtils.isEmpty(bytes)||StringUtils.isEmpty(decryptKey)){returnnull;}try{Cipher cipher =Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,newSecretKeySpec(decryptKey.getBytes(),"AES"));return cipher.doFinal(bytes);}catch(Exception e){
e.printStackTrace();returnnull;}}
2.2.5 文件AES加密并输出(终)
/**
* 文件AES加密并输出
*
* @param fileSourcePath 文件原始路径
* @param outEncryptPath 加密数据文件路径
* @throws IOException io异常
*/publicstaticvoidfileAcsEncrypt(String fileSourcePath,String outEncryptPath)throwsIOException{System.out.println("加密开始!");File file =newFile(fileSourcePath);// 以 byte 的形式读取,不改变文件数据的编码格式byte[] bytes =Files.readAllBytes(file.toPath());byte[] outFile =CryptoUtils.aesEncryptForFront(bytes,CryptoUtils.KEY_DES);OutputStream out =newBufferedOutputStream(newFileOutputStream(outEncryptPath));assert outFile !=null;
out.write(outFile);
out.flush();}
2.2.6 文件AES解密并输出(终)
/**
* 文件AES解密并输出
*
* @param fileEncryptPath 加密后文件路径
* @param outDecryptPath 解密后文件路径
* @throws IOException io异常
*/publicstaticvoidfileAcsDecrypt(String fileEncryptPath,String outDecryptPath)throwsIOException{File file =newFile(fileEncryptPath);// 以 byte 的形式读取,不改变文件数据的编码格式byte[] outFile =CryptoUtils.aesDecryptForFront(Files.readAllBytes(file.toPath()),CryptoUtils.KEY_DES);OutputStream out =newBufferedOutputStream(newFileOutputStream(outDecryptPath));assert outFile !=null;
out.write(outFile);
out.flush();System.out.println("解密结束!");}
2.2.7 使用(测试)方式一:
文本
main方法进行测试
publicstaticvoidmain(String[] args)throwsException{String old ="12345678";String target ="mbn/Mykb4f7xt2Zhz0xS6w==";// 加密后的字符串//加密System.out.println(CryptoUtils.aesEncryptForFront(old,CryptoUtils.KEY_DES));//解密System.out.println(CryptoUtils.aesDecryptForFront(target,CryptoUtils.KEY_DES));}
2.2.8 使用(测试)方式二:
文件
举例中:
pzy.txt文件需要有内容
, 名称随意 后缀随意
//加密/解密(生成加密后的文件后缀可以自定义)CryptoUtils.fileAcsEncrypt("D:\\pzy.txt","D:\\pzy1.txt");CryptoUtils.fileAcsDecrypt("D:\\pzy1.txt","D:\\pzy2.txt");
2.3 执行结果
2.3.1 控制台输出
mbn/Mykb4f7xt2Zhz0xS6w==
12345678
加密开始!
解密结束!
2.3.2 如图所示
文件生成 beta版
文件内容解释
- 第一个是
原文件
- 第二个是
加密byte后文件
不重要- 第三个是
解密后文件
2.4 跳过2.2 工具包代码
2.2详细解释 2.4 完整版
后续版本中同时对上面介绍的部分代码进行调整如下:
加密模式
EBC-> CBC 进行调整
- EBC: 一种简单的加密模式,每个明文块独立加密,不需要前后的文块信息, 并且不需要IV
- CBC: 更安全的加密模式,它使用前一个密文块的一部分(通常是最后8个字节)作为下一个明文块的加密密钥, 需要IV
- 增加了
初始化向量
(IV
)- 使用方式没有变化, 与上面解释完全相同
2.4.1 CryptoUtils密码学工具包
/**
* AES 加密/解密工具类 beta版
* <p>
* 版本更新
* 1. 新增json串加密解密
* 2. 新增文件加密与解密
* 3. 增加测试用例
*
* @author pzy
* @version v2.0.1
* @description OK
*/publicclassCryptoUtils{//这个密钥需要是16位 //对应128bit 原因: 128的密钥长度是目前能对安全性和性能的一种比较理想的折中选择publicstaticfinalStringKEY_DES="pzyPzyPzyPzyPzyP";// 偏移量 16位privatestaticfinalString iv ="0102030405060708";// private static final String algorithmStr = "AES/EBC/PKCS5Padding";privatestaticfinalString algorithmStr ="AES/CBC/PKCS5Padding";privatestaticfinalbyte[] ivByte = iv.getBytes(StandardCharsets.UTF_8);/**
* AES加密文本
*
* @param content 明文
* @param encryptKey 秘钥,必须为16个字符组成
* @return 密文
*/publicstaticStringaesEncryptForFront(String content,String encryptKey){if(StringUtils.isEmpty(content)||StringUtils.isEmpty(encryptKey)){returnnull;}try{Cipher cipher =Cipher.getInstance("AES/CBC/PKCS5Padding","SunJCE");
cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(encryptKey.getBytes(),"AES"),newIvParameterSpec(ivByte));byte[] encryptStr = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));returnBase64.getEncoder().encodeToString(encryptStr);}catch(Exception e){
e.printStackTrace();returnnull;}}/**
* AES解密文本
*
* @param encryptStr 密文
* @param decryptKey 秘钥,必须为16个字符组成
* @return 明文
*/publicstaticStringaesDecryptForFront(String encryptStr,String decryptKey){if(StringUtils.isEmpty(encryptStr)||StringUtils.isEmpty(decryptKey)){returnnull;}try{byte[] encryptByte =Base64.getDecoder().decode(encryptStr);Cipher cipher =Cipher.getInstance(algorithmStr);
cipher.init(Cipher.DECRYPT_MODE,newSecretKeySpec(decryptKey.getBytes(),"AES"),newIvParameterSpec(ivByte));byte[] decryptBytes = cipher.doFinal(encryptByte);returnnewString(decryptBytes);}catch(Exception e){
e.printStackTrace();returnnull;}}/**
* AES加密文件
*
* @param bytes 字节
* @param encryptKey 秘钥key
* @return 字节byte
*/publicstaticbyte[]aesEncryptForFront(byte[] bytes,String encryptKey){if(StringUtils.isEmpty(bytes)||StringUtils.isEmpty(encryptKey)){returnnull;}try{Cipher cipher =Cipher.getInstance(algorithmStr);
cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(encryptKey.getBytes(),"AES"),newIvParameterSpec(ivByte));return cipher.doFinal(bytes);}catch(Exception e){
e.printStackTrace();returnnull;}}/**
* AES解密文件
*
* @param bytes 字节
* @param decryptKey 解密key
* @return 解密字节
*/publicstaticbyte[]aesDecryptForFront(byte[] bytes,String decryptKey){if(StringUtils.isEmpty(bytes)||StringUtils.isEmpty(decryptKey)){returnnull;}try{Cipher cipher =Cipher.getInstance(algorithmStr);
cipher.init(Cipher.DECRYPT_MODE,newSecretKeySpec(decryptKey.getBytes(),"AES"),newIvParameterSpec(ivByte));return cipher.doFinal(bytes);}catch(Exception e){
e.printStackTrace();returnnull;}}/**
* 文件AES加密并输出
*
* @param fileSourcePath 文件原始路径
* @param outEncryptPath 加密数据文件路径
* @throws IOException io异常
*/publicstaticvoidfileAcsEncrypt(String fileSourcePath,String outEncryptPath)throwsIOException{System.out.println("加密开始!");File file =newFile(fileSourcePath);// 以 byte 的形式读取,不改变文件数据的编码格式byte[] bytes =Files.readAllBytes(file.toPath());byte[] outFile =CryptoUtils.aesEncryptForFront(bytes,CryptoUtils.KEY_DES);OutputStream out =newBufferedOutputStream(newFileOutputStream(outEncryptPath));assert outFile !=null;
out.write(outFile);
out.flush();}/**
* 文件AES解密并输出
*
* @param fileEncryptPath 加密后文件路径
* @param outDecryptPath 解密后文件路径
* @throws IOException io异常
*/publicstaticvoidfileAcsDecrypt(String fileEncryptPath,String outDecryptPath)throwsIOException{File file =newFile(fileEncryptPath);// 以 byte 的形式读取,不改变文件数据的编码格式byte[] outFile =CryptoUtils.aesDecryptForFront(Files.readAllBytes(file.toPath()),CryptoUtils.KEY_DES);OutputStream out =newBufferedOutputStream(newFileOutputStream(outDecryptPath));assert outFile !=null;
out.write(outFile);
out.flush();System.out.println("解密结束!");}}
2.4.2 测试代码完整版
/**
* 提供测试方式
*
* @param args ...
* @throws Exception 异常
*/publicstaticvoidmain(String[] args)throwsException{String old ="pzy: 今天天气挺好";String target ="c882579N5IQtAGKJcgYWGhvIbNTMZb6dGugSBl3IGzU=";// 加密后的字符串//文本------------------>//加密System.out.println(CryptoUtils.aesEncryptForFront(old,CryptoUtils.KEY_DES));//解密System.out.println(CryptoUtils.aesDecryptForFront(target,CryptoUtils.KEY_DES));//文件 beta版------------------------>//加密/解密(生成加密后的文件后缀可以自定义)CryptoUtils.fileAcsEncrypt("D:\\pzy.txt","D:\\pzy1.txt");CryptoUtils.fileAcsDecrypt("D:\\pzy1.txt","D:\\pzy2.txt");}
2.4.3 秘钥和IV随机 都是16位字符串即可 不可暴露
3. 结合业务使用
java 业务中需要数据加密的地方
数据安全
:在处理敏感数据如:个人信息
、财务信息
、或公司核心机密
,这些数据在存储和传输过程中都必须保证是安全
的。可以使用Java提供的加密和解密库
来加密这些数据,以防止数据泄露。网络安全
:在构建网络应用时,如Web服务、或者在两个系统之间进行数据传输时,你需要保护数据的完整性。这时,你可以使用加密技术来确保数据在传输过程中不会被篡改。保护密码和令牌
:敏感密码或令牌如: 数据库密码、API的密钥等。防止被恶意用户获取, 就得使用加密技术来存储这些密码,并在需要的时候解密。云存储和数据保护
:在云存储服务中,如Amazon S3, Google Cloud Storage等,你可以使用加密技术来保护你的数据。这样即使数据被泄露,也需要有正确的密钥才能解密。数据库保护
:数据库中存储敏感数据
时需要使用加密技术
来保护数据。数据库被泄露,关键信息也需要正确的密钥才能解密。物联网
:物联网设备
中,通常会使用加密技术来保护数据的传输和存储。例如,智能家居设备传输和接收指令
时, 设备的数据都会通过加密的连接发送,以确保数据的安全。
3.1 (
模拟
简易数据传输-收集功能)
后端返回值加密 然后获取到这个值解密
[异步处理, 解耦]
- 服务(1-n)取出数据进行处理(关键核心数据)
- 加密后交给mq(其他)去处理[
省略,mq具体操作请看mq系列文章
]- (数据处理类)服务 接收到mq(其他)消息进行解密处理
3.1.1 创建统一返回值(
叫啥都行
)
ResultResponse 这个类名随意, AaaResponse都行
注意: 加密前需要将
Object对象转换成json
然后再加密解密
JSON.toJSONString(data)
累加一下 加几个方法
/**
* 获取数据分析data(主)解密
* <p>
* 1. 修复返回 空字符串 null 的情况(主)
* 2. 解密数据分析字符串
*/publicStringgetAnalyseData()throwsJsonProcessingException{Object data =get("analyseData");//解密专用return data ==null?null:CryptoUtils.aesDecryptForFront(String.valueOf(data),CryptoUtils.KEY_DES);// return data == null ? null : new ObjectMapper().writeValueAsString(CryptoUtils.aesDecryptForFront(String.valueOf(data), CryptoUtils.KEY_DES));}/**
* 获取数据分析数据
*
* @param typeReference
* @param <T>
* @return
*/public<T>TgetAnalyseData(TypeReference<T> typeReference){Object data =get("analyseData");//解密操作String cryptoDecodeStr =CryptoUtils.aesDecryptForFront(String.valueOf(data),CryptoUtils.KEY_DES);// String jsonStr = JSON.toJSONString(cryptoDecodeStr);returnJSON.parseObject(cryptoDecodeStr, typeReference);}/**
* 数据分析专用(主) 加密
* <p>
* 数据完全不暴露给前端
* @param data
* @return
*/publicResultResponsesetAnalyseData(Object data){if(data !=null){//加密(密钥)
data =CryptoUtils.aesEncryptForFront(JSON.toJSONString(data),CryptoUtils.KEY_DES);}put("analyseData", data);returnthis;}//---------------------------------------->
3.1.2 controller层写一个demo
@Analyse(analyseBaseType =1,value ="测试")@ApiOperation(value ="测试1")@PostMapping("/addTest01")publicResultResponseaddTest01(@RequestBodyUser user){
log.info("===> 测试1 <===");
user.setPassword("123456");returnResultResponse.ok("添加成功!!!").setData(user.getAge()).setAnalyseData(user);}
3.1.3 数据采集注解(标记是否采集和加密)
如图所示,业务逻辑(
加注解
是采集和加密的) 细节不过多展示了
3.1.4 业务具体实现逻辑数据处理(略)
注解具体实现不展示了(具体业务了)
, 本篇主要是AES加密解密
3.1.5 测试结果(如图所示)
4. 前端使用AES加密(大致流程)
Java: 使用
AES/CBC/PKCS5Padding
加密的数据,
前端JS: 可以使用crypto库中的AES/CBC
解密函数进行解密。
- AES:
128
位(bit)- 使用
Node.js的crypto模块
如果是web端
- 使用
Web Cryptography API或其他第三方库(如crypto-js)
具体细节请查看前端AES的文档, 这里只是一个demo
4.1 前端js实现方式
const crypto =require('crypto');// 后端加密的密钥,与前端使用的密钥相同 const key ='your_secret_key';// 后端加密的初始化向量(IV),与前端使用的IV相同 const iv ='your_initialization_vector';// 后端加密后的密文 const ciphertext ='encrypted_data';// 创建AES解密对象,指定CBC模式、PKCS5Padding填充方式和密钥及IV const decipher = crypto.createDecipheriv('aes-128-cbc', key, Buffer.from(iv,'hex'));
decipher.setAutoPadding(true);// 自动填充PKCS5Padding // 解密数据 const plaintext = decipher.update(ciphertext,'hex','utf8');
plaintext += decipher.final('utf8');
console.log('解密后的明文:', plaintext);
5. 文章的总结与预告
5.1 本文总结
本文介绍了AES的定义,用法,及使用方式<
详细说明:
- 对比了
RSA(非对称性)
的区别, 各自的应用场景- 代码实现工具类, 业务中具体使用方式
- 最新增加了大文件加密解密功能
- 并且在后续更新中继续修改 完善部分说明和代码
5.2 下文预告
** —=> RSA(非对称性加密)的原理及代码使用方式 <=—**
包括:
- 公钥私钥的创建原理
- 明文+公钥 = 秘钥+明文
- 运算公式
*
,%
- java代码实现
- 测试代码及结果
- 分析,优化,总结
***作者pingzhuyan 感谢观看
版权归原作者 pingzhuyan 所有, 如有侵权,请联系我们删除。