【常见开源库的二次开发】基于openssl的加密与解密——MD5算法源码解析(五)

news2024/9/19 10:40:52

一、MD5算法分析 :

1.1 关于MD5

消息摘要”是指MD5(Message Digest Algorithm 5)算法。MD5是一种广泛使用的密码散列函数,它可以生成一个128位(16字节)的散列值。

RFC 1321: MD5由Ronald Rivest在1992年设计,并通过RFC 1321正式发布。它主要用于确保数据完整性,广泛应用于各种软件和系统中,用于验证数据未被篡改

抗碰撞性攻破: 抗碰撞性是指难以找到两个不同的输入值,使它们通过散列函数产生相同的输出值。2004年,中国的密码学家王小云发现了MD5、SHA-0和其他散列函数的碰撞漏洞,这表明MD5对于安全敏感的应用来说已不再安全。

不再安全: 由于MD5的碰撞漏洞,以及随后发现的更多安全弱点,MD5在安全性要求高的领域(如SSL证书、加密货币等)中已逐渐被其他更安全的算法(如SHA-256)所替代。

如果应用加salt: 加盐(salt)是一种安全措施,常用于存储密码。通过向原始密码添加一段随机数据(salt),然后再进行散列,可以增加破解的难度,减少使用彩虹表等攻击技术的风险。然而,即使加盐,由于MD5本身存在的安全漏洞,它仍然不推荐用于需要高安全性的密码存储。

1.2 算法原理

MD5算法将输入的消息分成512位的块,每个块再分成16个32位(4字节)的子块,命名为M0到M15。算法的核心是四轮处理,每轮使用不同的非线性函数(F、G、H、I),每轮包含16次操作,总共64次操作。

以下是MD5算法中四轮处理的概述:

  1. 第一轮:使用函数F,操作如下:

    FF(a, b, c, d, M0, 7, 0xd76aa478); 
    FF(d, a, b, c, M1, 12, 0xe8c7b756); // 继续处理直到M15
  2. 第二轮:使用函数G,操作如下:

    GG(a, b, c, d, M1, 5, 0xf61e2562); 
    GG(d, a, b, c, M6, 9, 0xc040b340); // 继续处理直到M11
  3. 第三轮:使用函数H,操作如下:

    HH(a, b, c, d, M5, 4, 0xfffa3942); 
    HH(d, a, b, c, M8, 11, 0x8771f681); // 继续处理直到M14
  4. 第四轮:使用函数I,操作如下:

    II(a, b, c, d, M0, 6, 0xf4292244);
    II(d, a, b, c, M7, 10, 0x432aff97); // 继续处理直到M15

在每轮中,函数FF、GG、HH、II分别定义了如何更新四个32位的寄存器(a, b, c, d)。这些函数通常包含一个非线性函数(F, G, H, I),一个常数(ac),一个消息块(x),以及一个位移量(s)。

例如,FF函数的定义可能如下:

#define FF(a, b, c, d, x, s, ac) { \ (a) += F((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT((a), (s)); \ (a) += (b); \ }

这里的F是一个非线性函数,ROTATE_LEFT是一个位移操作,将a左移s位,然后加上b

MD5算法的详细实现可以在RFC 1321文档中找到,该文档提供了算法的完整描述和实现细节。然而,由于MD5的安全性问题,现在推荐使用更安全的散列算法,如SHA-256。

二、MD5接口调用

演示如何使用OpenSSL库计算并输出字符串的MD5哈希值,主要用于学习和教学目的。通过这段代码,可以了解MD5哈希算法的基本使用方法,并学习如何使用OpenSSL库的函数来实现这一算法。

源代码:

#include <iostream>
#include <openssl/md5.h>

using namespace std;

