算法基础–MD5算法介绍

算法基础–MD5算法介绍MD5 是一种广泛使用的哈希函数 用于生成消息的 128 位摘要 确保数据完整性和防止篡改

大家好,欢迎来到IT知识分享网。

1、简介

  MD5再开发过程中经常碰到的一种算法,因此感觉有必要对其原理进行更深入的了解一下。

2、算法概念

  散列函数,也称作哈希函数,消息摘要函数,单向函数或者杂凑函数。散列函数主要用于验证数据的完整性。通过散列函数,可以创建消息的“数字指纹”,消息接收方可以通过校验消息的哈希值来验证消息的完整性,防止消息被篡改。散列函数具有以下特性:

  • 散列函数的运算过程是不可逆的,这个称为散列函数的单向性。
  • 对于一个已知的消息及其散列值,要找到另外一个消息使其获得相同的散列值是不可能的,这个特性称为散列函数的弱碰撞性。这个特性可以用来防止消息伪造。
  • 任意两个不同消息的散列值一定不同。
  • 对原始消息长度没有限制。
      任何消息经过散列函数处理后,都会产生一个唯一的散列值,这个散列值可以用来验证消息的完整性。计算消息散列值的过程被称为“消息摘要”,计算消息散列值的算法被称为消息摘要算法。MD5算法是Hash算法的一种,叫做消息摘要算法。所谓摘要,从字面意思理解,是指内容的大概。在MD5算法中,这个摘要是指将任意数据映射成一个128位长的摘要信息。并且其是不可逆的,即从摘要信息无法反向推演中原文,在演算过程中,原文的内容也是有丢失的。因为MD5算法最终生成的是一个128位长的数据,从原理上说,有2^128种可能,这是一个非常巨大的数据,约等于3.4乘10的38次方,虽然这个是个天文数字,但是世界上可以进行加密的数据原则上说是无限的,因此是可能存在不同的内容经过MD5加密后得到同样的摘要信息,但这个碰中的概率非常小。
    在这里插入图片描述

3、应用场景

  MD5常用在密码加密中,一般为了保证用户密码的安全,在数据库中存储的都是用户的密码经过MD5加密后的值,在客户端用户输入密码后,也会使用MD5进行加密,这样即使用户的网络被窃听,窃听者依然无法拿到用户的原始密码,并且即使用户数据库被盗,没有存储明文的密码对用户来说也多了一层安全保障。MD5签名技术还常用于防止信息的篡改。使用MD5可以对信息进行签名,接收者拿到信息后只要重新计算签名和原始签名进行对比,即可知道数据信息是否中途被篡改了。

4、算法原理

  假设原始消息长度是b(以bit为单位),注意这里b可以是任意长度,并不一定要是8的整数倍。计算该消息MD5值的过程如下:

 信息填充

   在计算消息的MD5值之前,首先对原始信息进行填充,这里的信息填充分为两步。

  • 填充原始信息:对原始信息进行填充,填充之后,要求信息的长度对512取余等于448。填充的规则如下:假设原始信息长度为b bit,那么在信息的b+1 bit位填充1,剩余的位填充0,直到信息长度对512取余为448。这里有一点需要注意,如果原始信息长度对512取余正好等于448,这种情况仍然要进行填充,很明显,在这时我们要填充的信息长度是512位,直到信息长度对512取余再次等于448。所以,填充的位数最少为1,最大为512。
  • 填充信息长度:填充信息长度,我们需要把原始信息长度转换成以bit为单位,然后在第一步操作的结果后面填充64bit的数据表示原始信息长度。第一步对原始信息进行填充之后,信息长度对512取余结果为448,这里再填充64bit的长度信息,整个信息恰好可以被512整除。其实从后续过程可以看到,计算MD5时,是将信息分为若干个分组进行处理的,每个信息分组的长度是512bit。

 信息处理

  • 信息分组定义
    原始信息经过填充之后,最终得到的信息长度(bit)是512的整数倍,我们先对信息进行分组,每512bit为一个分组,然后再将每个信息分组(512bit)再细分为16个小的分组,每个小分组的长度为32bit。规定如下
  • Mp 代表经过填充之后的信息
  • LM 表示Mp的长度(以bit为单位)
  • N 表示分组个数,N = LM/512
  • M[i] 表示将原始信息进行分组后的第i个信息分组,其中i=1…N
  • X[i] 表示将M[i]进行分组后的第i个小分组,其中i=1…16

 标准幻数定义

 现定义四个标准幻数如下,

  • A = 01 23 45 67
  • B = 89 ab cd ef
  • C = fe dc ba 98
  • D = 76 54 32 10
    在计算机中存储时,采用小端存储方式,以A为例,A在Java中初始化的代码为为A=0x

 常量表T

 T是一个常量表,T[i] = * abs(sin(i))的运算结果取整,其中i=1…64

 辅助方法

 T我们定义四个辅助方法。

  • F(x,y,z) = (x & y) | ((~x) & z)
  • G(x,y,z) = (x & z) | (y & (~z))
  • H(x,y,z) = x ^ y ^ z
  • I(x,y,z) = y ^ (x | (~z))
    其中,x,y,z长度为32bit

5、算法实现

