MD5算法,c语言(参考其他修改)

https://blog.csdn.net/hla199106/article/details/45129963

https://blog.csdn.net/White3zz/article/details/103130609

#define _CRT_SECURE_NO_WARNINGS

#ifndef MD5_H
#define MD5_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef unsigned char   uint8_t;
typedef unsigned   uint32_t;
typedef unsigned long long   uint64_t;

// MD5压缩函数4轮循环中使用的生成函数,每轮不同
#define F(b, c, d) (((b) & (c)) | ((~b) & (d)))
#define G(b, c, d) (((b) & (d)) | ((c) & (~d)))
#define H(b, c, d) ((b) ^ (c) ^ (d))
#define I(b, c, d) ((c) ^ ((b) | (~d)))

// 循环左移
#define LEFTROTATE(num, n) (((num) << n) | ((num >> (32 - n))))

// 64次迭代运算采用的左循环移位的s值
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
                       };

// T表,32位字,一共有64个元素,对应64次迭代,也成为加法常数
uint32_t T[64];
uint32_t A, B, C, D;
static int Initialized = 0;

void MD5Init()
{
    A = 0x67452301;
    B = 0xefcdab89;
    C = 0x98badcfe;
    D = 0x10325476;

    if (Initialized == 0) {
        Initialized = 1;
        uint64_t n = (uint64_t)1 << 32;
        for (int i = 1; i < 65; i++)
            T[i - 1] = fabs(sin(i) * n); //4294967296UL
    }
}

//  大端形式转换
void int2byte1(uint32_t val, uint8_t *bytes)
{
    bytes[0] = (uint8_t)(val >> 24);
    bytes[1] = (uint8_t)(val >> 16);
    bytes[2] = (uint8_t)(val >> 8);
    bytes[3] = (uint8_t)val;
}

// 两个工具函数 小端形式转换
void int2byte(uint32_t val, uint8_t *bytes)
{
    bytes[0] = (uint8_t)val;
    bytes[1] = (uint8_t)(val >> 8);
    bytes[2] = (uint8_t)(val >> 16);
    bytes[3] = (uint8_t)(val >> 24);
}

uint32_t byte2int(const uint8_t *bytes)
{
    return (uint32_t)bytes[0]
           | ((uint32_t)bytes[1] << 8)
           | ((uint32_t)bytes[2] << 16)
           | ((uint32_t)bytes[3] << 24);
}

// MD5主函数
int StrMD5(const char* str, uint32_t len, char *result)
{
    uint8_t block[64];
    uint8_t* temp = NULL;
    uint32_t X[16];

    MD5Init();

    uint32_t new_len = len + (((len & 0x3F) >= 56) ? (56 + 64 - (len & 0x3F)) : (56 - (len & 0x3F)));

    // 还要增加64bit
    if (!(temp = (uint8_t*)malloc(len + new_len + 8))) return -1;
    memcpy(temp, str, len);

    // 填充1000...0
    temp[len] = 0x80;
    for (uint32_t offset = len + 1; offset < new_len; offset++)
        temp[offset] = 0;

    // 在末尾再附加总长度count的低64位,由于这里的count单位是byte,所以要乘以8
    int2byte(len * 8, temp + new_len);
    int2byte(len >> 29, temp + new_len + 4); //参考了其他代码,count>>29相当于count*8>>32,但可以避免值溢出

    for (uint32_t offset = 0; offset < new_len; offset += 64) {
        memcpy(block, temp + offset, 64);

        // 保存512位的每32位分组,在X[k]时会用到
        for (int i = 0; i < 16; i++) {
            X[i] = byte2int(block + i * 4);
        }

        uint32_t a, b, c, d, temp, g, k;
        a = A, b = B, c = C, d = D;

        // 主循环,共四轮,每轮16次迭代,共64次迭代
        for (int i = 0; i < 64; i++) {
            if (i < 16) {
                g = F(b, c, d);
                k = i;
            } else if (i < 32) {
                g = G(b, c, d);
                k = (1 + 5 * i) % 16;
            } else if (i < 48) {
                g = H(b, c, d);
                k = (5 + 3 * i) % 16;
            } else {
                g = I(b, c, d);
                k = (7 * i) % 16;
            }
            temp = d, d = c, c = b, b = b + LEFTROTATE((a + g + X[k] + T[i]), S[i]), a = temp;
        }
        A += a, B += b, C += c, D += d;
    }
    free(temp);

    uint32_t AA, BB, CC, DD;
    int2byte1(A, (uint8_t*)&AA);
    int2byte1(B, (uint8_t*)&BB);
    int2byte1(C, (uint8_t*)&CC);
    int2byte1(D, (uint8_t*)&DD);
    sprintf( result, "%08X%08X%08X%08X", AA, BB, CC, DD );

    return 0;
}