int main() {
    cout << "Test Hash" << endl; // 输出测试信息

    unsigned char data[] = "测试MD5数据"; // 定义要进行MD5哈希的数据
    unsigned char out[MD5_DIGEST_LENGTH] = {0}; // 定义输出数组,大小为MD5哈希结果的长度
    int len = sizeof(data) - 1; // 计算数据长度,减去1是因为sizeof包含字符串末尾的'\0'

    MD5_CTX c; // 定义MD5上下文
    MD5_Init(&c); // 初始化MD5上下文
    MD5_Update(&c, data, len); // 更新MD5上下文,传入数据和数据长度
    MD5_Final(out, &c); // 完成MD5哈希,将结果存储在out数组中

    // 输出MD5哈希结果
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        cout << hex << (int)out[i]; // 以十六进制格式输出每个字节
    }
    cout << endl; // 输出换行符,使结果更清晰

    return 0; // 返回0表示程序成功执行
}

输出测试信息:提示用户程序开始运行。

unsigned char data[] = "测试MD5数据"; // 定义要进行MD5哈希的数据 
unsigned char out[MD5_DIGEST_LENGTH] = {0}; // 定义输出数组,大小为MD5哈希结果的长度 
int len = sizeof(data) - 1; // 计算数据长度,减去1是因为sizeof包含字符串末尾的'\0'

定义输入数据:一个用于计算MD5哈希的字符串。

定义输出数组:存储MD5哈希结果的数组,长度为16字节(MD5_DIGEST_LENGTH)。

计算数据长度sizeof(data) - 1用于获取实际字符串长度,不包括终止符'\0'

MD5_CTX c; // 定义MD5上下文 MD5_Init(&c); // 初始化MD5上下文 
MD5_Update(&c, data, len); // 更新MD5上下文,传入数据和数据长度 
MD5_Final(out, &c); // 完成MD5哈希,将结果存储在out数组中

MD5上下文:使用MD5_CTX结构体来保存MD5计算的中间状态。

初始化MD5上下文:使用MD5_Init函数。

更新MD5上下文:使用MD5_Update函数,将输入数据分块更新到MD5上下文中。

完成MD5哈希:使用MD5_Final函数,将最终的MD5哈希结果存储到输出数组中。

// 输出MD5哈希结果 for (int i = 0; 
i < MD5_DIGEST_LENGTH; i++) 
{ 
    cout << hex << (int)out[i]; // 以十六进制格式输出每个字节 
} 
cout << endl; // 输出换行符,使结果更清晰

输出MD5哈希结果:使用循环遍历输出数组的每个字节,并以十六进制格式输出。

换行符:在输出结束后添加换行符,使输出更整齐。

当我们改变data数组中的某一个值后,我们整个哈希值都会发生改变,修改输入数据的一个字节,然后重新计算该数据的MD5哈希值,并输出结果。通过这种方式,可以观察到数据微小变化对MD5哈希值的影响,从而理解MD5哈希算法的敏感性。

data[1] = 9;
MD5(data,len, out);
for(int i = 0; i < 16; i++)
	cout << hex << (int)out[i];

三、运用MD5 哈希列表(Hash List)验证文件完整性

哈希列表(Hash List)是一种用于验证文件完整性的技术。通过将文件分割成多个块,并对每个块生成哈希值,然后将所有块的哈希值合并再生成一个总的哈希值,可以有效地验证文件是否在传输或存储过程中被篡改

3.1 读取文件并分块

首先,将文件读取并分割成多个固定大小的块。例如,可以将文件分割成1MB的块。

3.2 生成每个块的哈希值

对每个块生成哈希值。常用的哈希算法包括MD5、SHA-1、SHA-256等。

3.3 合并所有块的哈希值

将所有块的哈希值合并成一个总的哈希值。可以采用类似的方式,将所有块的哈希值拼接起来,然后对这个拼接后的数据生成一个总的哈希值。

3.4 验证文件完整性

在文件传输或存储后,重新执行上述步骤,生成新的哈希列表和总的哈希值。比较新生成的总的哈希值与原始的总的哈希值,如果一致,则文件未被篡改;如果不一致,则文件已被篡改。

3.5 演示代码

通过计算文件的MD5哈希值来监控文件的完整性。如果文件被修改,程序会检测到并输出新的哈希值。

源代码:

#include <iostream>
#include <openssl/md5.h>
#include <fstream>
#include <iomanip>
#include <thread>

using namespace std;

