记Triple DEA加密在C#与Java之中的一些调用差异
最近在将C#源码转换到到 Java 源码的时候,碰到一个使用 Triple DEA 加密算法的函数:
1 2 3 4 5 6 |
byte[] str_bytes = Encoding.Unicode.GetBytes(str); byte[] key_bytes= Encoding.ASCII.GetBytes(key); TripleDESCryptoServiceProvider cryptoServiceProvider = new TripleDESCryptoServiceProvider(); cryptoServiceProvider.Key = key_bytes; cryptoServiceProvider.Mode = CipherMode.ECB; return Convert.ToBase64String(cryptoServiceProvider.CreateEncryptor().TransformFinalBlock(str_bytes, 0, str_bytes.Length)); |
搜索了一下上述代码在 Java 中的对应实现,可以得到以下的 Java 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
byte[] str_bytes = str.getBytes("utf-16LE"); byte[] key_bytes = key.getBytes("ascii"); SecretKey deskey = new SecretKeySpec(key_bytes, "DESede"); Cipher cipher = null; try { cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, deskey); return cipher.doFinal(str_bytes); } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | InvalidKeyException | BadPaddingException e) { e.printStackTrace(); } return null; |
这里有两个坑:
-
C# 中的
1Encoding.Unicode.GetBytes()
是 UTF-16LE 的编码,不注意看 IntelliSense 的话可能就以为是 UTF-8 编码了。
-
代码中有关密钥的是这么一行
1cryptoServiceProvider.Key = key_bytes;这里的 key_bytes我传入了一个 length 为 16 的 byte 数组,但是在 Java 之中我想故技重施就会提示:Invalid key length: 16 bytes,提示密钥长度不足,实际需要传入 length 为 24 的 byte[]。
最初我使用了 0 来填充剩余的 8 个 byte,但是发现在 Java 中加密后的字符串与 C# 中的不同,但长度相同,因此可能是密钥不对。
多番搜索后,而在StackOverflow 中的一个问题回答提到:DES would expect an 8 byte key (with parity). So Triple DES expects a 24 byte key (with parity). Since you only have a 16 byte key, you have to replicate some of it, to get the final key. Oftentimes the first and last 8 bytes are the same.
于是将代码改为以下实现:
1234567891011121314151617181920byte[] str_bytes = str.getBytes("utf-16LE");byte[] key_bytes = new byte[24];byte[] key_temp_bytes = key.getBytes("ascii");if (key_temp_bytes.length < 24) {System.arraycopy(key_temp_bytes, 0, key_bytes, 0, key_temp_bytes.length);System.arraycopy(key_temp_bytes, 0, key_bytes, 16, 8);}SecretKey deskey = new SecretKeySpec(key_bytes, "DESede");Cipher cipher = null;try {cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, deskey);return cipher.doFinal(str_bytes);} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | InvalidKeyException | BadPaddingException e) {e.printStackTrace();}return null;问题解决!
本文采用 CC BY-NC-SA 3.0 协议进行许可,在您遵循此协议的情况下,可以自由共享与演绎本文章。
本文链接:https://blog.codeingboy.me/some-difference-about-tdea-between-csharp-and-java/