1、编 辑 本 段 一 、 MD5 算 法1、 简 介不 管 是 MD2、 MD4 还 是 MD5, 它 们 都 需 要 获 得 一 个 随 机 长 度 的 信 息 并 产 生一 个 128 位 的 信 息 摘 要 。 虽 然 这 些 算 法 的 结 构 或 多 或 少 有 些 相 似 , 但 MD2的 设 计 与 MD4 和 MD5 完 全 不 同 , 那 是 因 为 MD2 是 为 8 位 机 器 做 过 设 计 优 化的 , 而 MD4 和 MD5 却 是 面 向 32 位 的 电 脑 。 这 三 个 算 法 的 描 述 和 C 语 言 源 代码 在 Internet RFCs 1321 中
2、 有 详 细 的 描 述( http:/www.ietf.org/rfc/rfc1321.txt) , 这 是 一 份 最 权 威 的 文 档 , 由Ronald L. Rivest 在 1992 年 8 月 向 IEFT 提 交 。 Van Oorschot 和 Wiener 曾 经 考 虑 过 一 个 在 散 列 中 暴 力 搜 寻 冲 突 的 函 数( Brute-Force Hash Function) , 而 且 他 们 猜 测 一 个 被 设 计 专 门 用 来 搜 索MD5 冲 突 的 机 器 ( 这 台 机 器 在 1994 年 的 制 造 成 本 大 约 是 一 百 万 美
3、元 ) 可 以平 均 每 24 天 就 找 到 一 个 冲 突 。 但 单 从 1991 年 到 2001 年 这 10 年 间 , 竟 没有 出 现 替 代 MD5 算 法 的 MD6 或 被 叫 做 其 他 什 么 名 字 的 新 算 法 这 一 点 , 我 们 就可 以 看 出 这 个 瑕 疵 并 没 有 太 多 的 影 响 MD5 的 安 全 性 。 上 面 所 有 这 些 都 不 足 以成 为 MD5 的 在 实 际 应 用 中 的 问 题 。 并 且 , 由 于 MD5 算 法 的 使 用 不 需 要 支 付 任何 版 权 费 用 的 , 所 以 在 一 般 的 情 况 下 ( 非
4、 绝 密 应 用 领 域 。 但 即 便 是 应 用 在 绝密 领 域 内 , MD5 也 不 失 为 一 种 非 常 优 秀 的 中 间 技 术 ) , MD5 怎 么 都 应 该 算 得上 是 非 常 安 全 的 了 。 2、 算 法 的 应 用MD5 的 典 型 应 用 是 对 一 段 信 息 ( Message) 产 生 信 息 摘 要 ( Message-Digest) , 以 防 止 被 篡 改 。 比 如 , 在 UNIX 下 有 很 多 软 件 在 下 载 的 时 候 都 有一 个 文 件 名 相 同 , 文 件 扩 展 名 为 .md5 的 文 件 , 在 这 个 文 件 中
5、 通 常 只 有 一 行文 本 , 大 致 结 构 如 : MD5 (tanajiya.tar.gz) = 0ca175b9c0f726a831d895e269332461 这 就 是 tanajiya.tar.gz 文 件 的 数 字 签 名 。 MD5 将 整 个 文 件 当 作 一 个 大文 本 信 息 , 通 过 其 不 可 逆 的 字 符 串 变 换 算 法 , 产 生 了 这 个 唯 一 的 MD5 信 息摘 要 。 如 果 在 以 后 传 播 这 个 文 件 的 过 程 中 , 无 论 文 件 的 内 容 发 生 了 任 何 形 式的 改 变 ( 包 括 人 为 修 改 或 者
6、下 载 过 程 中 线 路 不 稳 定 引 起 的 传 输 错 误 等 ) , 只要 你 对 这 个 文 件 重 新 计 算 MD5 时 就 会 发 现 信 息 摘 要 不 相 同 , 由 此 可 以 确 定 你得 到 的 只 是 一 个 不 正 确 的 文 件 。 如 果 再 有 一 个 第 三 方 的 认 证 机 构 , 用 MD5还 可 以 防 止 文 件 作 者 的 “抵 赖 “, 这 就 是 所 谓 的 数 字 签 名 应 用 。 3、 MD5 还 广 泛 用 于 加 密 和 解 密 技 术 上比 如 在 UNIX 系 统 中 用 户 的 密 码 就 是 以 MD5( 或 其 它 类
7、 似 的 算 法 ) 经 加密 后 存 储 在 文 件 系 统 中 。 当 用 户 登 录 的 时 候 , 系 统 把 用 户 输 入 的 密 码 计 算 成MD5 值 , 然 后 再 去 和 保 存 在 文 件 系 统 中 的 MD5 值 进 行 比 较 , 进 而 确 定 输 入 的密 码 是 否 正 确 。 通 过 这 样 的 步 骤 , 系 统 在 并 不 知 道 用 户 密 码 的 明 码 的 情 况 下就 可 以 确 定 用 户 登 录 系 统 的 合 法 性 。 这 不 但 可 以 避 免 用 户 的 密 码 被 具 有 系 统管 理 员 权 限 的 用 户 知 道 , 而 且
8、还 在 一 定 程 度 上 增 加 了 密 码 被 破 解 的 难 度 。 正 是 因 为 这 个 原 因 , 现 在 被 黑 客 使 用 最 多 的 一 种 破 译 密 码 的 方 法 就 是 一种 被 称 为 “跑 字 典 “的 方 法 。 有 两 种 方 法 得 到 字 典 , 一 种 是 日 常 搜 集 的 用 做 密码 的 字 符 串 表 , 另 一 种 是 用 排 列 组 合 方 法 生 成 的 , 先 用 MD5 程 序 计 算 出 这些 字 典 项 的 MD5 值 , 然 后 再 用 目 标 的 MD5 值 在 这 个 字 典 中 检 索 。 我 们 假 设 密码 的 最 大
9、长 度 为 8 位 字 节 ( 8 Bytes) , 同 时 密 码 只 能 是 字 母 和 数 字 , 共26+26+10=62 个 字 符 , 排 列 组 合 出 的 字 典 的 项 数 则 是 P(62,1)+P(62,2).+P(62,8), 那 也 已 经 是 一 个 很 天 文 的 数 字 了 , 存 储 这 个 字 典 就需 要 TB 级 的 磁 盘 阵 列 , 而 且 这 种 方 法 还 有 一 个 前 提 , 就 是 能 获 得 目 标 账 户 的密 码 MD5 值 的 情 况 下 才 可 以 。 这 种 加 密 技 术 被 广 泛 的 应 用 于 UNIX 系 统 中 ,这
10、 也 是 为 什 么 UNIX 系 统 比 一 般 操 作 系 统 更 为 坚 固 一 个 重 要 原 因 。 编 辑 本 段 二 、 算 法 描 述1、 简 介对 MD5 算 法 简 要 的 叙 述 可 以 为 : MD5 以 512 位 分 组 来 处 理 输 入 的 信 息 ,且 每 一 分 组 又 被 划 分 为 16 个 32 位 子 分 组 , 经 过 了 一 系 列 的 处 理 后 , 算 法 的输 出 由 四 个 32 位 分 组 组 成 , 将 这 四 个 32 位 分 组 级 联 后 将 生 成 一 个 128 位散 列 值 。 在 MD5 算 法 中 , 首 先 需 要
11、对 信 息 进 行 填 充 , 使 其 位 长 度 对 512 求 余 的结 果 等 于 448。 因 此 , 信 息 的 位 长 度 ( Bits Length) 将 被 扩 展 至N*512+448, 即 N*64+56 个 字 节 ( Bytes) , N 为 一 个 非 负 整 数 。 填 充 的 方 法如 下 , 在 信 息 的 后 面 填 充 一 个 1 和 无 数 个 0, 直 到 满 足 上 面 的 条 件 时 才 停 止用 0 对 信 息 的 填 充 。 然 后 , 再 在 这 个 结 果 后 面 附 加 一 个 以 64 位 二 进 制 表 示的 填 充 前 信 息 长 度
12、 。 经 过 这 两 步 的 处 理 , 现 在 的 信 息 字 节 长 度=N*512+448+64=(N+1)*512, 即 长 度 恰 好 是 512 的 整 数 倍 。 这 样 做 的 原 因 是为 满 足 后 面 处 理 中 对 信 息 长 度 的 要 求 。 MD5 中 有 四 个 32 位 被 称 作 链 接 变 量 ( Chaining Variable) 的 整 数 参 数 ,他 们 分 别 为 :A=0x01234567, B=0x89abcdef, C=0xfedcba98, D=0x76543210。 当 设 置 好 这 四 个 链 接 变 量 后 , 就 开 始 进
13、入 算 法 的 四 轮 循 环 运 算 。 循 环 的次 数 是 信 息 中 512 位 信 息 分 组 的 数 目 。 将 上 面 四 个 链 接 变 量 复 制 到 另 外 四 个 变 量 中 : A 到 a, B 到 b, C 到c, D 到 d。 主 循 环 有 四 轮 ( MD4 只 有 三 轮 ) , 每 轮 循 环 都 很 相 似 。 第 一 轮 进 行 16次 操 作 。 每 次 操 作 对 a、 b、 c 和 d 中 的 其 中 三 个 作 一 次 非 线 性 函 数 运 算 , 然后 将 所 得 结 果 加 上 第 四 个 变 量 , 文 本 的 一 个 子 分 组 和 一
14、 个 常 数 。 再 将 所 得 结果 向 右 环 移 一 个 不 定 的 数 , 并 加 上 a、 b、 c 或 d 中 之 一 。 最 后 用 该 结 果 取 代a、 b、 c 或 d 中 之 一 。 以 一 下 是 每 次 操 作 中 用 到 的 四 个 非 线 性 函 数 ( 每 轮 一 个 ) 。 F(X,Y,Z) =(X typedef unsigned int uint32; using std:string; using std:ifstream; /* MD5 declaration. */ class MD5 public: MD5(); MD5(const void* i
15、nput, size_t length); MD5(const string MD5(ifstream void update(const void* input, size_t length); void update(const string void update(ifstream const byte* digest(); string toString(); void reset(); private: void update(const byte* input, size_t length); void final(); void transform(const byte bloc
16、k64); void encode(const uint32* input, byte* output, size_t length); void decode(const byte* input, uint32* output, size_t length); string bytesToHexString(const byte* input, size_t length); /* class uncopyable */ MD5(const MD5 MD5 private: uint32 _state4; /* state (ABCD) */ uint32 _count2; /* numbe
17、r of bits, modulo 264 (low-order word first) */ byte _buffer64; /* input buffer */ byte _digest16; /* message digest */ bool _finished; /* calculate finished ? */ static const byte PADDING64; /* padding for calculate */ static const char HEX16; enum BUFFER_SIZE = 1024 ; ; #endif /*MD5_H*/ 2、 CPP 文 件
18、#include “md5.h“ using namespace std; /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15
19、#define S44 21 /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (x) (a) = ROTATE_LEFT (a), (s); (a) += (b); #define GG(a, b, c, d, x, s, ac) (a) += G (b), (c), (d) + (x) + ac; (a) = ROTATE_LEFT (a), (s); (a) += (b); #define HH(a, b, c, d, x, s, ac) (a) += H (b), (c), (d) + (x) + ac; (
20、a) = ROTATE_LEFT (a), (s); (a) += (b); #define II(a, b, c, d, x, s, ac) (a) += I (b), (c), (d) + (x) + ac; (a) = ROTATE_LEFT (a), (s); (a) += (b); const byte MD5:PADDING64 = 0x80 ; const char MD5:HEX16 = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f ; /* Default construct. */ MD5:MD5() reset(); /*
21、Construct a MD5 object with a input buffer. */ MD5:MD5(const void* input, size_t length) reset(); update(input, length); /* Construct a MD5 object with a string. */ MD5:MD5(const string update(str); /* Construct a MD5 object with a file. */ MD5:MD5(ifstream update(in); /* Return the message-digest *
22、/ const byte* MD5:digest() if (!_finished) _finished = true; final(); return _digest; /* Reset the calculate state */ void MD5:reset() _finished = false; /* reset number of bits. */ _count0 = _count1 = 0; /* Load magic initialization constants. */ _state0 = 0x67452301; _state1 = 0xefcdab89; _state2
23、= 0x98badcfe; _state3 = 0x10325476; /* Updating the context with a input buffer. */ void MD5:update(const void* input, size_t length) update(const byte*)input, length); /* Updating the context with a string. */ void MD5:update(const string /* Updating the context with a file. */ void MD5:update(ifst
24、ream std:streamsize length; char bufferBUFFER_SIZE; while (!in.eof() in.read(buffer, BUFFER_SIZE); length = in.gcount(); if (length 0) update(buffer, length); in.close(); /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the cont
25、ext. */ void MD5:update(const byte* input, size_t length) uint32 i, index, partLen; _finished = false; /* Compute number of bytes mod 64 */ index = (uint32)(_count0 3) /* update number of bits */ if (_count0 += (uint32)length 29); partLen = 64 - index; /* transform as many times as possible. */ if (length = partLen) memcpy( transform(_buffer); for (i = partLen; i + 63 length; i += 64) transform( index = 0; else i = 0; /* Buffer remaining input */