用 Java 解密 C# 加密的数据(DES)【转】
[原文地址:http://yidinghe.cnblogs.com/articles/449212.html]
今天碰上一件令我头大的事情。我们的系统要和一个外部系统进行通讯,传输方式是采用 DES 算法对消息进行加密,再用 BASE64 编码。不过对方系统是用 C# 写的。平台不一样,于是我和对面的老兄先测试一下加密解密。这一测试问题就来了。两边采用同样的密钥,对同一个字符串加密出来的结果不一样。怎么办呢?我先把他那边的代码要过来了,他是这样写的(C#):
byte[] bytes = Encoding.UTF8.GetBytes(message); byte[] resultBytes = des.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);
return Convert.ToBase64String(resultBytes); }
而我这边呢,是用 Java 这样写的(仅仅加密到字节串,BASE64 编码是在另一个类里):
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8")); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(message.getBytes("UTF-8")); }
两边一对比我就奇怪了,他那边怎么有个 IV (initialization vector)?我打开JDK文档一看Cipher类,竟然也有一个getIV()方法。看来这 IV 大有来头。于是在JDK文档里面到处找IV,找到了一个叫“IvParameterSpec“的类,莫非就是它?它实现的是 AlgorithmParameterSpec 接口,而Cipher.init()中就有一个 AlgorithmParameterSpec 类型的参数。那么看来就是它了。于是参考了IvParameterSpec的构造函数后,我这样把它加进去:
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8")); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(message.getBytes("UTF-8")); }
这下行了吧,结果一运行报异常:
java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
这又是什么? “ECB”? 还是找吧,在JDK文档中找到了这么几句鬼东西:
哦,问题就出在方法里的第一行。那么不准用 ECB,该用什么呢?在该文往下找,找到了这么几项:
The following names can be specified as the mode component in a transformation when requesting an instance of
Cipher
:
- NONE: No mode.
- CBC: Cipher Block Chaining Mode, as defined in FIPS PUB 81.
- CFB: Cipher Feedback Mode, as defined in FIPS PUB 81.
- ECB: Electronic Codebook Mode, as defined in: The National Institute of Standards and Technology (NIST) Federal Information Processing Standard (FIPS) PUB 81, "DES Modes of Operation," U.S. Department of Commerce, Dec 1980.
- OFB: Output Feedback Mode, as defined in FIPS PUB 81.
- PCBC: Propagating Cipher Block Chaining, as defined by Kerberos V4.
我这样都换着试一下就行了。哎,运气不错,拿着第一个 CBC 试一下就成功了,加密后的字符串也“正确”了。 我那个方法就变成这样:
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8")); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(message.getBytes("UTF-8")); }
这样,解决了这个 ECB 之后,Java 和 .net 平台的两个应用终于能够相互加密和解密数据了。什么?文不对题?加密都写出来了,解密还不简单?自己看着办吧。
[原文地址:http://yidinghe.cnblogs.com/articles/449212.html]