小文字 吃饭,睡觉,溜狗头

MD5/SHA与进制的表达

img

背景

日常生活中十进制用的最多,但是编码中二进制和十六进制也是随处可见,在打开各种二进制文件数据时,经常出现十六进制, 同时表示MD5,SHA时也常用到。

Hex 与 bit

从表示范围来讲:

  • 一个16进制数:最多可以表示16=2^4
  • 两个16进制数:最多表示16*16=2^8
  • 一个字节是8位,因此既可以用8位二进制数表示,也可以用2位16进制数表示;

总结一句话,2个十六进制 => 一个字节

MD5 与 Hex

在输出MD5的时候我们一般看到的是一个16进制的字符串,根据MD5的定义,他实际上是128位(16字节)的散列值; 所以MD5的16进制字符串长度为:128/8 * 2 = 32

aven$ md5 -s 123
MD5 ("123") = 202cb962ac59075b964b07152d234b70

也可以通过openssl生成MD5,注意使用echo输出时要加上-n参数,表示不输出换行符,否则得到的MD5会不一样。

aven$ echo -n 123|openssl md5 -hex
(stdin)= 202cb962ac59075b964b07152d234b70

SHA-1 与 Base64

SHA-1是一种常见的安全散列算法,当然现在已经被Google攻破了,根据定义,他是160位(20字节)的散列值;

  • 用十六进制表示,需要的16进制字符串长度为:160/8*2=40
  • 有的时候也用base64来表示, 需要的长度为:28

HEX

aven$ echo -n 123|openssl sha1 -hex
(stdin)= 40bd001563085fc35165329ea1ff5c5ecbdbbeef

Base64

aven$ echo -n 123|openssl sha1 -binary|base64
QL0AFWMIX8NRZTKeof9cXsvbvu8=

由于base64可以表示64种情况,64=2^6,因此理论上一个base64的字符对应6位的二进制范围,那么 160/6=26.6 个字符就可以表示160位的SHA-1. 那么为什么实际上确用28个字符来表示?

这个问题,可以这么考虑:1个字节是8位,我们除了要考虑理论上的表示范围还要考虑每个字节的位数, 所以实际上应该这么算:

160/8=20字节,对一个字节来说,base64用6位还多2位,6和8的最小公约数是24,也就是3个字节;
如果我们紧凑使用的话,也就是每三个字节用4个base64字符表示;
所以3*7=20+1,4*7=28,也就是我们需要用28个base64字符来表示160位的数据;