#ifndef SRC_UTIL_MD5_H_ #define SRC_UTIL_MD5_H_ #include <string> #include <iostream> #include <cstdint> namespace toolkit { 
    class MD5 { 
    public: typedef unsigned int size_type; // must be 32bit MD5(); MD5(const std::string& text); void update(const unsigned char *buf, size_type length); void update(const char *buf, size_type length); MD5& finalize(); std::string hexdigest() const; std::string rawdigest() const; friend std::ostream& operator<<(std::ostream&, MD5 md5); private: void init(); typedef uint8_t uint1; // 8bit typedef uint32_t uint4; // 32bit enum { 
   blocksize = 64}; // VC6 won't eat a const static int here void transform(const uint1 block[blocksize]); static void decode(uint4 output[], const uint1 input[], size_type len); static void encode(uint1 output[], const uint4 input[], size_type len); bool finalized; uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk uint4 count[2]; // 64bit counter for number of bits (lo, hi) uint4 state[4]; // digest so far uint1 digest[16]; // the result // low level logic operations static inline uint4 F(uint4 x, uint4 y, uint4 z); static inline uint4 G(uint4 x, uint4 y, uint4 z); static inline uint4 H(uint4 x, uint4 y, uint4 z); static inline uint4 I(uint4 x, uint4 y, uint4 z); static inline uint4 rotate_left(uint4 x, int n); static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); }; } /* namespace toolkit */ #endif /* SRC_UTIL_MD5_H_ */ 
/* interface header */ #include "MD5.h" /* system implementation headers */ #include <cstdio> #include <cstring> namespace toolkit { 
    // 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 #define S44 21 /// // F, G, H and I are basic MD5 functions. inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { 
    return (x&y) | (~x&z); } inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { 
    return (x&z) | (y&~z); } inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { 
    return x^y^z; } inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { 
    return y ^ (x | ~z); } // rotate_left rotates x left n bits. inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { 
    return (x << n) | (x >> (32-n)); } // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 
    a = rotate_left(a+ F(b,c,d) + x + ac, s) + b; } inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 
    a = rotate_left(a + G(b,c,d) + x + ac, s) + b; } inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 
    a = rotate_left(a + H(b,c,d) + x + ac, s) + b; } inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 
    a = rotate_left(a + I(b,c,d) + x + ac, s) + b; } // // default ctor, just initailize MD5::MD5() { 
    init(); } // // nifty shortcut ctor, compute MD5 for string and finalize it right away MD5::MD5(const std::string &text) { 
    init(); update(text.c_str(), text.length()); finalize(); } // void MD5::init() { 
    finalized=false; count[0] = 0; count[1] = 0; // load magic initialization constants. state[0] = 0x; state[1] = 0xefcdab89; state[2] = 0x98badcfe; state[3] = 0x; } // // decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4. void MD5::decode(uint4 output[], const uint1 input[], size_type len) { 
    for (unsigned int i = 0, j = 0; j < len; i++, j += 4) output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); } // // encodes input (uint4) into output (unsigned char). Assumes len is // a multiple of 4. void MD5::encode(uint1 output[], const uint4 input[], size_type len) { 
    for (size_type i = 0, j = 0; j < len; i++, j += 4) { 
    output[j] = input[i] & 0xff; output[j+1] = (input[i] >> 8) & 0xff; output[j+2] = (input[i] >> 16) & 0xff; output[j+3] = (input[i] >> 24) & 0xff; } } // // apply MD5 algo on a block void MD5::transform(const uint1 block[blocksize]) { 
    uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; decode (x, block, blocksize); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0xdb); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0xd8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd); /* 14 */ FF (c, d, a, b, x[14], S13, 0xae); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; // Zeroize sensitive information. memset(x, 0, sizeof x); } // // MD5 block update operation. Continues an MD5 message-digest // operation, processing another message block void MD5::update(const unsigned char input[], size_type length) { 
    // compute number of bytes mod 64 size_type index = count[0] / 8 % blocksize; // Update number of bits if ((count[0] += (length << 3)) < (length << 3)) count[1]++; count[1] += (length >> 29); // number of bytes we need to fill in buffer size_type firstpart = 64 - index; size_type i; // transform as many times as possible. if (length >= firstpart) { 
    // fill buffer first, transform memcpy(&buffer[index], input, firstpart); transform(buffer); // transform chunks of blocksize (64 bytes) for (i = firstpart; i + blocksize <= length; i += blocksize) transform(&input[i]); index = 0; } else i = 0; // buffer remaining input memcpy(&buffer[index], &input[i], length-i); } // // for convenience provide a verson with signed char void MD5::update(const char input[], size_type length) { 
    update((const unsigned char*)input, length); } // // MD5 finalization. Ends an MD5 message-digest operation, writing the // the message digest and zeroizing the context. MD5& MD5::finalize() { 
    static unsigned char padding[64] = { 
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (!finalized) { 
    // Save number of bits unsigned char bits[8]; encode(bits, count, 8); // pad out to 56 mod 64. size_type index = count[0] / 8 % 64; size_type padLen = (index < 56) ? (56 - index) : (120 - index); update(padding, padLen); // Append length (before padding) update(bits, 8); // Store state in digest encode(digest, state, 16); // Zeroize sensitive information. memset(buffer, 0, sizeof buffer); memset(count, 0, sizeof count); finalized=true; } return *this; } // // return hex representation of digest as string std::string MD5::hexdigest() const { 
    if (!finalized) return ""; char buf[33]; for (int i=0; i<16; i++) sprintf(buf+i*2, "%02x", digest[i]); buf[32]=0; return std::string(buf); } std::string MD5::rawdigest() const{ 
    return std::string((char *)digest, sizeof(digest)); } // std::ostream& operator<<(std::ostream& out, MD5 md5) { 
    return out << md5.hexdigest(); } // std::string md5(const std::string str) { 
    MD5 md5 = MD5(str); return md5.hexdigest(); } } /* namespace toolkit */ 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119492.html

(0)
上一篇 2025-11-05 08:26
下一篇 2025-11-05 08:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信