引言 我们在嵌入式及单片机的产品开发时,往往需要对一些文件进行检验,来保证此文件是在传输的过程没有被修改或者损坏。比如IAP升级程序时,往往就需要对升级固件进行校验。MD5是其中非常常用的一种检验方式。本文通过使用MD5检验程序,对STM32的Flash中的某一段数据进行检验,检验后存放到字符串里,可用来比对或者输出。
介绍MD5简介及使用场景MD5校验(checksum)是通过对接收的传输数据执行散列运算来检查数据的正确性。一个散列函数,比如 MD5,是一个将任意长度的数据字符串转化成短的固定长度的值的单向操作。任意两个字符串不应有相同的散列值(即,有“很大可能”是不一样的,并且要人为地创造出来两个散列值相同的字符串应该是困难的)。
一个 MD5 校验和(checksum)通过对接收的传输数据执行散列运算来检查数据的正确性。计算出的散列值拿来和随数据传输的散列值比较。如果两个值相同,说明传输的数据完整无误、没有被窜改过(前提是散列值没有被窜改),从而可以放心使用。
MD5校验可以应用多个领域,比如说机密资料的检验,下载文件的检验,明文密码的加密等。
MD5原理MD5的加密过程,整体来看,就是先定义四个值,然后用这四个值,对原文信息进行计算,并得到新的四个值,然后再对原文进行计算,再得到新的四个值,如此循环一定次数,最终对最后的这四个值进行简单的字符串拼接,就得到了最终的密文。
主要就是下面这3步:
填补信息
用原文长度位数对512求余,如果结果不为448,就填充到448位。填充是第一位填1,后面填0。512-448=64,用这剩余的64位,记录原文长度。
最终得到一个填补完的信息(总长=原文长度+512位) 拿到初始值
四个初始值,是MD5这个算法提前定义好的,分别是4个32位的值,总共刚好128位。
我们用ABCD命名:
A=0xefcdab89
B=0x89ABCDEF
C=0x98badcfe
D=0x10325476
3、真正的计算
计算分为多次循环,每次循环,都是用ABCD和原文在第一步填补完的信息,进行计算,最终得到新的ABCD。最后将最后一次ABCD拼成字符串,就是最终的密文。
循环先分为主循环,每个主循环中又套有子循环。
主循环次数 = 原文长度/512。
子循环次数 = 64次。
软件实现网络上的MD5检验程序有很多,但实现在STM32上的其实并没有几个能用的。本文的程序为我自主编写,并检验使用过的。 压缩函数
- a = A, b = B, c = C, d = D;
- FF(a, b, c, d, x[0, 7, 0xd76aa478);
- FF(d, a, b, c, x[1, 12, 0xe8c7b756);
- FF(c, d, a, b, x[2, 17, 0x242070db);
- FF(b, c, d, a, x[3, 22, 0xc1bdceee);
- FF(a, b, c, d, x[4, 7, 0xf57c0faf);
- FF(d, a, b, c, x[5, 12, 0x4787c62a);
- FF(c, d, a, b, x[6, 17, 0xa8304613);
- FF(b, c, d, a, x[7, 22, 0xfd469501);
- FF(a, b, c, d, x[8, 7, 0x698098d8);
- FF(d, a, b, c, x[9, 12, 0x8b44f7af);
- FF(c, d, a, b, x[10, 17, 0xffff5bb1);
- FF(b, c, d, a, x[11, 22, 0x895cd7be);
- FF(a, b, c, d, x[12, 7, 0x6b901122);
- FF(d, a, b, c, x[13, 12, 0xfd987193);
- FF(c, d, a, b, x[14, 17, 0xa679438e);
- FF(b, c, d, a, x[15, 22, 0x49b40821);
- GG(a, b, c, d, x[1, 5, 0xf61e2562);
- GG(d, a, b, c, x[6, 9, 0xc040b340);
- GG(c, d, a, b, x[11, 14, 0x265e5a51);
- GG(b, c, d, a, x[0, 20, 0xe9b6c7aa);
- GG(a, b, c, d, x[5, 5, 0xd62f105d);
- GG(d, a, b, c, x[10, 9, 0x02441453);
- GG(c, d, a, b, x[15, 14, 0xd8a1e681);
- GG(b, c, d, a, x[4, 20, 0xe7d3fbc8);
- GG(a, b, c, d, x[9, 5, 0x21e1cde6);
- GG(d, a, b, c, x[14, 9, 0xc33707d6);
- GG(c, d, a, b, x[3, 14, 0xf4d50d87);
- GG(b, c, d, a, x[8, 20, 0x455a14ed);
- GG(a, b, c, d, x[13, 5, 0xa9e3e905);
- GG(d, a, b, c, x[2, 9, 0xfcefa3f8);
- GG(c, d, a, b, x[7, 14, 0x676f02d9);
- GG(b, c, d, a, x[12, 20, 0x8d2a4c8a);
- HH(a, b, c, d, x[5, 4, 0xfffa3942);
- HH(d, a, b, c, x[8, 11, 0x8771f681);
- HH(c, d, a, b, x[11, 16, 0x6d9d6122);
- HH(b, c, d, a, x[14, 23, 0xfde5380c);
- HH(a, b, c, d, x[1, 4, 0xa4beea44);
- HH(d, a, b, c, x[4, 11, 0x4bdecfa9);
- HH(c, d, a, b, x[7, 16, 0xf6bb4b60);
- HH(b, c, d, a, x[10, 23, 0xbebfbc70);
- HH(a, b, c, d, x[13, 4, 0x289b7ec6);
- HH(d, a, b, c, x[0, 11, 0xeaa127fa);
- HH(c, d, a, b, x[3, 16, 0xd4ef3085);
- HH(b, c, d, a, x[6, 23, 0x04881d05);
- HH(a, b, c, d, x[9, 4, 0xd9d4d039);
- HH(d, a, b, c, x[12, 11, 0xe6db99e5);
- HH(c, d, a, b, x[15, 16, 0x1fa27cf8);
- HH(b, c, d, a, x[2, 23, 0xc4ac5665);
- II(a, b, c, d, x[0, 6, 0xf4292244);
- II(d, a, b, c, x[7, 10, 0x432aff97);
- II(c, d, a, b, x[14, 15, 0xab9423a7);
- II(b, c, d, a, x[5, 21, 0xfc93a039);
- II(a, b, c, d, x[12, 6, 0x655b59c3);
- II(d, a, b, c, x[3, 10, 0x8f0ccc92);
- II(c, d, a, b, x[10, 15, 0xffeff47d);
- II(b, c, d, a, x[1, 21, 0x85845dd1);
- II(a, b, c, d, x[8, 6, 0x6fa87e4f);
- II(d, a, b, c, x[15, 10, 0xfe2ce6e0);
- II(c, d, a, b, x[6, 15, 0xa3014314);
- II(b, c, d, a, x[13, 21, 0x4e0811a1);
- II(a, b, c, d, x[4, 6, 0xf7537e82);
- II(d, a, b, c, x[11, 10, 0xbd3af235);
- II(c, d, a, b, x[2, 15, 0x2ad7d2bb);
- II(b, c, d, a, x[9, 21, 0xeb86d391);
- A += a;
- B += b;
- C += c;
- D += d;
复制代码
分组读取
- <font face="Tahoma"><font color="#000000"><font size="3">uint8_t j, k;</font>
- <font size="3"> memset(x, 0, 64);</font>
- <font size="3"> ulSampleIndex = 0;</font>
- <font size="3"> for (j = 0; j < 16; j++)</font>
- <font size="3"> {</font>
- <font size="3"> for (k = 0; k < 4; k++)</font>
- <font size="3"> {</font>
- <font size="3"> if ((ulReadCnt >= ulFlieLength / 1024) && (ulDataIndex >= ulFlieLength % 1024))</font>
- <font size="3"> break;</font>
- <font size="3"> ((char *)x)[ulSampleIndex = ucaFlashBuf[ulDataIndex;</font>
- <font size="3"> ulDataIndex++;</font>
- <font size="3"> ulSampleIndex++;</font>
- <font size="3"> }</font>
- <font size="3"> }</font></font></font>
复制代码
应用函数
- <font size="3"> uint16_t usCnt = 0;</font>
- <font size="3"> uint32_t ulFileLen[2 = {0};</font>
- <font size="3"> </font><i>/* 计算整数部分 */</i>
- <font size="3"> for (ulReadCnt = 0; ulReadCnt < ulFlieLength / 1024; ulReadCnt++)</font>
- <font size="3"> {</font>
- <font size="3"> 读取你的文件的 1024字节;</font>
- <font size="3"> ulFlashAdd += 1024;</font>
- <font size="3"> for (usCnt = 0; usCnt < 16; usCnt++)</font>
- <font size="3"> {</font>
- <font size="3"> ReadGroupTempBuf(ulFlieLength);</font>
- <font size="3"> MD5();</font>
- <font size="3"> }</font>
- <font size="3"> ulDataIndex = 0;</font>
- <font size="3"> }</font>
- <font size="3"> </font><i>/* 计算余数部分 */</i>
- <font size="3"> memset(ucaFlashBuf, 0, 1025);</font>
- <font size="3"> 读取你的文件的文件长度对 1024取余后除以2个字节;</font>
- <font size="3"> ReadGroupTempBuf(ulFlieLength);</font>
- <font size="3"> for (usCnt = 0; usCnt < (ulFlieLength % 1024) / 64; usCnt++)</font>
- <font size="3"> {</font>
- <font size="3"> MD5();</font>
- <font size="3"> ReadGroupTempBuf(ulFlieLength);</font>
- <font size="3"> }</font>
- <font size="3"> </font><i>/* 文件结束补1,补0操作,128二进制即10000000 */</i>
- <font size="3"> ((char *)x)[ulFlieLength % 64 = 128;</font>
- <font size="3"> if (ulFlieLength % 64 > 55)</font>
- <font size="3"> {</font>
- <font size="3"> MD5(), memset(x, 0, 64);</font>
- <font size="3"> }</font>
- <font size="3"> </font><i>/* 文件末尾加入原文件的bit长度 */</i>
- <font size="3"> ulFileLen[1 = ulFlieLength / 0x20000000;</font>
- <font size="3"> ulFileLen[0 = (ulFlieLength % 0x20000000) * 8;</font>
- <font size="3"> memcpy(x + 14, ulFileLen, 8);</font>
- <font size="3"> MD5();</font>
- <font size="3"> sprintf(pEsult, "%08X%08X%08X%08X", PP(A), PP(B), PP(C), PP(D));</font>
复制代码
转载自: 跋扈洋
|