【问题标题】:Standard way to create a hash in Java在 Java 中创建哈希的标准方法
【发布时间】:2021-08-25 00:50:17
【问题描述】:

问题是关于在 Java 中创建哈希的正确方法: 假设我有一个正的 BigInteger 值,我想从中创建一个哈希值。让我们假设messageDigest 的下面实例是(SHA-256) 的有效实例

public static final BigInteger B = new BigInteger("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58", 16);

   byte[] byteArrayBBigInt = B.toByteArray();
   this.printArray(byteArrayBBigInt);
   messageDigest.reset();
   messageDigest.update(byteArrayBBigInt);
   byte[] outputBBigInt = messageDigest.digest();

现在我只假设下面的代码是正确的,因为根据测试,我生成的哈希值与以下代码相匹配:

http://www.fileformat.info/tool/hash.htm?hex=BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58

但是我不确定我们为什么要执行以下步骤,即 因为在 digest() 调用之后返回的字节数组是有符号的,在这种情况下它是负数,我怀疑我们确实需要将它转换为正数,即我们可以使用这样的函数。

public static String byteArrayToHexString(byte[] b) {
    String result = "";
    for (int i=0; i < b.length; i++) {
      result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
    }
    return result;
}

因此:

String hex = byteArrayToHexString(outputBBigInt)
BigInteger unsignedBigInteger = new BigInteger(hex, 16);

当我从新的十六进制字符串构造 BigInteger 并将其转换回字节数组时,我看到符号位,即最高有效位,即最左边的位,设置为 0,这意味着数字是正的,而且整个字节由零构成( 00000000 )。

我的问题是:是否有任何 RFC 描述了为什么我们需要始终将哈希转换为“正”无符号字节数组。我的意思是即使摘要调用后产生的数字是负数,它仍然是有效的哈希,对吗?因此,我们为什么需要那个额外的程序。基本上,我正在寻找一篇论文:描述我们需要这样做的标准或 rfc。

【问题讨论】:

  • 我的 2 美分: 1. 这很可能是因为通过简单地执行 hashCode % bucketSize; 可以更容易地找到这样一个 hashCode 的哈希桶。但我不是这方面的专家。 2. 你的代码风格不好,因为 hashCode() 的时间复杂度随着输入字符串的长度而增长,并且是 O(n) 实现。相信我,我们曾经在这样的实施上遇到过严重的问题。您可能希望将其更改为整个字符串的一部分的某些特征固定大小的数组。
  • 你会如何改变它。大整数不是固定长度,字节数组长度也不是固定的。我能想象的一件事是验证 BigInteger 长度不大于某个 Max 长度。但除此之外,你有一个你提议的例子吗?
  • 你的问题不是关于散列,而是关于将大整数转换为字节数组。
  • 好吧,我不会那样说,因为 toByteArray() 方法将大整数转换为字节数组,但是为了获得相同的结果,即与 fileformat.info 中所示的哈希相同,然后我需要对该字节数组应用一些额外的逻辑。您可以称其为关于散列或将大整数转换为字节数组,最后问题非常精确,即为什么我们需要额外的最后一步,即在我的情况下是方法 byteArrayToHexString 并且是否有标准/RFI 我可以阅读更多关于它。
  • @Tito 通常您会选择整个字符串中最具代表性的部分(取决于您的业务场景)。例如,如果您知道前 24 个字符是关键,为什么不直接使用它呢?或者,您为字节长度设置一个上限,例如 128,然后截断任何内容。

标签: java hash cryptography sha256


【解决方案1】:

散列由一个八位组字符串(在 Java 中称为字节数组)组成。如何将它转换为大数(Java 中的 BigInteger)完全超出了加密哈希算法的范围。所以不,没有 RFC 来描述它,因为(通常)没有理由将哈希视为数字。从这个意义上说,加密哈希与Object.hashCode() 完全不同。

您只能将十六进制视为无符号是一个问题,但如果您真的想要那么您可以先将其转换回字节数组,然后执行new BigInteger(result)。该构造函数确实威胁到结果中的编码已签名。请注意,在协议中通常不需要来回转换为十六进制;十六进制主要供人类使用,计算机可以处理字节。

【讨论】:

  • ECDSA 是其中哈希实际上直接用作数字的算法之一,但是这个数字的行为方式是算法特有的,而不是相反(尽管大多数密码学家更喜欢无符号大端符号)。
猜你喜欢
  • 2016-10-06
  • 1970-01-01
  • 2015-03-01
  • 2021-06-23
  • 1970-01-01
  • 2013-07-28
  • 2021-10-11
相关资源
最近更新 更多