// 计算文件的MD5哈希值
string GetFileListHash(const string& filepath)
{
    // 以二进制方式打开文件
    ifstream ifs(filepath, ios::binary);
    if (!ifs) {
        // 如果无法打开文件,输出错误信息并返回空字符串
        cerr << "Failed to open file: " << filepath << endl;
        return "";
    }

    // 定义一次读取的块大小
    int block_size = 128;

    // 定义读取文件的缓冲区
    unsigned char buf[block_size] = { 0 };

    // 定义输出哈希的数组
    unsigned char out[MD5_DIGEST_LENGTH] = { 0 };

    // 定义并初始化MD5上下文
    MD5_CTX c;
    MD5_Init(&c);

    // 读取文件直至文件末尾
    while (!ifs.eof()) {
        ifs.read(reinterpret_cast<char*>(buf), block_size);
        int read_size = ifs.gcount(); // 获取实际读取的字节数
        if (read_size > 0) {
            // 将读取的数据添加到MD5上下文中
            MD5_Update(&c, buf, read_size);
        }
    }

    // 完成MD5计算并将结果存储在out数组中
    MD5_Final(out, &c);
    ifs.close(); // 关闭文件流

    // 将MD5结果转换为字符串并返回
    return string(reinterpret_cast<char*>(out), MD5_DIGEST_LENGTH);
}

// 以十六进制格式输出数据
void PrintHex(const string& data) {
    for (unsigned char c : data) {
        cout << hex << setw(2) << setfill('0') << (int)c;
    }
    cout << endl;
}

int main() {
    cout << "Test Hash" << endl; // 输出测试信息

    unsigned char data[] = "测试MD5数据"; // 定义要进行MD5哈希的数据
    unsigned char out[MD5_DIGEST_LENGTH] = { 0 }; // 定义输出数组,大小为MD5哈希结果的长度
    int len = sizeof(data) - 1; // 计算数据长度,减去1是因为sizeof包含字符串末尾的'\0'

    // 对数据进行MD5哈希计算
    MD5(data, len, out);
    // 输出哈希结果
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        cout << hex << setw(2) << setfill('0') << (int)out[i];
    }
    cout << endl;

    data[1] = 9; // 修改数据
    MD5(data, len, out); // 再次计算MD5哈希
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        cout << hex << setw(2) << setfill('0') << (int)out[i];
    }
    cout << endl;

    string filepath = "/home/book/Desktop/test.txt"; // 文件路径
    auto hash1 = GetFileListHash(filepath); // 计算文件的哈希值
    PrintHex(hash1); // 输出文件哈希值

    // 循环检查文件完整性
    for (;;) {
        auto hash = GetFileListHash(filepath); // 重新计算文件哈希值
        if (hash != hash1) {
            cout << "文件被修改" << endl;
            PrintHex(hash); // 输出新的哈希值
            hash1 = hash; // 更新旧哈希值
        }
        this_thread::sleep_for(1s); // 每秒检查一次
    }

    return 0; // 程序正常结束
}

新建一个txt文件作为存储文件:

文件所形成的哈希值:

当我们改变txt文件中的内容后不断输出文件被修改并且输出修改后文件的哈希值:

函数 GetFileListHash 用于计算指定文件的MD5哈希值。

以二进制模式打开文件。

定义缓冲区 buf 用于读取文件内容。

初始化 MD5 上下文 MD5_CTX

循环读取文件内容并更新 MD5 上下文。

完成 MD5 计算并返回哈希值。

函数 PrintHex 将数据以十六进制格式输出。

遍历输入数据的每个字节。

使用 hexsetw(2) 和 setfill('0') 格式化输出。

初始化并测试 MD5 哈希计算

定义一个字符串 data 进行MD5哈希计算。

输出初始字符串的 MD5 哈希值。

修改字符串 data 并再次计算其 MD5 哈希值。

文件哈希计算与监控

指定文件路径 filepath

计算文件的初始 MD5 哈希值 hash1 并输出。

进入无限循环,不断重新计算文件的 MD5 哈希值,并与初始哈希值进行比较。

如果哈希值发生变化,输出新的哈希值,并更新初始哈希值 hash1

每秒钟检查一次文件的哈希值。

