【问题标题】:How do I translate this C# encrypt function into Java?如何将此 C# 加密函数转换为 Java?
【发布时间】:2012-07-26 17:32:18
【问题描述】:

我需要将以下 C# 代码翻译成 Java,但是,我找不到任何与 C# 的 Rfc2898DerivedBytes 和 Rijndael 等效的 Java。

    private static string Encrypt(string sData, string sEncryptionKey)
{
    string str = null;
    string str2;
    try
    {
        Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(sEncryptionKey, 8);
        Rijndael rijndael = Rijndael.Create();
        rijndael.IV = bytes.GetBytes(rijndael.BlockSize / 8);
        rijndael.Key = bytes.GetBytes(rijndael.KeySize / 8);
        byte[] buffer = Encoding.Unicode.GetBytes(sData);
        using (MemoryStream stream = new MemoryStream())
        {
            using (CryptoStream stream2 = new CryptoStream(stream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
            {
                stream.Write(bytes.Salt, 0, bytes.Salt.Length);
                stream2.Write(buffer, 0, buffer.Length);
                stream2.Close();
                str = Convert.ToBase64String(stream.ToArray());
                str2 = str;
            }
        }
    }
    catch (Exception exception)
    {
       System.out.println(exception.getMessage());
    }
    return str2;

}

[更新]

我需要使用这个函数对新创建的用户的密码进行加密,加密后的密码也应该被包括C#在内的其他调用者正确解密。

我按照cmets中列出的文档和答案,并尝试在下面写简单的示例以便快速验证。

public class testEncrypt {
public static void main(String[] args) throws Exception {

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

    char[] password = "passkey".toCharArray();

    SecureRandom random = new SecureRandom();
    byte[] salt = new byte[8];
    random.nextBytes(salt);

    KeySpec spec = new PBEKeySpec(password, salt, 1000, 256); 
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
    byte[] ciphertext = cipher.doFinal("301a7fed-54e4-4ae2-9b4d-6db057f75c91".getBytes("UTF-8"));

    System.out.println(ciphertext.length);

}

}

但是,密文的长度是48,但实际上在C#中,看起来是这样的格式

WHUNV5xrsfETEiCwcT0M731+Ak1jibsWEodJSaBraP1cmmkS1TpGWqwt/6p/a7oy8Yq30ImZPbFF+Y0JNLa3Eu2UGuazZtuhEepUIIdaDEtA2FO0JYIj2A==

总共 120 个字符。

代码有问题吗?

【问题讨论】:

标签: java encryption rijndael cryptostream rfc2898


【解决方案1】:

RFC2898 是 PBKDF2(Password Based Key Derivation Function)的正式名称。

这个问题似乎使用了 PBKDF2 的SecretKeyFactory 类。

Password Verification with PBKDF2 in Java

如果您找不到任何满意的实现,我建议您查看my question,我在其中使用了一些来自 BouncyCastle 的类(适用于 C#,但应该适用于 Java)并创建了算法。我不得不为 C# 创建它,因为 .NET Compact Framework 没有 Rfc2898DeriveBytes

This question 一定也能帮到你!

您还可以找到由偶然发现相同问题的人完成的实现 here

也回答你问题的第二部分,

Rijndael 与 AES 没有太大区别。引用此webpage

也就是说,Rijndael 允许选择密钥和块大小 独立于 { 128, 160, 192, 224, 256 } 位的集合。 (和 密钥大小实际上不必与块大小匹配)。然而, FIPS-197 指定块大小在 AES 中必须始终为 128 位, 并且密钥大小可以是 128、192 或 256 位。

Rijndael 算法被 NIST 选为高级加密算法。

所以你可以使用AES algorithm in Java

【讨论】:

  • 感谢您的回答,但即使我知道加密算法是 rijndael/AES 以及如何使用 Java 使用 AES 加密数据,我仍然不知道如何翻译原始 C# 代码,尤其是 rijndael 声明部分。目前,我已经完成了用 Java 翻译 Rfc2898DeriveBytes。你能告诉我更多关于如何翻译剩余部分的信息吗?谢谢
  • 您将无法将代码逐行转换为 Java,主要是因为 Java 中没有 CryptoStream 类。也看看这个question
  • 感谢您的回复。我已经用 Java 重写了整个 Rfc2898DeriveBytes 类,并使用了 java 的构建 AES 加密方法,但是它仍然不适合我。例如,IV 的长度在 Java 中被限制为 16。您能否为 150 名声提供一些工作代码示例。:)
  • 如果这听起来很粗鲁,我很抱歉,但如果您对它没有全面的了解,请不要尝试构建加密系统。如果您正在处理敏感的客户信息,请花很多精力和时间学习什么是密码算法,什么是 IV,块大小是多少,为什么使用 PBKDF2 等。无论如何,首先测试是否Rfc2898DeriveBytes工作正常。此外,如果 Java 中的 IV 限制为 16,则必须使用 128 位的块大小。使用您提出的当前代码以及您面临的任何问题更新您的答案。
  • 要添加到上面的评论中,更好的是,如果您负担得起,请不要构建自己的加密系统。使用已经在构建、尝试和测试的东西。不管你学得多么努力,只要有一个微妙的错误就可以打破它。另一方面,业界正在使用 MS Enterprise Library、ASP .NET Membership、Apache Shiro 或 Spring Security 等系统,并报告并修复了它们的错误。
猜你喜欢
  • 2011-10-09
  • 2012-02-19
  • 2015-09-23
  • 1970-01-01
  • 2021-11-03
  • 2012-09-23
  • 1970-01-01
  • 1970-01-01
  • 2021-12-12
相关资源
最近更新 更多