【问题标题】:Decrypting bytes encrypted by .NET's RijndaelManaged using Java使用 Java 解密由 .NET 的 RijndaelManaged 加密的字节
【发布时间】:2011-08-30 09:45:15
【问题描述】:

我正在尝试解密使用 .NET/C# 的 RijndaelManaged 加密的内容,使用 Java 进行解密。

C# 程序不是我的;我无法将其更改为更具互操作性。但我知道它是如何加密的:

byte[] bytes = new UnicodeEncoding().GetBytes(password); // edit: built-in is 8chars
FileStream fileStream = new FileStream(outputFile, FileMode.Create);
RijndaelManaged rijndaelManaged = new RijndaelManaged();
CryptoStream cryptoStream = new CryptoStream((Stream) fileStream,
    rijndaelManaged.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write);

我不知道如何在 Java 端解密。我发现最接近有用的是this blog post,但它对实际细节的了解很浅,我无法实现解密器。

编辑:我是个白痴,现在可以正常工作了。

UnicodeEncoding 是 UTF-16LE,而我使用的是 UTF-8。插入密码时切换到正确的编码已修复程序。

我还需要获得 BouncyCastle 并做 Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");

finaledit:下面是用 Java 从 .NET 解密 default RijndaelManaged 流的代码,假设它是使用原始密码作为密钥创建的:

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
String password = "kallisti"; // only 8, 12, or 16 chars will work as a key
byte[] key = password.getBytes(Charset.forName("UTF-16LE"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
    new IvParameterSpec(key));
return cipher; // then use CipherInputStream(InputStream, Cipher)

请记住:如果您控制 C# 端,请不要使用未派生的密码作为您的密钥!

【问题讨论】:

  • 不请自来的建议:不要使用new UnicodeEncoding().GetBytes(password); 来获取密码字节。有关原因,请参阅 en.wikipedia.org/wiki/PBKDF2tools.ietf.org/html/rfc2898 尤其是第 3 节。幸运的是,.NET 和 Java 都有符合 RFC2898(又名 PKCS5,又名 PBKDF2)的密钥派生类。您的应用应该使用它们。
  • 另请参阅stackoverflow.com/questions/2375541/…,了解有关 Java 中 PKBDF2 的问题。
  • @Cheeso:C# 应用程序不是我的;我知道使用原始密码作为密钥是一个糟糕的主意。它也没有加密任何真正需要加密的东西,只是应用程序编写者不希望其他应用程序能够读取的二进制 blob。

标签: c# java .net aes rijndaelmanaged


【解决方案1】:

可以使用标准的 AES 解密。 Rijndel 只是 AES 的超集,它对特定选项更加宽松。详情请见Rijndael support in Java

来自链接问题中给出的答案:

byte[] sessionKey = null; //Where you get this from is beyond the scope of this post
byte[] iv = null ; //Ditto
byte[] plaintext = null; //Whatever you want to encrypt/decrypt
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//You can use ENCRYPT_MODE or DECRYPT_MODE
cipher.calling init(Cipher.DECRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
byte[] ciphertext = cipher.doFinal(plaintext);

【讨论】:

  • 你有一点点倒退 - AES 是 Rijndael 的一个子集,特别是在块大小方面。 AES 将严格使用 128 的块大小(参考 FIPS 197),而 Rijndael 会给您一些灵活性。
  • 感谢您的建议 :) 已编辑答案。只是有点糊涂了。
  • "java.security.InvalidKeyException: Invalid AES key length: 8 bytes" "java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long" 我试过这段代码,但它没有工作。我正在使用与 C# 端正在执行的操作相同的密码。 C#端使用原始明文密码插入密码;上面的代码似乎期望接收从密码派生的字节数组。
  • 看看这是否更好:cs.ucdavis.edu/~rogaway/ocb/ocb-java/Rijndael.java。看起来 AES 支持需要特定的密钥长度(128、192、256 等)。因此,您必须在任一端制作与 AES 兼容的密钥。
  • 我知道我必须制作与 AES 兼容的密钥。但我需要以与 C# 程序正在执行的操作相同的方式执行此操作。 C# 程序只是为 RijndaeManaged 提供了一个 8 字节的密码,然后显然会自动将其导出为正确的密钥。我不知道如何在 Java 中做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-08
  • 2017-06-16
相关资源
最近更新 更多