『技术群里聊些啥』.NET 如何计算文件 MD5 哈希

前言

有网友在交流群中询问,文件 MD5 是全部读取到内存后计算出来的,还是拿到流就可以计算出来了:

caf3bad291d5c550a220ccd2d423d3a9.png

原理上来说,MD5 需要对全部内容做运算,所以应该是获取所有内容后再计算的。

但是,如果全部读取到内存后再计算,又不太现实,比如读取一个 1T 大小的文件。

Talk Is Cheap. Show Me The Code.

让我们来看看 .NET 中具体是如何实现的。

分析代码

.NET 下计算哈希的方法是ComputeHash:

b1c72dcb5b2a602aeded2aa40c3fd983.png

public byte[] ComputeHash(Stream inputStream)
{if (_disposed)throw new ObjectDisposedException(null);// Use ArrayPool.Shared instead of CryptoPool because the array is passed out.byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);int bytesRead;int clearLimit = 0;while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0){if (bytesRead > clearLimit){clearLimit = bytesRead;}HashCore(buffer, 0, bytesRead);}CryptographicOperations.ZeroMemory(buffer.AsSpan(0, clearLimit));ArrayPool<byte>.Shared.Return(buffer, clearArray: false);return CaptureHashCodeAndReinitialize();
}

通过while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)可以判断出,确实是获取了所有内容。

但是是分段获取的,每次最多只读取 4096 字节(byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);)。

关键是,分段读取出的字节,会合并放到内存中去计算哈希吗?

HashCore

分段读取出的字节是交由HashCore方法处理的。

它的具体实现代码在LiteHash结构中:

public void Append(ReadOnlySpan<byte> data)
{if (data.IsEmpty){return;}Check(Interop.Crypto.EvpDigestUpdate(_ctx, data, data.Length));
}

而调用的 EvpDigestUpdate 是底层 API,看不到源码:

internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl";[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDigestUpdate")]
private static partial int EvpDigestUpdate(SafeEvpMdCtxHandle ctx, ref byte d, int cnt);

在 OpenSSL 官网上,找到了这个 API 的描述:

d处的数据字节哈希到摘要上下文ctx中。可以在同一ctx上多次调用此函数,以对增加的数据进行哈希处理。

也就是说,计算文件哈希实际经过了多次处理。

那如何得到最后的哈希值呢?

CaptureHashCodeAndReinitialize

ComputeHash最后调用 CaptureHashCodeAndReinitialize 方法返回哈希值。

它的具体实现代码也在LiteHash结构中,调用了EvpDigestFinalEx API:

