Crystal: 如何找到二进制值的 SHA256 哈希值?

Crystal: How can I find the SHA256 hash of a binary value?

我是 Crystal 的新手。我想尝试找到十六进制字符串的 SHA256 散列。我已经设法让一些东西工作:

sha256 = OpenSSL::Digest.new("sha256")
puts sha256.update("abcd")

但我不确定如何将 "abcd" 的二进制值放入散列函数,或将二进制输出。我基本上希望能够重新创建此 Ruby 函数:

def hash256(hex)
  # 1. Convert hex string to array, and pack in to binary
  binary = [hex].pack("H*")

  # 2. Hash the binary value (returns binary)
  hash1 = Digest::SHA256.digest(binary)

  # 3. Hash it again (returns binary)
  hash2 = Digest::SHA256.digest(hash1)

  # 4. Convert back to hex (must unpack as array)
  result = hash2.unpack("H*")[0]

  return result
end

是否可以在 Crystal 中对二进制值使用 SHA256?

将一串十六进制字符解码为二进制切片目前不是crystal标准库的一部分,所以我自己写了一个解码函数:

def hex_decode(hex)
  return unless hex.size % 2 == 0

  slice = Slice(UInt8).new(hex.size / 2)
  0.step(to: hex.size - 1, by: 2) do |i|
    high_nibble = hex.to_unsafe[i].unsafe_chr.to_u8?(16)
    low_nibble = hex.to_unsafe[i + 1].unsafe_chr.to_u8?(16)
    return unless high_nibble && low_nibble

    slice[i / 2] = (high_nibble << 4) | low_nibble
  end

  slice
end

此函数接受包含十六进制字符的 String,然后将其解码为 Slice(UInt8)(如果十六进制无效,则为 returns nil)。

那么与上面粘贴的 ruby 代码等效的完整代码将是:

def hash256(hex_string)
  data = hex_decode(hex_string)
  raise "Invalid hexadecimal" unless data

  hash = OpenSSL::Digest.new("SHA256")
  hash.update(data)
  hash1 = hash.digest

  hash = OpenSSL::Digest.new("SHA256")
  hash.update(hash1)

  hash.hexdigest
end

虽然我不得不质疑你为什么要使用两次 SHA256。我建议像这样更改哈希函数:

def hash256(hex_string)
  data = hex_decode(hex_string)
  raise "Invalid hexadecimal" unless data

  hash = OpenSSL::Digest.new("SHA256")
  hash.update(data)

  hash.hexdigest
end

对于 Ruby 脚本生成 SHA256 散列 digest gem:

require "digest"

def calc_hash
  sha = Digest::SHA256.new
  sha.update(@index.to_s + @timestamp.to_s + @data + @previous_hash)
  sha.hexdigest
end

对于 Crystal,您可以要求 openssl 并改用它:

require "openssl"

def calc_hash
  hash = OpenSSL::Digest.new("SHA256")
  hash.update(@index.to_s + @timestamp.to_s + @data + @previous_hash)
  hash.hexdigest
end

您可以只使用十六进制字符串的 .hexbytes:

# Sha256 hash of hex string
hex = "abcd"
p OpenSSL::Digest.new("sha256").update(hex).final.hexstring
# => "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589"

# Sha256 hash of hex data but on binary value
bin = hex.hexbytes
p OpenSSL::Digest.new("sha256").update(bin).final.hexstring
# => "123d4c7ef2d1600a1b3a0f6addc60a10f05a3495c9409f2ecbf4cc095d000a6b"

这样,您就可以在 Crystal.

中对二进制值使用 SHA256