基本介绍
分组密码,也叫块加密(block cyphers
),一次加密明文中的一个块。将明文按一定的位长分组,明文组经过加密运算得到密文组。将多个密文组合并成密文。密文组经过解密运算(加密运算的逆运算),还原成明文组。
序列密码,也叫流加密(stream cyphers
),一次加密明文中的一个位。利用少量的密钥(制乱元素)通过某种复杂的运算(密码算法)产生大量的伪随机位流,用于对明文位流的加密。也可以用同样的密钥和密码算法及与加密相同的伪随机位流,用以还原明文位流。
四种分组加密模式
图片来源:分组加密的四种模式(ECB、CBC、CFB、OFB)
本文以分享代码为主,具体的逻辑原理请查看上述博客↑
ECB(Electronic Code Book)/电码本模式
ECB
模式是最简单的一种,从图中就可以看出,就是利用一个密钥KEY
分别对每个明文块进行加密,解密就是逆过程,同时可以发现每个明文块加密过程是相互独立的,可以并行,所以加密效率是最快的。
CBC(Cipher Block Chaining)/密文分组链接方式
CBC
模式与之前的ECB加密过程差不多,只不过每个明文块的加密密钥依赖于前一个明文加密后的结果,所以不能并行处理。
Cipher Feedback (CFB)/密文反馈模式
CFB
模式就是对初始化向量IV
进行加密再与明文异或来得到密文,再利用得到的密文作为下一个明文加密的密钥。
Output Feedback (OFB)/输出反馈模式
OFB
模式与CFB
模式的加密过程类似,不过OFB
模式是对明文加密后再进行的异或操作。这个模式最神奇的地方是加密和解密的过程是一样的,你可以查看下面Java
实现CFB
的加解密函数,是一模一样的。
代码实现
代码中实现了对普通字节数组的加/解密,还实现了对图片加解密。对图片的加解密是利用直接内存实现的。处理效率高,可以减少一次从操作系统到JVM的IO
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
public class PacketSecret {
private OperationMode mode;//要使用的加密运行模式
private SecretKey secretKey;//DES使用的密钥
private Cipher enCipher, deCipher;//加密/解密算法,这里选用DES
private static final byte[] IV = {
1, 2, 3, 4, 5, 6, 7, 8};
private static byte count;//记录填充数
public PacketSecret() {
this(new ECB());
}
public PacketSecret(OperationMode mode) {
this.mode = mode;
initDES();
}
public void setMode(OperationMode mode) {
this.mode = mode;
}
public OperationMode getMode() {
return mode;
}
//初始化密钥和加密算法
private void initDES() {
try {
//原始密钥,至少8个
byte[] rawKey = new byte[]{
1, 2, 3, 4, 5, 6, 7, 8};
DESKeySpec deskeySpec = new DESKeySpec(rawKey);
secretKey = SecretKeyFactory.getInstance("DES").generateSecret(deskeySpec);
enCipher = Cipher.getInstance("DES/ECB/NoPadding");//这里只使用普通的DES模式
deCipher = Cipher.getInstance("DES/ECB/NoPadding");
enCipher.init(Cipher.ENCRYPT_MODE, secretKey);
deCipher.init(Cipher.DECRYPT_MODE, secretKey);
} catch (Exception e) {
System.out.println("DES算法初始化失败");
e.printStackTrace();
}
}
//对分组数据预处理,以输入加密函数
private byte[] initPacket(byte[] data) {
if (data.length % 8 == 0) return data;
//如果刚好64一组则直接进行加密,否则先填充
byte[] newData = new byte[((data.length >> 3) + 1) * 8];
System.arraycopy(data, 0, newData, 0, data.length);//默认填充0
count = (byte) (8 - data.length % 8