本文提供一個輕量級、可移植的 MD5 實現(基於 Solar Designer 公共域代碼),演示如何讀取文件指定偏移區間並計算其 MD5 摘要,包含完整源碼、測試程序與 Makefile。
md5.h/md5.c)特點:無版權限制、無 32 位整數依賴、無大小端配置、API 與 OpenSSL 兼容 (MD5_Init/Update/Final)。
// md5.h
typedef struct {
MD5_u32plus lo, hi; // 位計數器
MD5_u32plus a, b, c, d; // 狀態變量
unsigned char buffer[64]; // 數據緩衝區
MD5_u32plus block[16]; // 16 個 32 位字
} MD5_CTX;
void MD5_Init(MD5_CTX *ctx);
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
void MD5_Final(unsigned char *result, MD5_CTX *ctx);
md5.c 實現了 RFC 1321 四輪變換(F/G/H/I 函數),採用 STEP 宏優化,支持任意長度數據流式處理。
// test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "md5.h"
unsigned char *getMD5InRange(const char *filename, long start, long end) {
FILE *fp = fopen(filename, "rb"); // 二進制模式關鍵!
if (!fp) return NULL;
fseek(fp, start, SEEK_SET);
long len = end - start + 1;
char *buf = malloc(len + 1);
fread(buf, 1, len, fp);
buf[len] = '\0';
fclose(fp);
unsigned char *digest = malloc(16);
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, buf, len); // 使用 len 而非 strlen,支持二進制數據
MD5_Final(digest, &ctx);
free(buf);
return digest;
}
int main(void) {
int st, ed;
while (scanf("%d %d", &st, &ed) == 2) {
unsigned char *md5 = getMD5InRange("aaa.txt", st, ed);
if (md5) {
for (int i = 0; i < 16; ++i) printf("%02x", md5[i]);
printf("\n");
free(md5);
}
}
return 0;
}
| 點 | 說明 |
|---|---|
二進制模式 "rb" | Windows 下文本模式會轉換換行符,導致 MD5 不匹配;Unix/Linux 無影響但建議統一用 rb。 |
MD5_Update 長度參數 | 必須傳實際讀取字節數 len,不可用 strlen(buf)(二進制數據可能含 \0)。 |
| 緩衝區分配 | malloc(len + 1) 並手動添加 \0 便於調試打印,實際計算不依賴結束符。 |
| 摘要輸出格式 | %02x 確保每字節兩位十六進制,共 32 字符。 |