很抱歉我这么好奇。
sha1使用[a-f0-9]
字符作为其哈希函数。我可以知道为什么它不使用所有可能的字符[a-z0-9]
吗?通过使用所有可用的字符,它可以大大增加可能的不同哈希的数量,从而降低可能的碰撞的可能性。
如果你不认为这是一个真正的问题,只需留言,我会立即删除这个问题。
===
如答案中所述,sha1执行NOT
仅使用16 chars
。正确的事实是:sha1是160位二进制数据(引用)。我添加这个是为了防止混淆。
您混淆了表示和内容。
sha1是160位二进制数据。你可以很容易地用来表示它
hex: 0xf1d2d2f924e986ac86fdf7b36c94bcdf32beec15
decimal: 1380568310619656533693587816107765069100751973397
binary: 1111000111010010110100101111100100100100111010011000011010101100100001101111110111110111101100110110110010010100101111001101111100110010101111101110110000010101
base 62: xufK3qj2bZgDrLA0XN0cLv1jZXc
十六进制并没有什么神奇之处。这只是一种非常常见的机制,用于显示沿4位边界轻松突破的内容。
base 62
输出是用这个小ruby生成的:
#!/usr/bin/ruby
def chars_from_hex(s)
c = s % 62
s = s / 62
if ( s > 0 )
chars_from_hex(s)
end
if (c < 10)
print c
elsif (c < 36)
print "abcdefghijklmnopqrstuvwxyz"[c-11].chr()
elsif (c < 62)
print "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[c-37].chr()
else
puts "error c", c
end
end
chars_from_hex(0xf1d2d2f924e986ac86fdf7b36c94bcdf32beec15)
它使用了从一个碱基转换为另一个碱基的标准习语,并将0-9
视为0-9,a-z
视为10-35,A-Z
视为36-61。如果需要的话,它可以通过包括例如!@#$%^&*()-_=+'|[]{},.<>/?;:'"~`
来简单地扩展以支持更多的数字。(或者任何一个庞大的Unicode代码点。)
@yes123特别询问了散列的ascii表示,因此以下是将160位散列直接解释为ascii的结果:
ñÒÒù$é¬ý÷³l¼ß2¾ì
它看起来不太像,因为:
- 对于小于32的字节值,ascii没有很好的可打印表示
- ascii本身不能表示大于127的字节值,127和255之间的值将根据iso-8859-01或其他字符编码方案进行解释
这种基础转换在实践中也很有用;Base64编码方法使用64个(而不是我的62个)字符来一次表示6个比特;它还需要两个字符来表示"数字"和一个字符来填充。UUEncoding选择了一组不同的"数字"。一位同事遇到了一个问题,通过将输入数字的基数改为输出数字,这个问题很容易解决。
这是错误的推理。sha1使用40*4=160比特。
恰好将其格式化为40个十六进制数字是很方便的(因此也是惯例)。
如果你觉得自己处于160位中可能开始发生冲突的问题域,你可以使用哈希大小更大的不同加密哈希
sha224: 224 bits
sha256: 256 bits
md5: 128 bits
使用十六进制只允许更容易地显示。SHA1使用160位。通过对其进行十六进制编码,它允许摘要以字符串的形式轻松显示和传输。仅此而已。
哈希算法的输出是位。用十六进制表示它们只是一种表示。它确实受益于长度为0 mod 16的结果,因此在基17中的表示将是不方便的。
sha-1生成一个160位的散列,即20个字节,其中有1461501637330902918203684832716283019655932542976个可能的值。因为散列算法就是这样定义的。
然而,将散列编码为可读文本通常是有用的,一种方便的方法是将这20个字节简单地编码为十六进制(将占用40个字节)。十六进制字符是[a-f0-9。