C# SHA-256和Java SHA-256,结果不同?

4

我希望将一些Java代码转换为C#。

Java代码:

  private static final byte[] SALT = "NJui8*&N823bVvy03^4N".getBytes();

  public static final String getSHA256Hash(String secret)
  {
    try {
      MessageDigest digest = MessageDigest.getInstance("SHA-256");
      digest.update(secret.getBytes());
      byte[] hash = digest.digest(SALT);
      StringBuffer hexString = new StringBuffer();
      for (int i = 0; i < hash.length; i++) {
        hexString.append(Integer.toHexString(0xFF & hash[i]));
      }
      return hexString.toString();
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } 
    throw new RuntimeException("SHA-256 realization algorithm not found in JDK!");
  }

当我尝试使用SimpleHash类时,我得到了不同的哈希值。

更新:

例如:

Java:byte[] hash = digest.digest(SALT); 生成的哈希值(前6个字节)为:

[0] = 9
[1] = -95
[2] = -68
[3] = 64
[4] = -11
[5] = 53
....

C#代码(SimpleHash类): string hashValue = Convert.ToBase64String(hashWithSaltBytes); hashWithSaltBytes的前6个字节为:

[0] 175 byte
[1] 209 byte
[2] 120 byte
[3] 74  byte
[4] 74  byte
[5] 227 byte

3
为什么使用“SHA-256”,但方法的名称为“getMd5Hash”? - dtb
我不确定。可能过去使用的是这种方法生成MD5。我们只是将项目从Java转换成C#。 - Ilyas I
您如何解决了这个问题?能否请在此更新修复方法,我也遇到了同样的问题。 - VinothKumar Subramani
5个回答

7
String.getBytes()方法使用平台的默认字符集编码字符串为字节,而你提供的示例代码使用的是UTF-8。请尝试以下操作:
digest.update(secret.getBytes("UTF-8"));

其次,Integer.toHexString方法返回十六进制结果,但没有前导0。

2
hexString.append(Integer.toHexString(0xFF & hash[i]));
您正在错误地构建哈希字符串。Integer.toHexString不包括前导零,因此Integer.toHexString(0xFF) == "FF",但问题在于Integer.toHexString(0x05) == "5"
建议更正:String.format("%02x", hash[i] & 0xFF)

2
public static String getEncryptedPassword(String clearTextPassword) throws NoSuchAlgorithmException{

    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update(clearTextPassword.getBytes(StandardCharsets.UTF_8));
    byte[] digest = md.digest();
    String hex = String.format("%064x", new BigInteger(1, digest));
    String st = new String(hex.toUpperCase());
    for (int i = 2; i < (hex.length() + hex.length() / 2) - 1 ;) {
        st = new StringBuffer(st).insert(i, "-").toString();
            i = i + 3;        
    }
    return st ; 

}

您可以使用以下Java代码来匹配C#:

您可以使用以下Java代码来匹配C#


2

您提供的C#代码也使用了盐 - 但Java代码没有。如果您在一个中使用了盐,而另一个中没有使用,则结果将是(并且应该是!)不同的。


代码包括 byte[] hash = digest.digest(SALT);。这不使用盐吗? - dtb

0

你并没有详细说明如何调用SimpleHash类 - 使用哪些参数等。

但请注意,它的ComputeHash方法在文档中有:

哈希值格式化为base64编码的字符串。

而你的类将输出格式化为十六进制,这显然会不同。

此外,SimpleHash中的盐被解释为base64,而你的方法将其解释为ASCII(或者你的系统编码是什么 - 很可能是一些ASCII兼容的东西,并且该字符串只包含ASCII字符)。

另外,SimpleHash中的输出包括盐(以便在使用随机盐时重现“验证”部分),而你的方法则不包括。

(其他答案已经提到了更多要点。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接