引言
我們在嵌入式及單片機的産品開發時,往往需要對一些檔案進行檢驗,來保證此檔案是在傳輸的過程沒有被修改或者損壞。比如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;
複制
分組讀取
uint8_t j, k;
memset(x, 0, 64);
ulSampleIndex = 0;
for (j = 0; j < 16; j++)
{
for (k = 0; k < 4; k++)
{
if ((ulReadCnt >= ulFlieLength / 1024) && (ulDataIndex >= ulFlieLength % 1024))
break;
((char *)x)[ulSampleIndex] = ucaFlashBuf[ulDataIndex];
ulDataIndex++;
ulSampleIndex++;
}
}
複制
應用函數
uint16_t usCnt = 0;
uint32_t ulFileLen[2] = {0};
/* 計算整數部分 */
for (ulReadCnt = 0; ulReadCnt < ulFlieLength / 1024; ulReadCnt++)
{
讀取你的檔案的 1024位元組;
ulFlashAdd += 1024;
for (usCnt = 0; usCnt < 16; usCnt++)
{
ReadGroupTempBuf(ulFlieLength);
MD5();
}
ulDataIndex = 0;
}
/* 計算餘數部分 */
memset(ucaFlashBuf, 0, 1025);
讀取你的檔案的檔案長度對 1024取餘後除以2個位元組;
ReadGroupTempBuf(ulFlieLength);
for (usCnt = 0; usCnt < (ulFlieLength % 1024) / 64; usCnt++)
{
MD5();
ReadGroupTempBuf(ulFlieLength);
}
/* 檔案結束補1,補0操作,128二進制即10000000 */
((char *)x)[ulFlieLength % 64] = 128;
if (ulFlieLength % 64 > 55)
{
MD5(), memset(x, 0, 64);
}
/* 檔案末尾加入原檔案的bit長度 */
ulFileLen[1] = ulFlieLength / 0x20000000;
ulFileLen[0] = (ulFlieLength % 0x20000000) * 8;
memcpy(x + 14, ulFileLen, 8);
MD5();
sprintf(pEsult, "%08X%08X%08X%08X", PP(A), PP(B), PP(C), PP(D));
複制
完整程式
擷取方式如下:
- https://blog.csdn.net/qq_44629109/category_11627212.html
- https://download.csdn.net/download/qq_44629109/85676113
MD5工具
下載下傳下面的MD5工具,可以直接把檔案的MD5轉換出來,我們可以用它來測試我們程式的MD5值到底對不對。
https://download.csdn.net/download/qq_44629109/85677447