通过计算文件的 MD5 哈希值来监控文件的完整性。它首先进行字符串的 MD5 哈希计算以测试功能,然后进入一个无限循环,定期检查指定文件的 MD5 哈希值。如果检测到文件发生了变化,程序会输出新的哈希值并更新记录的哈希值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1942519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows 磁盘分区样式有几种?如何查看电脑分区样式?

在使用 Windows 操作系统的过程中&#xff0c;磁盘分区是一个重要的概念。磁盘分区的方式直接影响到数据存储和系统运行的效率。磁盘分区的时候也有不同的样式&#xff0c;你知道分区类型有哪些吗&#xff1f;不同的分区样式决定了硬盘的分区方式、可支持的最大存储容量以及兼容…

某企业网络及服务器规划与设计

目录 1. 项目需求与设计... 5 1.1 项目需求... 5 1.2 组建企业网络内部网的流程... 5 1) 构思阶段... 5 2) 方案设计阶段... 6 3) 工程实施阶段... 6 4) 测试验收... 6 5) 管理维护... 7 1.3 技术可行性分析... 7 1.4 网络组网规则... 8 1.5 网络拓扑... 8 2. 项目所…

气膜体育馆内运动舒服吗—轻空间

气膜体育馆作为一种新型的体育设施&#xff0c;以其灵活的结构和高效的功能受到越来越多体育爱好者的青睐。很多人可能会担心在这种环境中运动是否会感到不适。轻空间将从气膜体育馆的结构特点、环境控制和用户体验三个方面&#xff0c;详细分析在气膜体育馆内运动的舒适度。 气…

如何用JavaScript实现视频观看时间追踪

在网页开发中&#xff0c;跟踪用户与多媒体内容&#xff08;如视频&#xff09;的互动是一项常见需求。无论是教育平台、数据分析&#xff0c;还是用户参与度统计&#xff0c;监控用户如何观看视频内容都能提供宝贵的见解。这篇文章将探索如何使用JavaScript实现视频播放时长的…

win10安装ElasticSearch7.x和分词插件

说明&#xff1a; 以下内容整理自网络&#xff0c;格式调整优化&#xff0c;更易阅读&#xff0c;希望能对需要的人有所帮助。 一 安装 Java环境 ElasticSearch使用Java开发的&#xff0c;依赖Java环境&#xff0c;安装 ElasticSearch 7.x 之前&#xff0c;需要先安装jdk-8。…

飞书群聊机器人自定义机器人接入,并实现艾特@群成员功能

飞书群聊机器人还是比钉钉的要麻烦一点&#xff0c;钉钉的直接通过手机号就可以艾特群里面的人&#xff0c;但是飞书的要想艾特群里面的人&#xff0c;需要使用用户的 Open ID 或 User ID。这两个ID怎么获取呢&#xff1f;还需要在飞书的开放平台上创建一个应用&#xff0c;然后…

requets库传data和传json的区别

传data和传json的qubie 被测对象&#xff0c;白月黑羽系统 系统下载地址&#xff1a; https://www.byhy.net/prac/pub/info/bysms/ 测试用例下载地址&#xff1a; https://cdn2.byhy.net/files/selenium/testcases.xlsx 一、传data import json import requests import pytes…

废锡回收处理的生物回收法

废锡回收处理是一个复杂但重要的过程&#xff0c;它有助于节约资源、降低生产成本&#xff0c;并减少环境污染。以下是废锡回收处理的主要方法和相关细节&#xff1a; 一、废锡回收处理的主要方法 1. 化学法回收 酸浸法&#xff1a; 原理&#xff1a;通过加入适量的酸&#xff…

设计模式第二天|设计模式创建型:工厂模式、抽象工厂模式、单例模式、建造者模式

文章目录 设计模式的分类工厂模式简单工厂定义核心俗话说优点缺点具体实现 工厂模式&#xff08;Spring IOC控制反转&#xff09;定义核心**组成****俗话说****实现思路****具体实现****使用场景** 抽象工厂模式**前提概念****定义****缺点****具体实现** 单例模式**定义****俗…

Java---后端事务管理

