Java加解密视频(AES算法)的实现
认识AES
先来看看什么是AES算法
什么是AES
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
AES简介
这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一 [1] 。
该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijdael之名命之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 “Rhine doll”。)
AES的加密模式及个模式加密的优缺点
AES的分组长度是128bit,三种可选密钥长度128bit,192bit和256bit,轮数分别为10、12和14
常见五中工作模式:
ECB (ElectronicCodebook,电子密码本)
优点:简单、可并行计算、误差不传递
缺点:不能隐藏明文模式(比如图像加密轮廓仍在)、主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)
用途:需要并行加密的应用
CBC (Cipher Block Chaining,密码分组链接)∶
优点:不容易主动攻击(误差传递)、适合长报文,是SSL、IPSec标准
缺点:无法并行、误差传递
用途:长报文传输,SSL和IPSec
CFB (CipherFeedback,密码反馈)︰
优点:不容易主动攻击(误差传递),分组转变为流模式,可加密小于分组数据缺点:无法并行、误差传递
OFB (OutputFeedback,输出反馈)︰
优点:分组转为流模式、可加密小于分组数据
缺点:主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)
用途:通信信道质量不高时使用,比如卫星通信
CTR (Counter,计数器模式)∶
描述:计算器模式不常见,在CTR模式中,有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次。
优点:并行、一次一密、不传递误差
缺点:主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)
总结
分组模式: ECB、CBC和CTR;
流模式: CFB、OFB
传递误差: CBC、CFB
不传递误差: ECB、OFB和CTR
可并行: ECB、CTR
不可并行: CBC、OFB、CFB
简单的伪代码及部分实现代码
加密视频
其实就是用字节流处理,没什么很大的难点 唯一需要注意的是,加解密字节数组的一些注意点。
加解密的伪代码
加密
public void encryptVideo(String filePath, String password) throws Exception {
//声明输入输出流为null -- 伪代码
try {
//在这里实例化输入输出流-- 伪代码
//读取文件和写入文件必要的参数
//文件的长度
long fileSize = new File(filePath).length();
//+1是为了保证 long不为整数时 向上取整
byte[] readByte = new byte[(int)fileSize + 1];
//从输入流中读取字节数组
bfInStream.read(readByte);
//获取使用Aes加密后的字节数组-- 伪代码
// 这里是额外的操作 比如可以再给字节数组进行自定义的加密操作 可有可无-- 伪代码
//输出流的写入加密后的字节数组-- 伪代码
}catch (FileNotFoundException fex) {
//这里做日志记录
}catch (Exception ex) {
//其他报错
}
finally {
//对应流的关闭
}
}
}
解密
其实流程和加密视频差不多,但是需要修改一些小地方
//获取文件长度
long fileSize = new File(filePath).length();
//保证字节数组为16的整数倍
byte[] readByte =
new byte[(int)fileSize + (16 - (int)fileSize%16)];
字节数组的加解密
public byte[] enAesForVideo(byte[] videoByte, String password) throws Exception {
byte[] enCode = null;
try {
//生成一个AES算法的密钥生成器
KeyGenerator kg = KeyGenerator.getInstance("AES");
//使用给定的随机源(可以看作你自己设置的密码,但对于程序而言,你输入的只是一个生成密钥的”种子“)
// 初始化该密钥生成器(生成密钥长度为128位)
kg.init(128, new SecureRandom(password.getBytes("UTF-8")));
//生成一个种子密钥。
SecretKey ruleKey = kg.generateKey();
//获取编码后的种子密钥
byte[] skCode = ruleKey.getEncoded();
//从给定的字节数组构造一个aes密钥
SecretKey aesKey = new SecretKeySpec(skCode, "AES");
//该类提供加密和解密的加密密码的功能
Cipher cp = Cipher.getInstance("AES");
//用密钥初始化
cp.init(Cipher.ENCRYPT_MODE, aesKey);
//真正的加密操作
enCode = cp.doFinal(videoByte);
} catch (Exception ex) {
//在这里进行出错的日志记录
ex.printStackTrace();
}
return enCode;
}
解密字节数组
与加密字节数组唯一不同的是以下这两项 其他一样
//该类提供加密和解密的加密密码的功能。
//它构成了Java加密扩展(JCE)框架的核心。
Cipher cp = Cipher.getInstance("AES/ECB/NoPadding");
//设置为解密模式
cp.init(Cipher.DECRYPT_MODE, aesKey);
遇到的问题
分段读取文件加密,导致解密后文件无法读出
直接一次性读入整个文件。(感觉上是分段加密后导致某些字符与换行符什么的特殊字符冲突)
解密时,未指定解密模式导致解密失败
将创建实例时的
Cipher cipher = Cipher.getInstance("AES");
将参数改为以下内容即可
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
解密时,需要输入的字节数组为16的整数倍
在创建临时字节数组用于,取得读出的数据时,加上参数,使得字节数组为16的整数倍。
long fileSize = new File(filePath).length();
byte[] readByte =
new byte[(int)fileSize + (16 - (int)fileSize%16)];