21xrx.com
2025-03-24 04:24:10 Monday
文章检索 我的文章 写文章
C++实现MD5加密算法
2023-06-23 20:20:52 深夜i     19     0
C++ MD5 加密算法

MD5是一种常用的消息摘要算法,能够将任意长度的消息均摊成固定长度的“摘要”或“指纹”,常用于数据完整性校验,数字签名等场景。本文介绍如何使用C++实现MD5加密算法。

MD5算法核心思想是将输入消息按照一定规律分组,每个分组进行一定的变换,最终得到一个固定长度的摘要。具体过程如下:

1. 填充数据

首先需要将输入消息填充至长度为512位的倍数。填充规则是将原消息末尾添加一个1,再添加若干个0,使得填充后的消息长度满足k * 512 + 448,其中k为非负整数。接下来添加一个64位的整数,表示原消息长度的比特数。

2. 初始化状态

MD5算法使用4个32位的寄存器(A, B, C, D)作为状态变量。初始化这些变量需要使用4个固定的常数。

3. 处理分组

将填充后的消息划分为512位一组,共n个分组。对于每一组,将状态变量赋初值,然后进行一系列迭代变换,最终得到新的状态变量值。

4. 输出摘要

将得到的4个32位的状态变量按照一定顺序拼接起来,得到一个128位的MD5摘要。

下面是使用C++实现MD5算法的示例代码:

#include <iostream>
#include <cstring>
#include <cstdint>
using namespace std;
// 循环左移
inline uint32_t left_rotate(uint32_t x, uint32_t n) {
  return (x << n) | (x >> (32 - n));
}
// 初始化状态
void init_state(uint32_t *state) {
  state[0] = 0x67452301;
  state[1] = 0xefcdab89;
  state[2] = 0x98badcfe;
  state[3] = 0x10325476;
}
// 处理分组
void process_block(uint32_t *state, const uint8_t *block) {
  uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
  uint32_t f, g;
  uint32_t x[16];
  // 将分组转换为32位整数数组
  for (int i = 0; i < 16; i++) {
    x[i] = ((uint32_t) block[i * 4 + 0] << 0) |
        ((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++) {
    if (i < 16) {
      f = (b & c) | (~b & d);
      g = i;
    } else if (i < 32) {
      f = (d & b) | (~d & c);
      g = (5 * i + 1) % 16;
    } else if (i < 48) {
      f = b ^ c ^ d;
      g = (3 * i + 5) % 16;
    } else {
      f = c ^ (b | ~d);
      g = (7 * i) % 16;
    }
    uint32_t tmp = d;
    d = c;
    c = b;
    b = b + left_rotate((a + f + x[g] + 0x5a827999), 5);
    a = tmp;
  }
  // 更新状态变量
  state[0] += a;
  state[1] += b;
  state[2] += c;
  state[3] += d;
}
// 计算MD5
void md5(const uint8_t *message, int message_length, uint8_t *digest) {
  uint32_t state[4];
  uint8_t block[64];
  uint64_t message_bits = (uint64_t) message_length * 8;
  // 初始化状态
  init_state(state);
  // 处理分组
  for (int i = 0; i < message_length / 64; i++) {
    memcpy(block, message + i * 64, 64);
    process_block(state, block);
  }
  // 填充最后一块
  int last_block_length = message_length % 64;
  memcpy(block, message + (message_length / 64) * 64, last_block_length);
  block[last_block_length] = 0x80;
  if (last_block_length < 56) {
    memset(block + last_block_length + 1, 0, 56 - last_block_length - 1);
  } else {
    memset(block + last_block_length + 1, 0, 64 - last_block_length - 1);
    process_block(state, block);
    memset(block, 0, 56);
  }
  *((uint64_t *) (block + 56)) = message_bits;
  process_block(state, block);
  // 输出摘要
  memcpy(digest, state, 16);
}
// 将16字节的MD5摘要转换成32字节的十六进制字符串
void digest_to_hex(const uint8_t *digest, char *hex) {
  static const char *hex_chars = "0123456789abcdef";
  for (int i = 0; i < 16; i++) {
    hex[i * 2 + 0] = hex_chars[digest[i] >> 4];
    hex[i * 2 + 1] = hex_chars[digest[i] & 0xf];
  }
  hex[32] = '\0';
}
// 测试程序
int main() {
  uint8_t message[] = "hello md5";
  uint8_t digest[16];
  char hex[33];
  md5(message, sizeof(message) - 1, digest);
  digest_to_hex(digest, hex);
  cout << hex << endl; // 输出16进制的MD5摘要
  return 0;
}

本实现中使用了C++11的一些新特性,如`uint8_t`、`uint32_t`等自定义数据类型,`auto`关键字推断类型等。实现的关键在于`process_block()`函数,它对每个分组进行迭代变换,并更新状态变量。其余细节可以参考代码注释。

总的来说,使用C++实现MD5算法具有以下优点:

1. 性能高,适用于对性能要求较高的场景。

2. 可以自定义数据类型和算法细节,灵活性强。

3. 可以与现有C++项目无缝集成。

当然,C++实现MD5算法也存在一些局限性,如未考虑线程安全、可移植性等问题。因此,需要根据具体场景进行合理选择。

  
  

评论区