代码世界聚眸光&#xff0c;昼夜敲盘思绪长。 算法心间精构建&#xff0c;编程路上细思量。 屏前架构乾坤定&#xff0c;键上飞驰智慧扬。 默默耕耘成果现&#xff0c;创新科技铸辉煌。 目录 一&#xff0c;概念 二&#xff0c;Spring事务管理 三&#xff0c;rollbackFor事务回…

深入了解软件架构:组件、容器与模块架构图详解

引言 在软件工程中&#xff0c;架构图是描绘系统结构和组件之间关系的重要工具。其中&#xff0c;组件架构图、子系统依赖分析&#xff08;容器图&#xff09;和模块架构图是三种常用的架构表示方法&#xff0c;它们各有侧重&#xff0c;适用于不同层面的架构分析与设计。本文…

JMeter请求导出Excel

前言 今天记录一个使用JMeter模拟浏览器请求后端导出&#xff0c;并下载Excel到指定位置的过程 创建请求 同样先创建一个线程组&#xff0c;再创建一个请求&#xff0c;设置好请求路径&#xff0c;端口号等 查看结果树 右键--添加--监听器--查看结果树 这里可以查看&#…

C语言 | Leetcode C语言题解之第273题整数转换英文表示

题目&#xff1a; 题解&#xff1a; char* singles[] {"", "One ","Two ","Three ","Four ","Five ","Six ","Seven ","Eight ","Nine "}; char* teens[] {"Ten…

二十、Qt位置相关函数

目录 一、函数概述 二、函数实践 三、总结 一、函数概述 Qt 提供了很多关于获取窗体位置及显示区域大小的函数&#xff0c;如 x()、y()和 pos()、react()、size()、geometry()等&#xff0c;统称为“位置相关函数”或“位置函数”&#xff0c; 如下图所示是几种主要的位置函数…

MybatisPlusException: Error: Method queryTotal execution error of sql 的报错解决

项目场景&#xff1a; 相关背景&#xff1a; 开发环境 开发系统时 系统页面加载正常 &#xff0c;发布运行环境后运行一段时间&#xff0c;前端页面 突然出现 报错信息&#xff0c; 报错信息如下&#xff1a; MybatisPlusException: Error: Method queryTotal execution erro…

gitee的怎么上传项目

前提 1.先下载Git Bash (如果没有下载的宝子们下载连接如下: 链接: link ) 项目上传到Gitee步骤 1.在Gitee上建立远程仓库 2.填写相关信息 3.进入本地你想要上传的文件目录下&#xff0c;右键单击空白处&#xff0c;点击Git Bash Here 4.配置你的用户名和邮箱 git con…

【快速逆向二/无过程/有源码】掌上高考—2024高考志愿填报服务平台

逆向日期&#xff1a;2024.07.21 使用工具&#xff1a;Node.js 加密工具&#xff1a;Crypto-js标准库 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法&…

【JVM基础04】——组成-什么是虚拟机栈?

目录 1- 引言&#xff1a;虚拟机栈1-1 虚拟机栈是什么&#xff1f;(What)1-2 为什么用虚拟机栈&#xff1f;虚拟机栈的作用 (Why) 2- ⭐核心&#xff1a;栈的常见问题(How)2-1 方法内的局部变量是否线程安全&#xff1f;线程不安全的局部变量 2-2 什么情况会导致栈内存溢出&…

数据传输工具性能深度评测(阿里云、百度智能云)

阿里云、百度智能云作为领先的云服务提供商&#xff0c;都为数据库提供了配套的数据库工具服务&#xff0c;其中 DTS 是迁移与同步业务的核心服务&#xff0c;本次测试旨在深入比较阿里云与百度智能云在 DTS 数据传输服务性能方面的表现&#xff0c;为企业在选择合适的数据传输…

电商比价平台的功能讲解及数据采集分析

引言 随着电子商务的快速发展&#xff0c;电商比价平台作为连接消费者与供应商的重要桥梁&#xff0c;其重要性日益凸显。这类平台通过自动化的比价功能&#xff0c;不仅帮助消费者快速找到性价比最高的商品&#xff0c;还为企业提供了高效的采购工具&#xff0c;实现了采购成…