将C#加密转换为Java

将C#加密转换为Java,java,c#,encryption,aes,rijndael,Java,C#,Encryption,Aes,Rijndael,我的任务是将一种C#加密方法转换成Java,我被卡住了。我知道C#代码可以工作,但我在让Java代码工作时遇到了麻烦 以下是C#代码: 更多信息 对于GetIV和GetKey,我可以保证java中的结果是相同的(我已经比较了每个字节),但我不包括这些方法,因为我认为这是敏感信息。我还可以保证输入字节[]相同且(冗余地)长度相同 调试尝试:Java中的当前错误是ECB模式无法使用IV 当我删除此代码时:new-IvParameterSpec(getIV())我得到此错误:错误的算法:需要AES

我的任务是将一种C#加密方法转换成Java,我被卡住了。我知道C#代码可以工作,但我在让Java代码工作时遇到了麻烦

以下是C#代码:

更多信息

  • 对于
    GetIV
    GetKey
    ,我可以保证java中的结果是相同的(我已经比较了每个字节),但我不包括这些方法,因为我认为这是敏感信息。我还可以保证输入字节[]相同且(冗余地)长度相同

  • 调试尝试:Java中的当前错误是
    ECB模式无法使用IV

    • 当我删除此代码时:
      new-IvParameterSpec(getIV())
      我得到此错误:
      错误的算法:需要AES或Rijndael
    • 如果我将算法更改为仅
      AES
      或仅
      Rijndael
      我会得到以下错误:
      使用填充密码解密时,输入长度必须是16的倍数。读取/删除前4个字节后,输入长度开始为
      424
      420
      。我已经验证了Java和C的输入字节是相同的

Java代码中的错误在哪里?

您得到了错误
ECB模式不能使用IV
,因为ECB不执行链接,所以IV没有意义。区别在于Java抛出了一个错误,而C#只是忽略了IV

当我删除此代码时:
新的IvParameterSpec(getIV())
我得到此错误:
错误的算法:
AES或Rijndael
必需

如果将算法更改为仅AES或仅Rijndael,则会出现以下错误:
使用填充密码解密时,输入长度必须是16的倍数。

你的想法是对的,但你做得太过分了。此错误仅与
SecretKeySpec
有关,它不关心模式,只关心算法<代码>密码
是指定模式的地方。此外,Rijndael和AES也不是一回事

因此,首先将前几行更改为:

Cipher cipher = Cipher.getInstance("Rijndael/ECB/NoPadding");
byte[] key = getKey(input[1]);
SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "Rijndael");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
请注意,由于您使用的是整个
,因此不需要offset和length参数,因此只需执行以下操作即可

SecretKey secretKey = new SecretKeySpec(key, "Rijndael");

原始C#代码有一些不太明显的行为:

while ((bytes = input.Read(buffer, 0, BufferSize)) > 0)
{
    for (int i = 0; i < bytes; i += rijndael.BlockSize)
    {
        decryptor.TransformBlock(buffer, i, rijndael.BlockSize, buffer, i);
    }
    output.Write(buffer, 0, bytes);
}
while((字节=input.Read(buffer,0,BufferSize))>0)
{
for(int i=0;i
当循环到达
输入
的末尾时,它将把剩余的部分复制到
缓冲区
。除非最后一次
读取
正好是1024字节,否则在输入结束后,上一个循环(如果它通过一次
读取
操作获得整个
输入
,则来自初始化)将有剩余

内部循环一次解密一个16字节的块。在420字节的示例中,最后一个块将由剩余的4个字节的输入和另外12个字节的垃圾组成。但这没关系,因为
output.Write
只写入
字节数
以截断垃圾。您必须在Java代码中复制这种行为



旁注:你一定要使用ECB吗?不太安全…

非常感谢。当我应用您的更改时,出现以下错误:
输入长度不是16字节的倍数
。这与我遇到的另一个错误类似,只是它没有说明任何关于填充的内容。我尝试删除输入数组的最后4个字节(以及前4个字节),因为最后4个字节是填充的,以使长度为16的倍数,这非常有效,解密后的字符串末尾只有一些奇怪的字符……我忘了提一下,你也不会像原来的C#那样截断最终结果(
output.SetLength(output.Length-pad-4);
),这也会影响你的结果。是的,我认为不太明显的行为是最后一个部分。一旦我把它转换成Java,它就工作了!再次感谢!!
SecretKey secretKey = new SecretKeySpec(key, "Rijndael");
while ((bytes = input.Read(buffer, 0, BufferSize)) > 0)
{
    for (int i = 0; i < bytes; i += rijndael.BlockSize)
    {
        decryptor.TransformBlock(buffer, i, rijndael.BlockSize, buffer, i);
    }
    output.Write(buffer, 0, bytes);
}