当前位置: 首页 > 知识库问答 >
问题:

如何进行多次散列并在每一轮中串联一个字符串

申屠裕
2023-03-14

我正在编写一个程序,在密码的末尾连接一个单词r,然后计算SHA-256散列。稍后,在十六进制结果的末尾再次添加r字,并使用sha256计算新的哈希。

我要把这个重复100遍。每次我想打印散列。

在伪代码中如下所示:

hash = SHA256(...(SHA256(SHA256(“password”||R)||R)||R)..)

我目前正在通过哈希两次来测试我的代码:

   String R = "f@ghj!$g";
   hash = password.concat(R);

   MessageDigest md = MessageDigest.getInstance("SHA-256");
   digest = hash.getBytes(StandardCharsets.UTF_8);

   for (int i=0;i<2;i++) {

     md.update(digest);
     digest = md.digest();

     hash = String.format("%064x", new BigInteger(1,digest)).concat(R);
     System.out.println(hash);

     digest = hash.getBytes(StandardCharsets.UTF_8);
   }

让我们暂时忘记这个连接。

例如无法理解为什么下面两个代码会产生不同的结果:

代码1:

   for (int i=0;i<2;i++) {

     md.update(digest);
     digest = md.digest();

   }

 hash = String.format("%064x", new BigInteger(1,digest));   
 System.out.println(hash);

代码二:

   for (int i=0;i<2;i++) {

     md.update(digest);
     digest = md.digest();
     //convert hash to string
     hash = String.format("%064x", new BigInteger(1,digest));
     //convert string again to bytes
     digest = hash.getBytes(StandardCharsets.UTF_8);
   }

 System.out.println(hash);

我的问题是:每次将r字级联并以正确的方式再次编码成字节时,哪种方法是将散列(byte[])解码成十六进制字符串的正确方法?

共有1个答案

丁学
2023-03-14

代码片段1是正确的,但是您需要将print语句添加到其中以获得您预期的输出。但是,为此,您需要使用真正的十六进制编码器/解码器,这是没有帮助的,java.util默认情况下不提供它。

这里是一个经过修改的示例,没有连接,我故意省略了它,让您有事情要做。

代码使用了一个相对较慢但易于记忆和阅读的toHex函数。BigInteger首先需要构造一个BigInteger,这样做很浪费,而且可能更慢。虽然对于32字节的散列值,代码似乎可以正常工作,但我仍然认为代码很难维护。

public static byte[] printHexadecimalHashIterations(byte[] input, int iterations)
{
    var digest = input.clone();

    MessageDigest md;
    try
    {
        md = MessageDigest.getInstance("SHA-256");
    }
    catch (NoSuchAlgorithmException e)
    {
        throw new IllegalStateException("SHA-256 hash should be available", e);
    }

    for (int i = 0; i < iterations; i++)
    {
        md.update(digest);
        digest = md.digest();

        printDigest("Intermediate hash", digest);
    }

    printDigest("Final hash", digest);

    return digest;
}

public static void printDigest(String hashType, byte[] digest)
{
    var digestInHex = toHex(digest);
    System.out.printf("%s: %s%n", hashType, digestInHex);
}

public static String toHex(byte[] data)
{
    var sb = new StringBuilder(data.length * 2);
    for (int i = 0; i < data.length; i++)
    {
        sb.append(String.format("%02X", data[i]));
    }
    return sb.toString();
}

public static void main(String[] args)
{
    printHexadecimalHashIterations("password".getBytes(StandardCharsets.UTF_8), 2);
}

主要的一点是,(安全的)散列函数的数据由字节组成(如果您更喜欢这个名称,也可以使用八位字节)。十六进制字符串只是这些字节的文本表示。它与数据本身并不相同。

您应该能够区分二进制数据和十六进制,十六进制只是二进制数据的表示。不要像问题中那样把二进制数据称为“十六进制”:这是一个危险信号,你没有得到区别。

然而,在您的情况下,您只需要十六进制将它们打印到屏幕上;您根本不需要将digest字节数组转换为十六进制;它仍然可用。所以你可以继续做下去。

如果需要将文本表示转换回字节,则需要执行十六进制解码。显然,您将再次需要一个不涉及biginteger的好html" target="_blank">方法。有很多库(Guava,Apache Commons,Bouncy Castle)提供了很好的十六进制编码器/解码器,并在SO上提供了关于这方面的问题/答案。代码片段2中的hash.getBytes(StandardCharSets.utf_8)语句不执行十六进制解码,它执行字符编码。

最后一个提示是:update方法允许将数据流传输到digest函数中。这意味着您实际上不必连接任何内容来通过连接计算摘要:您只需对update执行多个调用即可。

编程快乐。

编辑:

为了执行您的任务,我会做如下操作:

final byte[] passwordBytes = "password".getBytes(StandardCharsets.UTF_8);
final byte[] rBytes = "f@ghj!$g".getBytes(StandardCharsets.UTF_8);

digest.update(passwordBytes);
digest.update(rBytes);
byte[] currentHash = digest.digest();

for (int i = 1; i < iterations; i++)
{
    digest.update(currentHash);
    digest.update(rBytes);
    currentHash = digest.digest();
}
 类似资料:
  • 我有一个Laravel 5.8项目,我需要加入3个表来显示一些结果。 基本上,我已经将所有自定义id存储在一个名为的表中。 例如,这里有两个自定义ID,我需要检索它们的: 所以我试了一下: 但这是错误的,并向我展示了错误: SQLSTATE[42000]:语法错误或访问冲突:1066不唯一 所以我需要这样说: 然后: 我该怎么做呢?

  • 问题内容: 我已经开始使用LPTHW学习Python,并且开始练习16: http://learnpythonthehardway.org/book/ex16.html 并且觉得自己是个白痴,因为我无法弄清楚看似简单的“额外功劳”分配之一,但需要以下条件: 压缩为一行代码。我尝试了以下一些方法: 要么: 要么: 我只是无法让它在同一行中重写line1,line2和line3字符串。而且,我尝试了各

  • 问题内容: 如何在Java中使用sha256对某些字符串进行哈希处理?有人知道有免费的图书馆吗? 问题答案: SHA-256不是“编码”,而是单向哈希。 你基本上可以将字符串转换为字节(例如使用),然后对字节进行哈希处理。请注意,哈希的结果也将是任意二进制数据,并且如果要在字符串中表示它,则应使用base64或hex … 不要尝试使用构造函数。 例如

  • 问题内容: 我是Java的新手,为了实践起见,我试图创建一个十六进制到十进制的数字转换器,因为我已经成功地制作了一个二进制到十进制的转换器。 我遇到的问题基本上是将一个字符串中的给定字符与另一个字符串进行比较。这就是我定义要比较的当前字符的方式: 这是我尝试比较角色的方法: 当我尝试通过仅输入数字(例如12)来运行代码时,它可以工作,但是当我尝试使用“ b”时,会出现一个奇怪的错误。这是运行程序的

  • 我有一个字符串原型,其代码如下所示: 用法:

  • 问题内容: 在JavaScript中有一个简单的等效项吗? 这是使用PHP的,它允许您使用单词数组来查找和替换。我可以使用JavaScript / jQuery做类似的事情吗? 问题答案: 您可以使用自己的函数来扩展String对象,该函数可以满足您的需要(如果缺少功能,则很有用): 对于全局替换,您可以使用正则表达式: 要使用该功能,它将类似于您的PHP示例: