news 2026/4/16 16:19:20

C++ MD5 算法实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ MD5 算法实现原理

一:概述

MD5算法是一种广泛使用的哈希函数,可生成 128位哈希值。MD5 由Ronald Rivest于 1991 年设计,用于取代早期的哈希函数MD4。MD5 算法是把任意长度的字节流 → 通过固定的非线性函数 + 位运算 → 压缩成 128 bit 状态。

MD5 可作为校验和算法,用于验证数据完整性并检测意外的数据损坏。历史上,它曾被广泛用作加密哈希函数,但随后人们发现其存在多种安全漏洞。因此,MD5 已不再适用于安全敏感场景。不过,在非加密用途下,MD5 仍然具有一定价值,例如用于确定分区数据库中某个键所属的分区。由于其计算开销低于较新的安全哈希算法,在对安全性要求不高的场合,MD5 仍更受青睐。

二:算法原理

MD5 是一种将任意长度消息映射为固定长度输出的哈希算法,其输出长度为 128 位。算法首先将输入消息划分为若干个 512 位的数据块,每个数据块由 16 个 32 位字组成。为满足分组处理的要求,消息在处理前需要进行填充,使其总长度成为 512 的整数倍。

填充过程如下:首先在消息末尾附加一个值为 1 的比特;随后添加若干个值为 0 的比特,使填充后的消息长度比 512 的倍数少 64 位;最后,用 64 位表示原始消息长度(2的64次方取模)并附加到消息末尾。

MD5 的核心算法维护一个 128 位的内部状态,该状态由四个 32 位字组成,通常记为 A、B、C 和 D。这些状态变量在算法开始时被初始化为固定的常量。随后,算法依次处理每一个 512 位消息块,并在此过程中不断更新内部状态。

每个消息块的处理过程由四个相似的阶段组成,称为“轮”。每一轮包含 16 个基本操作,这些操作基于非线性布尔函数、在 32 位无符号整数范围内进行加法运算,溢出部分被丢弃;循环左移运算则是在保持位数不变的情况下,将移出的高位重新补回到低位。算法共定义了四种不同的非线性函数,每一轮使用其中一种。

三:代码

#include <stdint.h> #include <string.h> #include <stdio.h> /* ===== MD5 四个非线性函数 ===== */ #define F(x,y,z) ((x & y) | (~x & z)) #define G(x,y,z) ((x & z) | (y & ~z)) #define H(x,y,z) (x ^ y ^ z) #define I(x,y,z) (y ^ (x | ~z)) static inline uint32_t rol(uint32_t x, uint32_t n) { return (x << n) | (x >> (32 - n)); } /* ===== 常量 ===== */ static const uint32_t K[64] = { 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, 0x6b901122,0xfd987193,0xa679438e,0x49b40821, 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa, 0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed, 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a, 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70, 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039, 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1, 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 }; static const uint32_t S[64] = { 7,12,17,22, 7,12,17,22, 7,12,17,22, 7,12,17,22, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 4,11,16,23, 4,11,16,23, 4,11,16,23, 4,11,16,23, 6,10,15,21, 6,10,15,21, 6,10,15,21, 6,10,15,21 }; /* ===== MD5 上下文 ===== */ typedef struct { uint32_t state[4]; uint64_t bitlen; uint8_t buffer[64]; size_t buflen; } md5_ctx; /* ===== 单个 512-bit 块处理 ===== */ static void md5_process_block(md5_ctx* ctx, const uint8_t block[64]) { uint32_t A = ctx->state[0]; uint32_t B = ctx->state[1]; uint32_t C = ctx->state[2]; uint32_t D = ctx->state[3]; uint32_t M[16]; /* little-endian 解析 */ for (int i = 0; i < 16; i++) { M[i] = (uint32_t)block[i * 4] | ((uint32_t)block[i * 4 + 1] << 8) | ((uint32_t)block[i * 4 + 2] << 16) | ((uint32_t)block[i * 4 + 3] << 24); } for (int i = 0; i < 64; i++) { uint32_t Fv, g; if (i < 16) { Fv = F(B, C, D); g = i; } else if (i < 32) { Fv = G(B, C, D); g = (5 * i + 1) % 16; } else if (i < 48) { Fv = H(B, C, D); g = (3 * i + 5) % 16; } else { Fv = I(B, C, D); g = (7 * i) % 16; } uint32_t tmp = D; D = C; C = B; B = B + rol(A + Fv + K[i] + M[g], S[i]); A = tmp; } ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; } /* ===== 接口函数 ===== */ void md5_init(md5_ctx* ctx) { ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; ctx->bitlen = 0; ctx->buflen = 0; } void md5_update(md5_ctx* ctx, const uint8_t* data, size_t len) { ctx->bitlen += (uint64_t)len * 8; while (len--) { ctx->buffer[ctx->buflen++] = *data++; if (ctx->buflen == 64) { md5_process_block(ctx, ctx->buffer); ctx->buflen = 0; } } } void md5_final(md5_ctx* ctx, uint8_t out[16]) { size_t i = ctx->buflen; ctx->buffer[i++] = 0x80; if (i > 56) { memset(ctx->buffer + i, 0, 64 - i); md5_process_block(ctx, ctx->buffer); i = 0; } memset(ctx->buffer + i, 0, 56 - i); for (int j = 0; j < 8; j++) ctx->buffer[56 + j] = (ctx->bitlen >> (8 * j)) & 0xff; md5_process_block(ctx, ctx->buffer); for (i = 0; i < 4; i++) { out[i * 4 + 0] = (ctx->state[i] >> 0) & 0xff; out[i * 4 + 1] = (ctx->state[i] >> 8) & 0xff; out[i * 4 + 2] = (ctx->state[i] >> 16) & 0xff; out[i * 4 + 3] = (ctx->state[i] >> 24) & 0xff; } } /* ===== 测试 ===== */ int main(void) { const char* msg = "abc"; uint8_t hash[16]; md5_ctx ctx; md5_init(&ctx); md5_update(&ctx, (const uint8_t*)msg, strlen(msg)); md5_final(&ctx, hash); for (int i = 0; i < 16; i++) printf("%02x", hash[i]); printf("\n"); return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 15:34:40

Spring Boot定时任务实战:让代码像闹钟一样准时工作!

文章目录 一、Spring Boot定时任务基础&#xff1a;从"闹钟"到"智能日历"1.1 启用定时任务功能1.2 创建你的第一个定时任务 二、多种调度方式详解&#xff1a;选择合适的"时间管理器"2.1 fixedRate&#xff1a;固定频率执行2.2 fixedDelay&#…

作者头像 李华
网站建设 2026/4/16 15:34:35

Sealos DevBox的长期主义:为什么我押注它能赢得未来

说实话&#xff0c;当所有人都在吹捧云端开发是未来趋势时&#xff0c;我反而想泼点冷水——这个赛道九成的玩家活不过三年。不是危言耸听。Gitpod 融资上亿最后收缩业务&#xff0c;CodeSandbox 转型做 AI&#xff0c;国内一堆云 IDE 项目悄无声息地停更。大家都说云端开发好&…

作者头像 李华
网站建设 2026/4/13 17:26:25

springboot影院购票管理系统设计实现

影院购票管理系统设计背景传统影院票务管理依赖人工操作&#xff0c;存在效率低、易出错、数据统计困难等问题。随着移动互联网普及&#xff0c;观众对线上购票、选座、实时查询的需求激增。SpringBoot框架因其快速开发、微服务支持及与Spring生态无缝整合的特性&#xff0c;成…

作者头像 李华
网站建设 2026/4/15 19:05:42

Apache Fesod 读取端的事件驱动架构

抽丝剥茧&#xff1a;Apache Fesod 读取端的事件驱动架构 1. 入口&#xff1a;一个优雅的门面 (Facade) 简约而不简单 哪怕系统内部再复杂&#xff0c;给用户的入口必须足够简单。Fesod 采用了经典的 Facade 模式&#xff08;外观模式&#xff09;。 所有的读取操作都从 Fes…

作者头像 李华
网站建设 2026/4/13 20:58:24

震惊!浙江AI巨头光景泽创,竟因这3个秘密颠覆行业!

当AI工具不再“单打独斗”&#xff1a;全链路协同如何重塑中小微企业增长逻辑 最近与几位电商和本地生活领域的创业者交流&#xff0c;一个普遍的共鸣是&#xff1a;大家手里或多或少都用上了几款AI工具——有的用AI生成海报&#xff0c;有的用机器人自动回消息&#xff0c;还…

作者头像 李华