DES加密算法应用:分组加密模式
通常,大多数的分组加密算法都是把数据按照64位分组的方式进行加密和解密。但是几乎所有的加密工作所涉及的数据量都远远大于64位,因此就需要不断地重复加密过程,直到处理完所有的分组。这种分组加密中所涉及的重复性方式称为分组加密模式。
处理多个数据分组最简单的方式是将每一个生成的密文分组添加到之前生成的密文分组之后。这种简单的方式被称为ECB,或者电子码本(electronic code book)。这种方法的简单性使其比较流行,但它相对来说是不安全的。主要问题是,对于任意给定的密钥,相同的明文分组加密之后得到的密文结果总是一样的,即明文和密文的分组是一一对应的关系。假如黑客破解了哪怕一小段数据,他就可以以此建立一个密码本,来对其他数据段进行破解。
一种更好的方法是CBC或被称为密码分组链接的模式。
CBC模式通过对分组密码增加简单的操作和反馈避免ECB中出现的问题。反馈使得密文的每个分组都同之前执行的操作在一定程度上有依赖关系(ECB中每个分组的加密和解密都是独立的)。在CBC模式中,用之前的密文分组作为反馈,这样就算是明文中的同一个分组,每次都好像加密成另一个不同的密文分组一样。
对于之前作为反馈的密文分组,在加密一个明文分组前,将前一个输出的密文分组与该明文分组求异或,然后再加密。
当解密时,将前一个输出的明文分组同接下来待解密的密文分组求异或,然后再解密。这两种方式可以简单的表示为:
Ci = Ek(Pi ⊕ Ci-1)
Pi = Ci-1 ⊕ Dk(Ci)
这里Ci和Pi为缓冲区C和P中的第(i)个密文和明文分组,而Ek和Dk是使用密钥K进行的加密和解密操作。
通常,会在明文的开始处增加一个随机的数据块。这是因为即使有黑客知道明文的第一个分组包含的信息,它也不能用于模拟链接的顺序。这个增加的随机数据块称为 初始向量。按照正常的方式对其加密,这里不需要任何反馈。然后,将加密后的初始向量作为接下来加密和解密第一个分组数据的反馈。
下面的示例中给出了两个函数(cbc_encipher和cbc_decipher)的实现。它们采用DES算法中的CBC模式来对缓冲区中的数据做加密和解密的动作。
函数cbc_encipher接受一个size字节大小的明文缓冲区作为参数,使用key作为密钥来对其加密。该函数假设明文的第一个分组是64位的初始向量。
函数cbc_decipher接受一个size字节大小的密文缓冲区作为参数,使用key作为密钥来对期解密。为了保持对称性,初始化向量也要解密,并作为明文的第一个分组返回。
两个函数的时间复杂度都是O(n),这里n代表加密或解密的分组数量。这是因为这两个函数都只是简单地调用复杂度同为O(1)的des_encipher和dex_decipher,每处理一个分组调用一次。
示例:DES算法的CBC模式实现
/*cbc.c*/ #include <stdlib.h> #include "bit.h" #include "cbc.h" #include "encipher.h" /*cbc_encipher DES算法中的cbc加密模式*/ void cbc_encipher(const unsigned char *plaintext, unsigned char *ciphertext, const unsigned char *key, int size) { unsigned char temp[8]; int i; /*加密初始化向量*/ des_encipher(&plaintext[0],&ciphertext[0],key); /*使用DES算法中的CBC模式加密缓冲区*/ i=8; while(i < size) { bit_xor(&plaintext[i], &ciphertext[i-8], temp, 64); /*temp = Pi XOR Ci-1*/ des_encipher(temp,&ciphertext[i],NULL); /*Ek(temp)*/ i=i+8; } return; } /*cbc_descipher DES算法中的cbc解密模式*/ void cbc_decipher(const unsigned char *ciphertext, unsigned char *plaintext, const unsigned char *key, int size) { unsigned char temp[8]; int i; /*解密初始化向量*/ des_decipher(&ciphertext[0], &plaintext[0], key); /*使用DES算法中的CBC模式解密缓冲区*/ i=8; while(i < size) { des_decipher(&ciphertext[i],temp,NULL); /*temp = Dk(Ci)*/ bit_xor(&ciphertext[i-8], temp, &plaintext[i], 64); /*Ci-1 XOR temp*/ i=i+8; } return; }