Author: R.W.Flurando
Tags: 困难, 教程
我闲来无事,担心岁月蹉跎,每每见到白发之人,心中恐惧。于是立定决心,网罗天下疑难琐事,终于挑了个相较之下最简单的md5算法来学习。
不过对拿着Pygame Zero都写不出Simon Say的我来说还是很困难的。
这个md5到底是怎么算的呢?
首先,方便起见我们只对一串可以一股脑读进内存的字节做处理(你可能想问,为啥不处理一串比特,或者超长字节流?我这不是能力有限嘛……对于怎么流式处理数据我现在是一头雾水,只好先放一边,有知道的请在ISSUE那里指点我,非常感谢!)
然后我们在这串字节后面跟着加上一个字节(也就是八个比特,比特知道吧?开关,01,二进制,明白不),加的是什么字节呢?10000000,注意这是二进制下的,十进制这个数是128,16进制是80。
然后得数一数原本(没有加128的时候)的这串字节有多长,这里指的是比特长度,你如果数了字节数,得自己乘上8。这很重要,别数错,因为我们接下来要把字节串长度(字节长度)补成64的倍数。
怎么补呢?要知道,我们得预留8个字节准备补字节串的原比特长度(就是说最后那64比特其实是这个长度的二进制表示,不过还有坑我们等下说)。那这之间怎么办,全部补0,准确地说是00000000。
请当心,补法只有一种,中间这些0没位置就算了,但前面说的128和刚保留的8个字节必须要有,不够你就往后补,但别一下加上去几个64字节的0,好吧。原则是每个串有且仅有一种补法。
举个例子,现在补完128,一共有57字节,离64只有7个,那我们就补7+56=63个字节的0,这不就有位置了吗?如果补完128一共68字节怎么办,相当于剩下4个字节,这时候就别补60+56个0字节了,只要补64-8-4=52个0字节就行。
最后剩下这8个字节怎么补?当心,不能一股脑摆上去,你看文档里那句little endianenss是不是很怪,没感觉也没事,我给你举两个例子,第一个错误例子,第二个正确例子。对了,记得原比特长度要取二进制下的低64位,你给它模个2的64次方就行。
看出来区别没有?第二种就叫little endianness,第一种是big endianness。我想你应该已经明白该怎么选择了。这种endianness的区分是为啥呢?因为人们想用多个字节表示数据,就好像我们这里的数字一样,小的数方便可能我一个字节表示绰绰有余,但数字大一些怎么办,8位只有2的8次方也就是256种形式,数显然比这个多,那么就需要多个字节表示数,比如连在一起的几个字节可以用二进制形式表示数。这很好,但问题出现了,人们开始时没有统一endianness,就导致从字节串一头开始读的时候,我认为先读到的是最低位,他认为是最高位,明白不?就好像我们十进制里看123456,机器不像人类,好像一股脑就了解了整个数,它是一位一位读的,你也不能想象成十二万三千……应该想象一,二,三,四,五,六一个一个给到你。这时候我们就会奇怪,到底是十二万多,还是六十多万呢?这就需要约定,这就是little endianness和big endianness的意义。
现在我们的字节串已经是64的倍数了,可以开始运算。
初始的四个“词”(是的,md5的运算基于所谓的词,一个词是四个字节,这样我们的字节串应该看成词串,长度是16的倍数,每个词看成一个用32个比特表示的数就行)我就不多说了,照抄!
注意,都是16进制下的数,不像十进制1234567890,它们是123456789ABCDEF0表示的,A是10,F是15,懂了吧?
K和s也建议直接抄(为啥是K,s?我抄维基百科的,RFC editor上是T,不过那个c实现好是好,真的不直观,不如维基的伪代码好照着实现)
接下来的运算我就不多说了,那段伪代码已经很清晰了,你们自己去看吧。值得注意的是接下来的循环操作每次对16个词进行运算并更新那四个词,算完这16个算下16个,最后正好结束就输出了。
这里有个细节,就是它词和词运算必须还是词,就是你别超出32比特,记得加法完要模一下2的32次方。
还有,它有个向左环形移位操作,这里最好的办法就是用或运算,别想别的。比如我要把数A做这个操作n位,怎么办,直接对左移n位的A后模2的32次方,然后和右移(32-n)位的A做或运算。(或运算是一种对比特的操作,只要有1这位就是1,比如1或0是1,0或0是0,10110101或11001000是11111101)
都跑完后输出这四个词,ok!万事大吉!
等一下,别急!还有坑!看到文档里那个little endianness没有?
这四个词顺序不变但各自都要按左边低位右边高位的方法输出!而且这个位不是你想的个位或者二进制的什么位,它是字节位,8个比特一组。
比如,我的四个词分别是(我们用16进制表示,一个数字/字母对应4个比特,按照我们习惯的左边高位右边低位写)
现在最后的md5如何用16进制字符串表示呢?
你可以暂停,好好想一想,再往下看你的答案对不对,当然我也有可能写错,欢迎在ISSUE那里指正(注意:我很少看Github,所以可能很久不回,抱歉)
正确答案是 7856341289674523023fb800bca5d356
你学会了吗?
技术不易,全靠社区。如果这篇文章有帮到你,请不要感谢我,希望你在学会技术后不要自得于“技术壁垒”,而是多多分享,欢迎把你的博客地址发到我的ISSUE那里,我们多多交流。