int FileMD5(const char* filepath, char *result)
{
    FILE *fp = NULL;
    uint8_t buffer[4096], block[64];
    uint8_t* tempstr = NULL;
    size_t count = 0; // count用于记录总长度,补位的时候需要用到
    uint32_t X[16];
    int flag = 0;

    if ((fp = fopen(filepath, "rb+")) == NULL) {
        printf("[ERROR] File in %s not found.", filepath);
        return -1;
    }

    MD5Init();

    while (!feof(fp)) {
        memset(buffer, 0, sizeof(buffer));
        // fread函数返回读取的次数,设定每次读取一个字符,就可以知道字符长度了
        uint32_t len = fread(buffer, 1, 4096, fp);
        // 更新文件总长度
        count += len;
        // 当读取文件到末尾时,意味着需要进行补位操作了,此时读到的len可能不足512bit,也可能刚好等于512bit
        if (feof(fp)) {
            flag = 1;

            // 因为恰好等于448bit不行,所以new_len直接等于len+1
            uint32_t new_len;
            for (new_len = len + 1; new_len % 64 != 56; new_len++);

            // 还要增加64bit
            tempstr = (uint8_t*)malloc(new_len + 8);
            memcpy(tempstr, buffer, len);

            // 填充1000...0
            tempstr[len] = 0x80;
            for (int offset = len + 1; offset < new_len; offset++)
                tempstr[offset] = 0;

            // 在末尾再附加总长度count的低64位,由于这里的count单位是byte,所以要乘以8
            int2byte(count * 8, tempstr + new_len);
            int2byte(count >> 29, tempstr + new_len + 4); //参考了其他代码,count>>29相当于count*8>>32,但可以避免值溢出
            len = new_len;
        }

        // 虽然每次只读取512bit,但是还是采用这样的方式,可以防止最后的一次由于补位导致可能出现的 len > 512bit 的情况(此时就要分两次了)
        for (int offset = 0; offset < len; offset += 64) {
            // 读到结尾时,我们把补位后的数据存在了temp中,为了处理的统一,将temp中的数据保存到buffer上
            if (flag == 1) {
                memcpy(block, tempstr + offset, 64);
            } else {
                memcpy(block, buffer + offset, 64);
            }

            // 保存512位的每32位分组,在X[k]时会用到
            for (int i = 0; i < 16; i++) {
                X[i] = byte2int(block + i * 4);
            }

            uint32_t a, b, c, d, temp, g, k;
            a = A, b = B, c = C, d = D;

            // 主循环,共四轮,每轮16次迭代,共64次迭代
            for (int i = 0; i < 64; i++) {
                if (i < 16) {
                    g = F(b, c, d);
                    k = i;
                } else if (i < 32) {
                    g = G(b, c, d);
                    k = (1 + 5 * i) % 16;
                } else if (i < 48) {
                    g = H(b, c, d);
                    k = (5 + 3 * i) % 16;
                } else {
                    g = I(b, c, d);
                    k = (7 * i) % 16;
                }
                temp = d, d = c, c = b, b = b + LEFTROTATE((a + g + X[k] + T[i]), S[i]), a = temp;
            }
            A += a, B += b, C += c, D += d;
        }
    }
    fclose(fp);
    free(tempstr);

    uint32_t AA, BB, CC, DD;
    int2byte1(A, (uint8_t*)&AA);
    int2byte1(B, (uint8_t*)&BB);
    int2byte1(C, (uint8_t*)&CC);
    int2byte1(D, (uint8_t*)&DD);
    sprintf( result, "%08X%08X%08X%08X", AA, BB, CC, DD );

    return 0;
}

#ifdef __cplusplus
}
#endif

#endif // !MD5_H

//#include "md5.h"
//#include <conio.h>
//
//int main()
//{
//    char result[33];
//
//    const char* str = "你要测试的字符串你要测试的字符串你要测试的字符串你要测试的字符串";
//    if (StrMD5(str, strlen(str), result) == 0) {
//        printf("\n[INFO] The result is: %s\n", result);
//    }
//
//    const char* filepath = "C:\\Users\\wzdyq\\Downloads\\RunningCheeseChrome.7z";
//    if (FileMD5(filepath, result) == 0) {
//        printf("\n[INFO] The result is: %s\n", result);
//    }
//
//    printf("\nPress any key to exit...");
//    _getch();
//
//    return 0;
//}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值