public int Finalize(Span<byte> destination)
{Debug.Assert(destination.Length >= _hashSizeInBytes);uint length = (uint)destination.Length;Check(Interop.Crypto.EvpDigestFinalEx(_ctx, ref MemoryMarshal.GetReference(destination), ref length));Debug.Assert(length == _hashSizeInBytes);return _hashSizeInBytes;
}[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDigestFinalEx")]
internal static partial int EvpDigestFinalEx(SafeEvpMdCtxHandle ctx, ref byte md, ref uint s);

ctx中检索摘要值并将其放在md中。如果s参数不是 NULL,则写入的数据字节数(即摘要的长度)将写入s处。

结论

通过以上分析,可以得出文件 MD5 哈希计算流程如下:

b93945f54ff3190e3bd0f29cd5519974.png

不过,群里又有网友说,不要用 MD5:

a61c1356410b36a18b1c7ab80932623b.png

这又是为什么呢?我们下回分解!

添加微信号【MyIO666】,邀你加入技术交流群

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

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

相关文章

【空间数据库】ArcGIS地理空间数据库GeoDatabase(GDB)概述及建立过程图文详解

地理数据库(Geodatabase)是一种面向对象的数据模型,它对于地理空间特征的表达更接近我们对现实世界的认识。地理数据库在一个公共模型框架下,对GIS处理和表达的空间特征,如适量、栅格、Tin、网络等进行统一描述和存储,是目前最先进的数据管理模式,本文介绍地理数据库的概…

探索发现:平台云——云的新风向

本文讲的是探索发现&#xff1a;平台云——云的新风向&#xff0c;云主机&#xff0c;自2011年火热崛起之后&#xff0c;成为IDC行业替代VPS的完美系列&#xff0c;它的成功在于其相对于VPS的压倒性优势;而平台云凭借其的便捷的操作、实时监控和可视化服务&#xff0c;让站长们…

Android之运行app提示The application could not be installed: INSTALL_FAILED_TEST_ONLY

1、问题 笔记本新安装的Android studio&#xff08;版本3.5.2&#xff09;运行最简单的程序&#xff0c;错误提示如下 The application could not be installed: INSTALL_FAILED_TEST_ONLY 2、分析 高版本的Android studio里面AndroidManifest.xml文件默认如下 android:tes…

windows下配置mysql主从复制_Windows下MySQL主从复制的配置方法

MySQL主从复制允许将来自一个数据库(主数据库)的数据复制到一个或多个数据库(从数据库)。主数据库一般是实时的业务数据写入和更新操作&#xff0c;从数据库常用的读取为主。主从复制过程&#xff1a;1、主服务器上面的任何修改都会通过自己的 I/O tread(I/O 线程)保存在二进制…

【ArcGIS风暴】全国1:100万基础地理数据库获取及ArcGIS图幅完美拼接---以甘肃省为例

在日常工作中,如第三次全国国土调查、不动产登记等,我们总需要对图斑、线状等数据进行数据分幅、图幅拼接等操作。另外,日常学习工作中,无论是制图还是进行分析,都不可避免的需要使用一些基础地理数据,像行政边界、水系、道路、居民地等等,那么,这些基础地理数据有没有…

体验 .NET MAUI RC3 ,马上就要发布RTM

前言.NET MAUI 已经传了很久了&#xff0c; 5月10日&#xff0c;微软终于跟随 VS2022 17.3 预览版 发布了MAUI的候选版本 &#xff0c;今天我们来体验一波。环境运行环境&#xff1a;.Net 6开发环境&#xff1a;VS2022 17.3 &#xff08;必须是预览3&#xff09;使用在安装了V…

WebApi的调用-3.Basic验证

webapi里的特性 /// <summary>/// Basic验证 /// </summary>/// <remarks>/// /// </remarks>public class BasicAuthorizeAttibute : AuthorizeAttribute{public override void OnAuthorization(HttpActionContext actionContext){var authori…

ats 字符集问题

2019独角兽企业重金招聘Python工程师标准>>> 架构很简单&#xff0c;nginx->ats->nginx 后端nginx有做内容替换&#xff0c;字符编码为gb2312&#xff0c;因为ats为utf8编码导致前端内容展示时进行了错误的替换&#xff0c;导致内容错乱。 如 治疗鼻窦炎---&g…

《零基础看得懂的C语言入门教程 》——(十三)socket服务端编写

一、学习目标 了解C语言的socket的概念了解C语言socket的使用方法完成C语言socket服务端 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离学习误区 第二篇&#xff1a;&#xff0…

129. Sum Root to Leaf Numbers

/** 129. Sum Root to Leaf Numbers * 2016-5-21 By Mingyang* dfs包含三种&#xff0c;这里是dfs的preorder方法&#xff0c;先解决根再是左右*/public int sumNumbers(TreeNode root) {return dfs(root, 0);}public int dfs(TreeNode root, int levelBase) {if (root null)r…

Android之Unexpected error while executing: am start -n “***.Activity“-a android.intent.action.MAIN

1 问题 编译项目的时候&#xff0c;as错误提示如下 $ adb shell am start -n "package/package.***Activity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER Unexpected error while executing: am start -n "package/package.***Activ…

古董来了:1999年的物件,香港已经回归了,我都上初中了,那么你出生了吗?

受疫情的影响&#xff0c;哪都去不了&#xff0c;只能在家憋着&#xff08;为社会做贡献&#xff09;这种状态已经持续了将近两个月了。无聊至极的我&#xff0c;一天无所事事&#xff0c;只能是在家这儿瞅瞅&#xff0c;那儿看看&#xff0c;用一句诗经里面的话来形容我最合适…

.NET性能优化-为结构体数组使用StructLinq

前言本系列的主要目的是告诉大家在遇到性能问题时&#xff0c;有哪些方案可以去优化&#xff1b;并不是要求大家一开始就使用这些方案来提升性能。在之前几篇文章中&#xff0c;有很多网友就有一些非此即彼的观念&#xff0c;在实际中&#xff0c;处处都是开发效率和性能之间取…

Android Studio之提示Unable to delete directory ‘*****\MyApplication\app\build‘

1 问题 运行android studio 无论clean project还是rebuild project,提示如下 Unable to delete directory *****\MyApplication\app\buildFailed to delete some children. This might happen because a process has files open or has its working directory set in the tar…

《假如编程是魔法之零基础看得懂的Python入门教程 》——(七)我把魔法变成了积木

学习目标 了解魔法积木的使用——自定义函数了解魔法积木的结果反馈——自定义函数返回值了解魔法积木的原料传递——自定义函数传参了解魔法积木的类型分类——类与对象 推荐 1.《备受好评的看得懂的C语言入门教程》 目录 第一篇&#xff1a;《假如编程是魔法之零基础看得…

关于Activity的getReferrer():如何在Activity中获取调用者?

http://blog.csdn.net/u013553529/article/details/53856800 关于Activity的getReferrer()之一&#xff1a;如何在Activity中获取调用者&#xff1f; http://blog.csdn.net/u013553529/article/details/53882440 关于Activity的getReferrer()之二&#xff1a;调用者的包名是如何…

java之七 高级类设计

static的用法 有时你希望定义一个类成员&#xff0c;使它的使用完全独立于该类的任何对象。通常情况下&#xff0c;类成员必须通过它的类的对象访问&#xff0c;但是可以创建这样一个成员&#xff0c;它能够被它自己使用&#xff0c;而不必引用特定的实例。在成员的声明前面加上…

【遥感数字图像处理】实验:Erdas 软件的认识与使用

Erdas软件下载地址:《GISer福音来了:测绘地理信息类专业软件版本大全汇总下载!》 1.1 简介 ERDAS IMAGINE 是美国 ERDAS(Earth Resource Data Analysis System)公司开发的遥感图像处理系统,它以其先进的图像处理技术,友好、灵活的用户界面和操作方式,面向广阔应用领域…

import 别名_Python基础找茬系列09--import和from-import的引用区别

一、语法区别二、两种导包在内存上的区别一图看懂import与from-import的区别无论是使用import隐式导包还是form-import显示导包&#xff0c;整个模块都会被加载到内存中例如&#xff1a;from test import b,整个模块依旧进入内存&#xff0c;因为如果只有函数b进入内存&#xf…

Android Studio之提示Gradle sync failed: Plugin with id ‘com.novoda.bintray-release‘ not found.

1 问题 导入别人的模块到Android Studio,错误提示如下 Gradle sync failed: Plugin with id com.novoda.bintray-release not found. 2 解决办法 在project的build.gradle里面添加如下 dependencies {classpath com.android.tools.build:gradle:3.5.2//加上下面的代码classp…