2017-02-17 240 views
4

我是Crystal的新手。我想尝试找到一个十六进制字符串的哈希值SHA256。我已经成功地得到一些工作: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的二进制值?

回答

8

解码十六进制字符的字符串转换成二进制片不是目前晶体标准库的一部分,所以我写的解码功能自己:

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)(如果十六进制无效,则返回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 
+0

非常感谢。两次使用SHA256的原因是因为我试图通过编写一个比特币库来学习Crystal,而没有真正的理由,事情往往会被哈希两次。 – inersha

0

对于Ruby脚本生成SHA256哈希与digest宝石:

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