I'm new to Crystal. I'd like to try and find the SHA256 hash of a hex string. I've managed to get something working:
sha256 = OpenSSL::Digest.new("sha256")
puts sha256.update("abcd")
But I'm not sure how to put the binary value of "abcd" in to the hash function, or get binary out. I'd basically like to be able to recreate this Ruby function:
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
Is it possible to use SHA256 with binary values in Crystal?
To determine the file's SHA-256: Note: [FILENAME] = Name of file. Type CertUtil -hashfile [FILENAME] SHA256 and then press Enter.
SHA256 algorithm generates an almost-unique, fixed size 256-bit (32-byte) hash. Hash is so called a one way function. This makes it suitable for checking integrity of your data, challenge hash authentication, anti-tamper, digital signatures, blockchain.
Decoding a string of hex characters into a binary slice isn't currently part of the crystal standard library, so I wrote a decoding function myself:
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
This function takes a String
containing hexadecimal characters, then decodes it into a Slice(UInt8)
(or returns nil
if the hex is invalid).
Then the full code equivalent to the ruby code you pasted above would be:
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
Although I have to question why you would want to use SHA256 twice. I would recommend changing the hash function like so:
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
For a Ruby script generating a SHA256 hash with the 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
For Crystal, you can require openssl
and use that instead:
require "openssl"
def calc_hash
hash = OpenSSL::Digest.new("SHA256")
hash.update(@index.to_s + @timestamp.to_s + @data + @previous_hash)
hash.hexdigest
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With