关于3DES算法C版本与JAVA版本的兼容问题
http://argv.info/2011/01/06/c-on-the-3des-algorithm-version-version-and-java-compatibility/
今天在一个项目中遇到报文中密码字段3DES加密的情况,对方提供了JAVA版的例子,我这里下载了一个C版本的3DES实现源码包,尝试后发现加密后结果不同。
在网上查了下,发现有很多和这个情况一样,在《用java实现3des加密》一文中提到:
对于其他语言开发的3des,一定要采用相同的mode和padding才能保证通信。
重点就在这里,这里说的mode和padding是什么意思呢?(注:以下内容大段抄袭《DES 算法的 C++ 与 JAVA 互相加解密》-。-)
首先说mode。mode在这里指加密模式。常见的加密模式有ECB/CBC/CFB/OFB四种。加密算法是按块进行加密的,例如DES是64bit(8 bytes)一个块进行加密,每次输入8个字节的明文进行加密,输出8个字节密文,如果是明文一共16个字节长,则分成两组加密。例如明文是12345678 12345678(空格为了查看方便,实际不包含,下同),那么加密的结果类似C4132737962C519C C4132737962C519C,如果是你,看到密文什么感想?没错,这个应该是一组数据重复两遍吧?这中加密模式就是ECB,分组之间没有联系,只要组和组明文相同,那么他们的密文也是相同的。为了解决这个问题,出现了其他的加密模式,分别为CBC 加密模式(密码分组连接),CFB加密模式(密码反馈模式),OFB加密模式(输出反馈模式)。CBC 是要求给一个初始化的向量,然后将每个输出与该向量作运算,并将运算的结果作为下一个加密块的初始化向量,CFB 和 OFB 则不需要提供初始化向量,直接将密码或者输出作为初始化向量进行运算;这样就避免了明文的规律出现在密文中;当然缺点是解密时需要保证密文的正确性,如果网络传输时发生了一部分错误,则后面的解密结果就可能是错误的(ECB模式仅影响传输错误的那个块)。
接下来是padding。padding在这里指填充方式,假如明文是10位,按照8bytes分组,正好1组多2个byte,这2个byte怎么加密?这时候必须对明文进行填充。填充方式很多,具体可以参考《Using Padding in Encryption》一文。常用的PKCS#7,该填充方法是将每一个补充的字节内容填充为填充的字节个数;例如明文长度是 100 , 分组的大小是32个字节,那么需要分为四组,补充28个字节,那么补充的字节全部补充为’\0×28′。还有一种PKCS#5,和PKCS#7的区别就是,分组的大小为8个字节。另外还有一个规定,就是如果明文刚刚好进行分组,那么需要补充一个独立的分组出来。例如 DES明文:12345678,为 8 个字节,则必须补充8个0×08至16个字节,然后进行加密;解密后的字符串为12345678\x08\x08\x08\x08\x08\x08\x08\x08,需要将后面的0×08去掉,就能得到原始明文。
知道了这些,再去看下JAVA版本的3DES加解密。private static final String Algorithm = "DESede"; //定义加密算法,可用DES,DESede,Blowfish
在这里,DESede算法即为传说中的3DES加密,其mode为ECB,padding为PKCS#5。按照上面所描述的,我封装了两个函数。
首先是包含的头文件,以及预定义内容:
|
其中d3des.h为网上下载的3des的C版本实现。网上很好找。
然后是加密函数:将from中长度为len个字节的明文,经过密钥key的DESede加密,获得密文存放在to中,函数返回值为密文长度。
|
解密函数:将from中长度为len个字节的密文,经过密钥key的DESede解密,获得明文存放在to中,函数返回值为明文长度。
|
以上两个函数中的key(24位)以及其他输入参数都需要函数调用者负责校验。
参考资料: [1] 用java实现3des加密 [2] DES 算法的 C++ 与 JAVA 互相加解密 [3] Using Padding in Encryption [4] Block cipher modes of operation
分类: Algorithm, C/CPP