在java开发过程中,很多时候我们都需要加密数据,例如声音、敏感信息等。我们通常使用的是 MD5加密、SHA加密、DES 加密、AES 加密等。今天我们就看看AES 加密。

问题出处

在项目中,代码写的好好的,本地测试什么都没问题,打包发布,高高兴兴的回家,第二天到公司,发现加密的数据,下载时解密失败。这什么情况,哪出了问题,汗直接流了出来。不经意间的一个想法:windows和linux 有什么差别呢?于是开始调查,有了如下的总结。

解决方法

方法一

代码如下:

    private void encryptAES1(String key, ByteArrayInputStream inputStream, ByteArrayOutputStream outputStream) throws IOException {
CipherInputStream cipherInputStream = null;
try{
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom(key.getBytes(StandardCharsets.UTF_8)));
SecretKey secretKey = keyGenerator.generateKey();
byte[] keyEncoded = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyEncoded, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);// 解密 Cipher.DECRYPT_MODE
cipherInputStream = new CipherInputStream(inputStream, cipher);
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = cipherInputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, numBytes);
}
}catch (NoSuchPaddingException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
e.printStackTrace();
} finally {
outputStream.flush();
outputStream.close();
inputStream.close();
if (null != cipherInputStream){
cipherInputStream.close();
}
}
}

此方法在windows 系统是能够加密和解密。但是在linux 系统中,加密解密会失败。原因是因为windows 和linux 内核不同,产生的随机数不同,所以导致了linux 系统加密解密失效。解决方法参照 方法二

方法二

代码如下:

    private void encryptAES2(String key, ByteArrayInputStream inputStream, ByteArrayOutputStream outputStream) throws IOException {
CipherInputStream cipherInputStream = null;
try{
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] keyEncoded = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyEncoded, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);//解密 Cipher.DECRYPT_MODE
cipherInputStream = new CipherInputStream(inputStream, cipher);
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = cipherInputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, numBytes);
}
}catch (NoSuchPaddingException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
e.printStackTrace();
} finally {
outputStream.flush();
outputStream.close();
inputStream.close();
if (null != cipherInputStream){
cipherInputStream.close();
}
}
}

此方法是能够解决不同系统加密算法的差异,能够成功的实现windows、linux 系统加密解密。但是经过代码检测,发现【SecureRandom.getInstance("SHA1PRNG");】中的 SHA1PRNG 是有代码风险的。通过查找资料,发现可以替换成 NativePRNG ,但是代码书写完成后,运行失败。经过请教公司前辈们,的到 方法三 的方案。

方法三

代码如下:

    private void encryptAES3(String key, ByteArrayInputStream inputStream, ByteArrayOutputStream outputStream) throws IOException {
CipherInputStream cipherInputStream = null;
try{
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes(StandardCharsets.UTF_8));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);// Cipher.DECRYPT_MODE
cipherInputStream = new CipherInputStream(inputStream, cipher);
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = cipherInputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, numBytes);
}
}catch (NoSuchPaddingException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
e.printStackTrace();
} finally {
outputStream.flush();
outputStream.close();
inputStream.close();
if (null != cipherInputStream){
cipherInputStream.close();
}
}
}

此方法去除了随机数,使用MessageDigest 类,可以生成和 KeyGenerator 生成相同位数的的密匙。有没有代码风险或着缺陷还没有发现,路过的朋友要是知道的化请留言告知。

补充

  • 以上三种方法中 keyGenerator.init(param1, param2) 方法中,第一个参数是产生随机数的位数,他可以是128(16字节)、192(24字节)、256(32字节)。需要加密的数据,不满16字节的,加密后会生成16字节的加密数据;等于16字节的数据,加密后会生成32字节的加密数据。所以方法三中 【byte[] keyBytes =newbyte[16];】是16。
  • 建议:若需要对加密后数据拼接的,且整个文件解密的,例如实时的声音数据、大篇幅的文本消息(分段加密)等,最好加密的数据是16的倍数,加密后减去末尾的16字节再拼接(最后一段数据加密不需要减16)。

总结

这里只是简单的介绍了AES 加密,为什么没有详细的说明DES、AES、MD5 等加密的原理和差别呢,因为我还不够了解他们的原理。感兴趣的小伙伴可以网上搜索下他们的原理和差别。

