【问题标题】:port sha-1 hash from C# to Android/java将 sha-1 哈希从 C# 移植到 Android/java
【发布时间】:2023-05-16 00:01:01
【问题描述】:

我需要从 C# 移植以下代码

    private string hashcode(string code)
    {
        byte[] bytes = Encoding.Unicode.GetBytes(code);
        byte[] inArray = HashAlgorithm.Create("SHA1").ComputeHash(bytes);
        return Convert.ToBase64String(inArray);
    }

到 Android 应用程序。我在 Java 中有这个:

private static String hashCode(String userCode) {
    String hashSha1;
    MessageDigest digest = null;
    try {
        digest = MessageDigest.getInstance("SHA-1");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    digest.reset();
    byte[] data = digest.digest(userCode.getBytes());
    return Base64.encodeToString(data, Base64.DEFAULT);
}

唉,这段代码不会产生相同的结果。找出原因是一场非常疯狂的追逐。

我可以在 Android 中做什么来获得相同的哈希值?

【问题讨论】:

  • 为什么需要再次生成哈希?
  • 嗯?如果您不想希望能够再次生成哈希,那么哈希的意义何在?
  • 我只需要移植这段代码。代码生成哈希。

标签: java c# android sha1


【解决方案1】:

这是您将 userCode 字符串转换为字节的 C# 代码:

byte[] bytes = Encoding.Unicode.GetBytes(code);

而Java代码就是:

userCode.getBytes()

这意味着在 Java 中您使用的是平台默认编码,在 Android 上是 UTF-8。您应该指定与Encoding.Unicode 等效的编码,即StandardCharsets.UTF_16LE

你应该永远调用String(byte[])String.getBytes(),它们都使用平台默认编码。 总是指定要使用的编码。

在更笼统的一点上,您说“找出为什么是一场非常疯狂的追逐” - 但在这种情况下,解决方案几乎是总是详细记录一次转变。你在这里有三个转换:

  • Stringbyte[](将 userCode 编码为二进制数据)
  • MD5 散列(byte[]byte[]
  • 将哈希编码为 base64

如果您分别采取了这些步骤并记录了结果,您就会发现问题出在第一步。

【讨论】:

    【解决方案2】:

    Android 将 UTF-8 作为默认字符集。尝试使用StandardCharsets.UTF_16LE 代替String.getBytes(Charset charset)

    【讨论】:

    • 最好指定UTF_16LE 明确字节序。