1

我在解密用 C# 加密的 Java 字节时遇到问题。

Java 的输出在五个明文块的最后两个中有错误。第四块完全错误,第五块有一个字符错误。

我已经仔细检查/注意到的事情:

  • 密钥和 IV 是相同的,尽管我必须在最后重复 16 位 C# 密钥的第一个字节以创建 24 位 Java 密钥。
  • C# 使用 CBC 和 PKCS7。块大小为 8。
  • Java 正在使用 CBC 和 PKCS5(为此目的应该与 7 相同)。

这是 C# 中的加密方面

byKey = Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
byte[] inputByteArray = Encoding.UTF8.GetBytes(val);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());

并在Java中解密

byte[] inputByteArray = Base64.decode(val);
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(byKey, "DESede"), new IvParameterSpec(iv, 0, 8));

byte[] decryptedBytes;
for (int i = 0, j = 0; i < inputByteArray.length; i++) {
    if ((decryptedBytes = c.update(inputByteArray, i, 1)) == null)
        continue;
    else {
        System.out.println(new String(decryptedBytes));
        j += decryptedBytes.length;
    }          
}

我期待看到系统上的明文块。我知道 .update() 循环可以替换为 .doFinal() 但我想逐块查看它。

我对Java不是很熟悉,所以我特别感谢那里的任何建议。

编辑 我不相信文本编码是问题所在。这是表现出相同问题的原始代码,只是没有显示它的逐块性质:

byte[] decrypted = c.doFinal(inputByteArray);
return new String(decrypted, "UTF-8");
4

3 回答 3

0

Java 通常与 C# 有不同的默认值,因此您不应在任何地方依赖默认值,尤其是在字节和字符串之间进行转换时。除了 @jtahlborn 关于在任意点破坏 UTF-8 字符串的评论外,您还需要在 Java 代码中指定 UTF-8,就像在 C# 代码中所做的那样:

System.out.println(new String(decryptedBytes, "UTF-8"));

您可能想尝试检查实际字节,而不是检查字符。这应该让您更好地处理任何可能的不匹配发生的位置。

于 2013-08-28T12:17:25.960 回答
0

事实证明它毕竟不是加密。

问题出在 BASE64 编码上,事实上它是通过一个 cookie 传播的,它把 + 变成了一个空格(所以感谢 rossum 的逐字节建议)。

于 2013-08-29T04:54:56.280 回答
0

您不能获取任意 utf-8 字节块并将它们转换为字符串(另外,您没有指定字符集)。您需要将所有字节放在一起并将它们转换为字符串,指定"UTF-8"字符集。

于 2013-08-28T01:48:45.620 回答