Java AES 加密小试牛刀的更多相关文章

  1. Java AES加密

    Java AES 加密 加密 /** * * @description 加密 * * @param content 需要加密的内容 * @param password 加密密码 * @return * ...

  2. C# 实现 JAVA AES加密解密[原创]

    以下是网上普遍能收到的JAVA AES加密解密方法. 因为里面用到了KeyGenerator 和 SecureRandom,但是.NET 里面没有这2个类.无法使用安全随机数生成KEY. 我们在接收J ...

  3. java AES加密、解密(兼容windows和linux)

      java AES加密.解密 CreationTime--2018年7月14日10点06分 Author:Marydon 1.准备工作 updateTime--2018年8月10日15点28分 up ...

  4. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  5. Java aes加密C#解密的取巧方法

    摘要: 项目开发过程中遇到一个棘手的问题:A系统使用java开发,通过AES加密数据,B系统使用C#开发,需要从A系统获取数据,但在AES解密的时候遇到麻烦.Java的代码和C#的代码无法互通. Ja ...

  6. Java AES加密案例

    AES加密原理 http://www.blogjava.net/amigoxie/archive/2014/07/06/415503.html PHP 加密 https://segmentfault. ...

  7. C#与Java AES 加密解密

    参考文档:https://www.cnblogs.com/xbzhu/p/7064642.html 前几天对接Java接口,需要C#加密参数,Java解密.奈何网上找了一堆大同小异的加解密方法都跟Ja ...

  8. JAVA AES加密解密

    import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java ...

  9. Java AES 加密工具类

    package com.microwisdom.utils; import java.security.NoSuchAlgorithmException; import java.security.S ...

随机推荐

  1. Java 大数加法HdAcm1002

    1 import java.util.Scanner; 2 3 4 public class Main { 5 public static void main(String[] args) { 6 S ...

  2. 《深入理解java虚拟机》第3版笔记3

    第3章 垃圾收集器与内存分配策略 可达性分析算法 在Java技术体系里面,固定可作为GC Roots的对象包括以下几种: 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使 ...

  3. super的两个作用

    super与实例没有什么关系,它本身有两个作用的,参考如下理解: 1.super可以当函数用.super作为函数调用时,表示父类的构造函数.示例: class Par { constructor() ...

  4. 假期作业02:安装JDK与文本编辑器并编写第一个Java程序

    假期作业02:安装JDK与文本编辑器并编写第一个Java程序 一.安装JDK与文本编辑器并编写第一个java程序 首先在oracle官网(需要创建账号,进行登录后方可使用)按照自己的需求下载JDK(h ...

  5. C#多线程开发-线程池03

    你好,我是阿辉. 前面2篇文章介绍了线程的基础知识和线程同步,下面我们来一起认识学习下,线程池的使用. 线程池 创建线程是昂贵的操作,所以为每个短暂的异步操作创建线程会产生显著的开销.一般情况下,都会 ...

  6. IOS 集成 Bilibili IJKPlayer播放器,播放rtmp视频流

    因为公司项目需要,我一个连iPhone都没用过的人竟然跑去开发iOS APP.近一段时间一直忙于赶项目,到今天差不多了,所以记录一下当时遇到的各种坑,先从ios 集成 ijkplayer播放器说起! ...

  7. RabbitMQ-如何保证消息在99.99%的情况下不丢失

    1. 简介 MQ虽然帮我们解决了很多问题,但是也带来了很多问题,其中最麻烦的就是,如何保证消息的可靠性传输. 我们在聊如何保证消息的可靠性传输之前,先考虑下哪些情况下会出现消息丢失的情况. 首先,上图 ...

  8. 模拟BS服务器

    一.模拟BS服务器分析 二.BS模拟服务器代码实现 图片都是单独请求,后台单独线程,这边是通过构造方法传入的Runable接口的实现类匿名对象创建线程: 创建本地输入流读取到网络输出流传过来的信息再放 ...

  9. 前端--jstree--异步加载数据

    利用回调来处理服务器返回的数据, 默认只能解析固定格式的返回值 <div class=""> <div id="div-jstree"> ...

  10. RocketMQ详解(二)安装使用详解

    专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...