您的位置:首页 > 编程语言 > Java开发

用 Java 解密 C# 加密的数据(DES)

2009-11-05 11:40 701 查看

用 Java 解密 C# 加密的数据(DES)

[原文地址:http://yidinghe.cnblogs.com/articles/449212.html]

今天碰上一件令我头大的事情。我们的系统要和一个外部系统进行通讯,传输方式是采用 DES 算法对消息进行加密,再用 BASE64 编码。不过对方系统是用 C# 写的。平台不一样,于是我和对面的老兄先测试一下加密解密。这一测试问题就来了。两边采用同样的密钥,对同一个字符串加密出来的结果不一样。怎么办呢?我先把他那边的代码要过来了,他是这样写的(C#):

public static string Encrypt(string message, string key)
{
DES des = new DESCryptoServiceProvider();
des.Key = Encoding.UTF8.GetBytes(key);
des.IV = Encoding.UTF8.GetBytes(key);

byte[] bytes = Encoding.UTF8.GetBytes(message);
byte[] resultBytes = des.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);

return Convert.ToBase64String(resultBytes);
}

而我这边呢,是用 Java 这样写的(仅仅加密到字节串,BASE64 编码是在另一个类里):

public static byte[] desEncrypt(String message, String key) throws Exception {
Cipher cipher = Cipher.getInstance("DES");

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的构造函数后,我这样把它加进去:

public static byte[] desEncrypt(String message, String key) throws Exception {
Cipher cipher = Cipher.getInstance("DES");

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文档中找到了这么几句鬼东西:

the SunJCE provider uses ECB as the default mode, and PKCS5Padding as the default padding scheme for DES, DES-EDE and Blowfish ciphers. This means that in the case of the SunJCE provider,
Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");
and
Cipher c1 = Cipher.getInstance("DES");
are equivalent statements.

哦,问题就出在方法里的第一行。那么不准用 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 试一下就成功了,加密后的字符串也“正确”了。
我那个方法就变成这样:

public static byte[] desEncrypt(String message, String key) throws Exception {
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: