run sun 2023-11-01 11:39 采纳率: 100%
浏览 11
已结题

在循环中,输入相同字符,得到的MD5的值却不同,如何解决?

MD5算法如下

#include <iostream>
#include <vector>
#include <cstdlib>
#include <fstream>
#include <string>

using namespace std;

#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476

const char str16[] = "0123456789abcdef";

const unsigned int T[] = {
    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 };

const unsigned int s[] = { 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 };
class MD5 {
private:
    unsigned int tempA, tempB, tempC, tempD, strlength;
public:
    MD5() {
        tempA = A;
        tempB = B;
        tempC = C;
        tempD = D;
        strlength = 0;
    }
    // F函数
    unsigned int F(unsigned int b, unsigned int c, unsigned int d) {
        return (b & c) | ((~b) & d);
    }
    // G函数
    unsigned int G(unsigned int b, unsigned int c, unsigned int d) {
        return (b & d) | (c & (~d));
    }
    // H函数
    unsigned int H(unsigned int b, unsigned int c, unsigned int d) {
        return b ^ c ^ d;
    }
    // I函数
    unsigned int I(unsigned int b, unsigned int c, unsigned int d) {
        return c ^ (b | (~d));
    }
    // 移位操作函数
    unsigned int shift(unsigned int a, unsigned int n) {
        return (a << n) | (a >> (32 - n));
    }
    // 编码函数
    string encode(string src) {
        vector<unsigned int> rec = padding(src);
        for (unsigned int i = 0; i < strlength / 16; i++) {
            unsigned int num[16];
            for (int j = 0; j < 16; j++) {
                num[j] = rec[i * 16 + j];
            }
            iterateFunc(num, 16);
        }
        return format(tempA) + format(tempB) + format(tempC) + format(tempD);
    }
    // 循环压缩
    void iterateFunc(unsigned int* X, int size = 16) {
        unsigned int a = tempA,
            b = tempB,
            c = tempC,
            d = tempD,
            rec = 0,
            g, k;
        for (int i = 0; i < 64; i++) {
            if (i < 16) {
                // F迭代
                g = F(b, c, d);
                k = i;
            }
            else if (i < 32) {
                // G迭代
                g = G(b, c, d);
                k = (1 + 5 * i) % 16;
            }
            else if (i < 48) {
                // H迭代
                g = H(b, c, d);
                k = (5 + 3 * i) % 16;
            }
            else {
                // I迭代
                g = I(b, c, d);
                k = (7 * i) % 16;
            }
            rec = d;
            d = c;
            c = b;
            b = b + shift(a + g + X[k] + T[i], s[i]);
            a = rec;
        }
        tempA += a;
        tempB += b;
        tempC += c;
        tempD += d;
    }
    // 填充字符串
    vector<unsigned int> padding(string src) {
        // 以512位,64个字节为一组
        unsigned int num = ((src.length() + 8) / 64) + 1;
        vector<unsigned int> rec(num * 16);
        strlength = num * 16;
        for (unsigned int i = 0; i < src.length(); i++) {
            // 一个unsigned int对应4个字节,保存4个字符信息
            rec[i >> 2] |= (int)(src[i]) << ((i % 4) * 8);
        }
        // 补充1000...000
        rec[src.length() >> 2] |= (0x80 << ((src.length() % 4) * 8));
        // 填充原文长度
        rec[rec.size() - 2] = (src.length() << 3);
        return rec;
    }
    // 整理输出
    string format(unsigned int num) {
        string res = "";
        unsigned int base = 1 << 8;
        for (int i = 0; i < 4; i++) {
            string tmp = "";
            unsigned int b = (num >> (i * 8)) % base & 0xff;
            for (int j = 0; j < 2; j++) {
                tmp = str16[b % 16] + tmp;
                b /= 16;
            }
            res += tmp;
        }
        return res;
    }
};

测试:

int main() {
    ofstream o;
    MD5 test;
    string a="1";
    string s;
    for (size_t i = 0; i < 3; i++){
        s = test.encode(a);
        cout << s << endl;
    } 
    return 0;
}

MD5算法本身没有问题,单次使用也没有问题,但是一放到循环中就得到错误的答案,请问如何解决?

  • 写回答

3条回答 默认 最新

  • 社区专家-Monster-XH 2023-11-01 11:39
    关注
    • 找到问题了,问题出在你的 MD5 类中。每次计算完一个 MD5 值后,你没有重置 MD5 类中的 tempA, tempB, tempC, 和 tempD 到初始值,所以每次迭代都会保存前一次的结果并累加上去。
    • 你要在 encode 方法的开始处重置这些值。

    修改 encode 方法如下:

    string encode(string src) {
        tempA = A;
        tempB = B;
        tempC = C;
        tempD = D;  // 重置这四个值
        strlength = 0;
        vector<unsigned int> rec = padding(src);
        for (unsigned int i = 0; i < strlength / 16; i++) {
            unsigned int num[16];
            for (int j = 0; j < 16; j++) {
                num[j] = rec[i * 16 + j];
            }
            iterateFunc(num, 16);
        }
        return format(tempA) + format(tempB) + format(tempC) + format(tempD);
    }
    
    • 这样每次调用 encode 方法时,它都会从原始的 A, B, C, 和 D 值开始,确保每次的结果都是正确的。
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 11月9日
  • 已采纳回答 11月1日
  • 创建了问题 11月1日

悬赏问题

  • ¥15 (标签-考研|关键词-set)
  • ¥15 求修改代码,图书管理系统
  • ¥15 请问有没求偏多标签数据集yeast,reference,recreation,scene,health数据集。
  • ¥15 传感网应用开发单片机实训
  • ¥15 Delphi 关于sAlphaImageList使用问题
  • ¥15 寻找将CAJ格式文档转txt文本的方案
  • ¥20 数电设计提问求帮助,出租车计费器
  • ¥15 shein测试开发会问些啥我是写java的
  • ¥15 关于#单片机#的问题:我有个课程项目设计,我想在STM32F103veTX单片机,M3主控模块上设计一个程序,在Keil uVision5(C语言)上代码该怎么编译?(嫌钱少我可以加钱,急急急)
  • ¥15 opnet仿真网络协议遇到问题