首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将C#密码学转换为Java

将C#密码学转换为Java
EN

Stack Overflow用户
提问于 2015-07-14 17:18:13
回答 1查看 380关注 0票数 4

我的任务是将C#加密方法转换为Java,现在我被困住了。我知道C#代码可以工作,但是我很难让我的Java代码工作。

以下是C#代码:

代码语言:javascript
运行
复制
private const int Nb = 4; // Legal values:  4 = 128-bit blocks

public static void Decrypt(byte[] input, Stream output)
    { 
        var s1 = new MemoryStream(input);
        const int BufferSize = 1024;
        byte[] buffer = new byte[BufferSize];

        input.Read(buffer, 0, 4);
        int pad = buffer[3];

        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.BlockSize = Nb * 32;
        rijndael.KeySize = buffer[1] * 32;

        rijndael.Mode = CipherMode.ECB;
        rijndael.Padding = PaddingMode.None;

        byte[] key = GetKey(buffer[1]);
        ICryptoTransform decryptor = rijndael.CreateDecryptor(key, GetIV());

        int bytes;
        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);
        }
        output.SetLength(output.Length - pad - 4);
    }

到目前为止,我在Java方面的尝试如下:

代码语言:javascript
运行
复制
public static String decrypt(byte[] input) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
    byte[] key = getKey(input[1]);
    SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES/ECB/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(getIV()));
    // remove first 4 since C# code reads past those
    byte[] finalDecoded = Arrays.copyOfRange(input, 4, input.length);
    byte[] decryptedVal = cipher.doFinal(finalDecoded);
    return new String(decryptedVal);
}

更多的信息

  • 对于GetIVGetKey,我可以保证java中的结果是相同的(我比较了每个字节),但是我没有包括这些方法,因为我相信这些是敏感的信息。我还可以保证输入的byte[]是相同的和(冗余的)相同的长度。
  • 调试尝试:当前的错误是ECB mode cannot use IV
代码语言:javascript
运行
复制
- When I remove this code : `new IvParameterSpec(getIV())` I get this error: `Wrong algorithm: AES or Rijndael required`
- If I change the algorithm to only `AES` or only `Rijndael` I get this error: `Input length must be multiple of 16 when decrypting with padded cipher`. The input length starting is `424` and `420` after reading past/removing the first 4 bytes. I have verified that the input bytes are the same for Java and C#.

我在Java代码中做错了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-07-14 18:26:00

您将得到错误的ECB mode cannot use IV,因为欧洲央行不执行链接,所以IV没有意义。不同之处在于,Java抛出了一个错误,而C#只是忽略了IV。

当我删除这个代码:new IvParameterSpec(getIV())时,我得到了这个错误:new IvParameterSpec(getIV()) 如果我只将算法更改为AES或只有Rijndael,则会得到以下错误:Input length must be multiple of 16 when decrypting with Input length must be multiple of 16 when decrypting with

你的想法是对的,但你做得太过分了。这个错误只与SecretKeySpec有关,它不关心模式,而只关心算法。Cipher是您指定模式的地方。而且,Rijndael和AES也不是完全一样的。

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

代码语言:javascript
运行
复制
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);

请注意,由于您使用的是整个key,所以不需要偏移量和长度参数,所以您可以这样做

代码语言:javascript
运行
复制
SecretKey secretKey = new SecretKeySpec(key, "Rijndael");

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

代码语言:javascript
运行
复制
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);
}

当循环到达input的末尾时,它会将它的多少复制到buffer中。除非上一次Read正好是1024字节,否则在输入结束后会有来自前一个循环的残留(或者如果它通过一个Read操作获得整个input )。

内环一次解密一个16字节的块.在420个字节的示例中,最后一个块将包含其余4个字节的输入和12个字节的垃圾。但是,这是可以的,因为output.Write只写入bytes字节数来截断垃圾。您必须在Java代码中复制此行为。

旁注:你一定要使用欧洲央行吗?不是很安全..。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31413244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档