MD5哈希和Base64编码

31

如果我有一个32个字符的字符串(MD5哈希值),并将其使用Base64编码,那么编码后的字符串的最大长度是多少?

答案:编码后的字符串最大长度为44个字符。

5
如果你有一个32个字符的字符串,它是一个MD5哈希值,那么它已经是十六进制编码的,无需对其进行base64编码。 - President James K. Polk
2
一个MD5哈希不是十六进制!它是16个字节 - 十六进制只是一种传统的表示方法。 - Nick Johnson
3
@GregS,你说得对,MD5散列通常以十六进制形式表示,这是Base64的子集。但是将其转换为Base64有一个目的——Base64采用更大的字符集,因此需要更少的字符。如果你使用Base64(22个字符),而不是十六进制(32个字符)表示法,在明文或字符编码方案中保存时可以节省磁盘空间。 - Thomas Albright
@GregS 实际上,如果期望的格式是这样的,例如在HTTP Content-MD5 header中,你确实需要对其进行编码。 - Michael
@Michael 实际上,在这种情况下,您必须先进行十六进制解码,然后再进行base64编码。32个字符的十六进制字符串的base64编码将是不正确的。 - President James K. Polk
@GregS 是的,没错 - Michael
3个回答

77
一个MD5值在Base64表示法中始终为22(有用的)字符长。许多Base64算法在对MD5散列进行编码时还会附加2个字符的填充,使总长度达到24个字符。这种填充不添加有用信息,可以被丢弃。只有前22个字符是重要的。
原因如下:
一个MD5哈希值是128位的值。每个Base64字符串中的每个字符包含6个信息位,因为该字符有64个可能的值,并且需要6个2的幂才能达到64。每个字符具有6个信息位,21个字符含126位信息,22个字符含132位信息。由于128位无法容纳在21个字符内,但可以适应22个字符(留有一点余地),因此128位值始终在Base64中以22个字符的形式表示。
关于填充的说明:
我上面提到,许多Base64编码算法在对MD5值进行编码时会附加一些字符填充。这是因为Base64将3个字节的信息表示为4个字符。由于MD5具有16个字节的信息,因此许多Base64编码算法附加“ ==”来表示输入的16个字节比下一个3的倍数少2个字节,而下一个3的倍数是18个字节。这2个等号不添加任何信息,存储时可以丢弃。

12
根据http://zh.wikipedia.org/wiki/Base64,输入n个字节将会输出(n + 2 - ((n + 2) % 3)) / 3 * 4个字节长度,当n很大时趋近于n * 4 / 3或1.33333n。因此,对于32个字节的输入,输出长度为((32 + 2 - (32 + 2) % 3)) / 3 * 4 = 34 - (34 % 3) / 3 * 4 = (34 - 1) / 3 * 4 = 33/3*4 = 44个字符。您也可以将其以原始二进制形式(128位)提取并直接编码为base64,这意味着只需转换16个字节而不是32个字节,编码后变为24个字节。

8
MD5哈希是128位,可以编码为24个Base64字符。 - President James K. Polk
@ GregS,抱歉,是的,我在想160位的SHA1。 - Arantor
3
在将十六进制编码的哈希输出进行Base64编码时,实际上没有任何意义 - 十六进制序列中的有效字符是Base64序列中的子集。 - caf
2
@caf,但是将十六进制解码然后重新编码为Base64可能有意义...编码后的字符串大小会更小。 - JoelFan
@JoelFan,例子在这里:http://stackoverflow.com/questions/27383761/how-do-you-reencode-a-python-string-via-packing-and-unpacking-using-binascii - shadowbq
更容易解释这个数学问题的方法是,将每3个字节的二进制(24位)编码为4个字符(每个字符6位)。因此,ROUND_UP(n / 3)* 4是最常用的写法,大多数编程语言都可以写成:(n + 2)/ 3 * 4或Math.ceil(n / 3)* 4。无论哪种情况,答案仍然是24个字符。 - Adam Tegen

5

MD5 128位以Base64表示为22个字符,同时在此情况下还有2个填充字符"="。

如何实现?

$ md5sum ./README.md 
c6b5f48774aa0a87a82a276ff86be507  ./README.md
$ md5sum ./README.md | base64
YzZiNWY0ODc3NGFhMGE4N2E4MmEyNzZmZjg2YmU1MDcgIC4vUkVBRE1FLm1kCg==

在这种情况下,Base64编码字符串的长度不会比MD5哈希长度短。因为编码的是MD5哈希的存储形式,而不是MD5哈希值本身。需要注意MD5哈希的一个数字使用了多少位来存储。正确的方法是:将哈希值转换成二进制,再将二进制转换成Base64编码字符串。
$ cat ./README.md |  openssl dgst -md5 
c6b5f48774aa0a87a82a276ff86be507
$ cat ./README.md |  openssl dgst -md5 -binary | openssl enc -base64
xrX0h3SqCoeoKidv+GvlBw==

或者
$ md5sum ./LICENSE 
e3fc50a88d0a364313df4b21ef20c29e  ./LICENSE
$ cat ./LICENSE |  openssl dgst -md5 -binary | openssl enc -base64
4/xQqI0KNkMT30sh7yDCng==
$ (echo 0:; echo e3fc50a88d0a364313df4b21ef20c29e) | xxd -rp -l 16|base64
4/xQqI0KNkMT30sh7yDCng==

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接