分组加密算法运行模式
分组加密算法运行模式
分组加密算法运行模式
分组加密算法顾名思义,就是对明文进行定长分组,然后对每个分组进行单独的加密运算为密文,最后合并为最终的加密数据。
例如 DES
算法的明文分组为 \(64\) bit,通过 56
bit 的密钥生成的分组密文长度为 64
bit;
如果需要更长的明文,则需要对明文进行分组,然后进行迭代加密。而分组密码的迭代方法就称为分组加密算法的运行模式:
ECB 模式
Electronic codebook,即电码本模式,是最简单的运行模式,它一次对一个 \(64\) 比特长的明文分组加密,而且每次的加密密钥都相同。
如果消息长于 \(64\) 比特 , 则将其分为长为 \(64\) 比特的分组,最后一个分组如果不够 \(64\)比特,则需要填充。
解密过程也是一次对一个分组解密,而且每次解密都使用同一密钥。
下图表示了ECB模式:明文是由分组长为 64 比特的分组 序列 \(P_1\) ,\(P_2\) , ... ,\(P_n\) 构成,相应的密文分组序列是 \(C_1\),\(C_2\) ,...,\(C_N\) 。
ECB 在用于短数据(如加密密钥)时非常理想,因此如果需要安全地传递 DES 密钥,ECB 是最合适的模式。
缺陷
ECB 的最大特性是同一明文分组在消息中重复出现的话,产生的密文分组也相同。ECB 用于长消息时可能不够安全,如果消息有固定结构,密码分析者有可能找出这种关系。例如,如果已知消息总是以某个预定义字段开始,那么分析者就可能得到很多明文-密文
对。如果消息有重复的元素而重复的周期是 64 的倍数,那么密码分析者就能够识别这些元素。以上这些特性都有助于密码分析者, 有可能为其提供对分组的代换或重排的机会。
另外ECB模式中,每个明文对应着相应的密文。那么攻击者并不需要进行解密,他可以伪造密文的顺序,从而改变了解密出来的明文顺序。比如 A 转账给B C元。如果A,B,C是明文分组,其对应的密文分组是a,b,c, 则攻击者只需要改变密文的顺序为:b,a,c, 那么被解密出来的明文含义就是 B转账给A C元。
CBC模式
Cipher block chaining,密码分组链接模式。
CBC模式一次对一个明文分组加密,每次加密使用同一密钥,加密算法的输入是当前明文分组和前一次密文分组的异或,因此加密算法的输入不会显示出与这次的明文分组之间的固定关系,所以重复的明文分组不会在密文中暴露出这种重复关系。
解密时,每一个密文分组被解密后,再与前一个密文分组异或,得到明文分组。
SSL/TLS 协议就是使用CBC模式来保证通信的机密性的。
例:使用 java.crpto
包下的工具类,进行AES加密
// AES 运算
public void AESCipher(InputStream in, String key, OutputStream out, int mod) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException {
SecretKeySpec keySpec = new SecretKeySpec((key).getBytes(),"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(mod, keySpec);
int blockSize = cipher.getBlockSize();
byte[] bytes = new byte[blockSize];
try(BufferedInputStream bin = new BufferedInputStream(in, blockSize);
BufferedOutputStream bout = new BufferedOutputStream(out, blockSize)){
while(bin.read(bytes)>0){
byte[] ciphered = cipher.update(bytes);
out.write(ciphered);
}
}
}
// 加密
public void AESEncrypt(InputStream in, String key, OutputStream out) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException {
AESCipher(in,key,out,Cipher.ENCRYPT_MODE);
}
// 解密
public void AESDecrypt(InputStream in, String key, OutputStream out) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException {
AESCipher(in,key,out,Cipher.DECRYPT_MODE);
}
@Test
public void test2() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException {
AESEncrypt(new FileInputStream("/home/niss/.zshrc"),"1234567812345678",new FileOutputStream("./encrypt.data"));
AESDecrypt(new FileInputStream("./encrypt.data"),"1234567812345678",System.out);
}
注意:AES的密钥长度为
128
位,也就是16
字节;DES的密钥长度为56
位,也就是7
字节;
缺陷
CBC是一个链式结构,如果要生成密文分组 \(i\),则必须先加密明文分组 \(i-1\),\(i-2\),... \(1\),也就是说不能并行进行计算。
另外我们观察CBC的解密过程可以看到,如果一个密文分组损坏,只要密文长度不变,则只会影响其相关联的两个明文分组的解密。
CBC模式可以操纵解密过程的初始化向量,从而对解密后的明文进行攻击。具体来说就是对初始化向量进行反转,从而导致XOR之后的明文分组1也被反转了。
另外还有一种攻击叫做填充提示攻击,如果在分组密码中,明文长度不是分组长度的整数倍时候,需要在最后一个分组填充一些数据让其凑够一个分组长度。在填充提示攻击中,攻击者会反复发送一段密文,每次发送都修改填充的数据,从而根据解密的错误信息来推断一部分明文相关的信息。
CFB 模式
Cipher feedback,密文反馈模式。
DES 是分组长为 64 比特的分组密码,但利用 CFB 模式或 OFB 模式可将 DES 转换为流密码。流密码不需要对消息填充, 而且运行是实时的。
因此如果传送字母流,可使用流密码对每个字母直接加密并传送。
流密码具有密文和明文一样长这一性质,因此,如果需要发送的每个字符长为 \(8\) 比特,就应使用 \(8\) 比特密钥来加密每个字符。如果密钥长超过 \(8\) 比特,则造成浪费。
CFB 模式示意图,设传送的每个单元(如一个字符)是 \(j\) 比特长,通常取 \(j = 8\),与 CBC 模式一样,明文单元被链接在一起,使得密文是前面所有明文的函数。
OFB 模式
output feedback
,OFB模式。
结构类似于 CFB,不同之处是OFB 模式是将加密算法的输出反馈到移位寄存器,而 CFB 模式中是将密文单元反馈到移位寄存器。
OFB 模式的优点是传输过程中的比特错误不会被传播。例如 \(C_1\) 中出现 1 比特错误,在解密结果中只有 \(P_1\) 受到影响,以后各明文单元则不受影响。
而在 CFB 中,\(C_1\) 也作为移位寄存器的输入,因此它的 1 比特错误会影响解密结果中各明文单元的值。
OFB 的缺点是它比 CFB 模式更易受到对消息流的篡改攻击,比如在密文中取 1 比特的补,那么在恢复的明文中相应位置的比特 也为原比特的补。因此使得敌手有可能通过对消息校验部分的篡改和对数据部分的篡改,而以纠错码不能检测的方式篡改密文。