imtoken钱包下载教程|hash

作者: imtoken钱包下载教程
2024-03-07 19:05:50

什么是哈希(Hash)? - 知乎

什么是哈希(Hash)? - 知乎切换模式写文章登录/注册什么是哈希(Hash)?星河·书院混迹IT多年的系统架构师及项目管理者,欢迎学术沟通,其他合作一、什么是 Hash 算法简单来说就是把任意输入 通过特定方式(hash函数) 处理后 生成一个值。这个值等同于存放数据的地址,这个地址里面再吧输入的数据进行存储。这个hash函数又叫散列函数,会有一些常用的构造散列函数的方法,但是处理结果值可能相同,那就叫冲突,冲突也有常用的冲突常用的冲突解决方法。散列算法(Hash Algorithm),又称哈希算法,杂凑算法,是一种从任意文件中创造小的数字「指纹」的方法。与指纹一样,散列算法就是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。因此,当原有文件发生改变时,其标志值也会发生改变,从而告诉文件使用者当前的文件已经不是你所需求的文件。Hash 算法能将将任意长度的二进制明文映射为较短的二进制串的算法,并且不同的明文很难映射为相同的 Hash 值。也可以理解为空间映射函数,是从一个非常大的取值空间映射到一个非常小的取值空间,由于不是一对一的映射,Hash 函数转换后不可逆,意思是不可能通过逆操作和 Hash 值还原出原始的值。散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h(K)(称为散列函数),计算出对应的函数值来,把这个值解释为结点的存储地址,将结点存入到此存储单元中。检索时,用同样的方法计算地址,然后到相应的单元里去取要找的结点。通过散列方法可以对结点进行快速检索。散列(hash,也称“哈希”)是一种重要的存储方式,也是一种常见的检索方法。二、Hash 算法有什么特点Hash 值又称为指纹或者摘要,具有以下特点:正向快速:给定明文和 Hash 算法,在有限时间和有限资源内能计算得到 Hash 值。逆向困难:给定 Hash 值,在有限时间内很难逆推出明文。输入敏感:原始输入信息发生任何变化,新的 Hash 值都应该出现很大变化。冲突避免:很难找到两段内容不同的明文,使得它们的 Hash 值一致。三、Hash 算法有哪些常见 Hash 算法有 MD5 和 SHA 系列,目前 MD5 和 SHA1 已经被破解,一般推荐至少使用 SHA2-256 算法。彩虹表。用来存放所有hash值的部分hash值字典。然后通过碰撞破解密码下面我们来看具体写一个 Hash 函数需要注意些什么,首先要明白 Hash 函数是把一个大范围映射到一个小范围,目的往往是为了节省空间,使得数据容易保存,另外 Hash 函数也会应用于查找上。四、Hash 算法碰撞稍微想一下就可以发现,既然输入数据长度不固定,而输出的哈希值却是固定长度的,这意味着哈希值是一个有限集合,而输入数据则可以是无穷多个,那么建立一对一关系明显是不现实的。所以“碰撞”是必然会发生的,所以一个成熟的哈希算法会有较好的抗冲突性,同时在实现哈希表的结构时也要考虑到哈希冲突的问题。比如“666”经过 Hash 后是“fae0b27c451c728867a567e8c1bb4e53”,相同 Hash 算法得到的值是一样的。比如 WiFi 密码如果是 8 位纯数字的话,顶多就是 99999999 种可能性,破解这个密码需要做的就是提前生成好 0 到 1 亿数字的 Hash 值,然后做 1 亿次布尔运算(就是 Bool 值判断,0 或者 1),而现在普通 I5 四核 CPU 每秒能到达 200 亿次浮点数计算,做 1 亿次布尔运算也就是秒级别的时间就破解了。8位大小写字母、数字、特殊符号组成的密码,若按照MD5加密,则hash值大概10000千亿,i9算力每秒1千亿。也需要至少24h。这只是极端情况下,如果加上加密算法不确定(比如3),请求时间(比如3),查询时间(比如3),这就已经需要半年左右,倘若再加上错误等待时间(比如输入5次错误等待24小时),那就已经需要50年。。。当然,如果有三万台电脑同时破解,也还是一天 -_-|||。不过道高一尺,魔高一丈。谁又会傻乎乎的一个站着打一个等着挨。都是相对的。所以密码尽量不要用纯数字,因为根本没有任何安全性。五、加盐防碰撞对数字内容进行 Hash 运算,获取唯一的摘要值来指代原始完整的数字内容,利用 Hash 函数的抗碰撞性来确保内容未被篡改。常用于用户名和密码来确保用户信息安全,为了防止攻击会采用加盐的方法,就是原来的明文加上一个随机数之后的 Hash 值,Hash 值和盐会保存在两个地方,只要不是同时泄漏就很难被破解。————————————————版权声明:本文为CSDN博主「码墨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:哈希(Hash)算法_码墨-CSDN博客_hash算法发布于 2021-06-15 18:51Hash算法加密​赞同 45​​10 条评论​分享​喜欢​收藏​申请

Hash(散列函数)_百度百科

(散列函数)_百度百科 网页新闻贴吧知道网盘图片视频地图文库资讯采购百科百度首页登录注册进入词条全站搜索帮助首页秒懂百科特色百科知识专题加入百科百科团队权威合作下载百科APP个人中心HASH是一个多义词,请在下列义项上选择浏览(共2个义项)展开添加义项Hash播报讨论上传视频散列函数收藏查看我的收藏0有用+10本词条由“科普中国”科学百科词条编写与应用工作项目 审核 。Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。中文名哈希外文名Hash释    义把任意长度的输入通过散列算法变换成固定长度的输出属    性压缩映射特    点很难找到逆向规律目录1简介2基本概念▪性质▪常用HASH函数▪处理冲突方法▪查找性能分析▪散列函数应用▪哈希函数▪文件的hash值▪hash文件▪userhash3散列表4扩展5命令描述▪语法▪选项说明▪HASH命令简介播报编辑Hash算法可以将一个数据转换为一个标志,这个标志和源数据的每一个字节都有十分紧密的关系。Hash算法还具有一个特点,就是很难找到逆向规律。Hash算法是一个广义的算法,也可以认为是一种思想,使用Hash算法可以提高存储空间的利用率,可以提高数据的查询效率,也可以做数字签名来保障数据传递的安全性。所以Hash算法被广泛地应用在互联网应用中。 [1]Hash算法也被称为散列算法,Hash算法虽然被称为算法,但实际上它更像是一种思想。Hash算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是Hash算法。 [2]基本概念播报编辑若结构中存在和关键字K相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数(Hash function),按这个事先建立的表为散列表。对不同的关键字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),这种现象称碰撞。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数H(key)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象” 作为记录在表中的存储位置,这种表便称为散列表,这一映象过程称为散列造表或散列,所得的存储位置称散列地址。若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突。性质所有散列函数都有如下一个基本特性:如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的。这个特性是散列函数具有确定性的结果。但另一方面,散列函数的输入和输出不是一一对应的,如果两个散列值相同,两个输入值很可能是相同的,但不绝对肯定二者一定相等(可能出现哈希碰撞)。输入一些数据计算出散列值,然后部分改变输入值,一个具有强混淆特性的散列函数会产生一个完全不同的散列值。 [3]典型的散列函数都有无限定义域,比如任意长度的字节字符串,和有限的值域,比如固定长度的比特串。在某些情况下,散列函数可以设计成具有相同大小的定义域和值域间的一一对应。一一对应的散列函数也称为排列。可逆性可以通过使用一系列的对于输入值的可逆“混合”运算而得到。常用HASH函数散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位。常用Hash函数有:1.直接寻址法。取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数)2.数字分析法。分析一组数据,比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。3.平方取中法。取关键字平方后的中间几位作为散列地址。4.折叠法。将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。5.随机数法。选择一随机函数,取关键字作为随机函数的种子生成随机值作为散列地址,通常用于关键字长度不同的场合。6.除留余数法。取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生碰撞。处理冲突方法1.开放寻址法;Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法:1). di=1,2,3,…,m-1,称线性探测再散列;2). di=1^2,-1^2,2^2,-2^2,3^2,…,±k^2,(k<=m/2)称二次探测再散列;3). di=伪随机数序列,称伪随机探测再散列。2. 再散列法:Hi=RHi(key),i=1,2,…,k RHi均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间。3. 链地址法(拉链法)4. 建立一个公共溢出区查找性能分析散列表的查找过程基本上和造表过程相同。一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。在介绍的三种处理冲突的方法中,产生冲突后的查找仍然是给定值与关键码进行比较的过程。所以,对散列表查找效率的量度,依然用平均查找长度来衡量。查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。影响产生冲突多少有以下三个因素:1.散列函数是否均匀;2.处理冲突的方法;3.散列表的装填因子。散列表的装填因子定义为:α= 填入表中的元素个数/散列表的长度α是散列表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。实际上,散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。了解了hash基本定义,就不能不提到一些著名的hash算法,MD5和SHA-1可以说是应用最广泛的Hash算法,而它们都是以MD4为基础设计的。常用hash算法的介绍:(1)MD4MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年设计的,MD 是 Message Digest(消息摘要) 的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于 32位操作数的位操作来实现的。(2)MD5MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。(3)SHA-1及其他SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。 [4]散列函数应用由于散列函数的应用的多样性,它们经常是专为某一应用而设计的。例如,加密散列函数假设存在一个要找到具有相同散列值的原始输入的敌人。一个设计优秀的加密散列函数是一个“单向”操作:对于给定的散列值,没有实用的方法可以计算出一个原始输入,也就是说很难伪造。为加密散列为目的设计的函数,如MD5,被广泛的用作检验散列函数。这样软件下载的时候,就会对照验证代码之后才下载正确的文件部分。此代码有可能因为环境因素的变化,如机器配置或者IP地址的改变而有变动。以保证源文件的安全性。错误监测和修复函数主要用于辨别数据被随机的过程所扰乱的事例。当散列函数被用于校验和的时候,可以用相对较短的散列值来验证任意长度的数据是否被更改过。错误校正使用一个散列函数可以很直观的检测出数据在传输时发生的错误。在数据的发送方,对将要发送的数据应用散列函数,并将计算的结果同原始数据一同发送。在数据的接收方,同样的散列函数被再一次应用到接收到的数据上,如果两次散列函数计算出来的结果不一致,那么就说明数据在传输的过程中某些地方有错误了。这就叫做冗余校验。对于错误校正,假设相似扰动的分布接近最小(a distribution of likely perturbations is assumed at least approximately)。对于一个信息串的微扰可以被分为两类,大的(不可能的)错误和小的(可能的)错误。我们对于第二类错误重新定义如下,假如给定 H(x) 和 x+s,那么只要s足够小,我们就能有效的计算出x。那样的散列函数被称作错误校正编码。这些错误校正编码有两个重要的分类:循环冗余校验和里德所罗门码。语音识别对于像从一个已知列表中匹配一个MP3文件这样的应用,一种可能的方案是使用传统的散列函数——例如MD5,但是这种方案会对时间平移、CD读取错误、不同的音频压缩算法或者音量调整的实现机制等情况非常敏感。使用一些类似于MD5的方法有利于迅速找到那些严格相同(从音频文件的二进制数据来看)的音频文件,但是要找到全部相同(从音频文件的内容来看)的音频文件就需要使用其他更高级的算法了。那些并不紧随IT工业潮流的人往往能反其道而行之,对于那些微小差异足够鲁棒的散列函数确实存在。现存的绝大多数散列算法都是不够鲁棒的,但是有少数散列算法能够达到辨别从嘈杂房间里的扬声器里播放出来的音乐的鲁棒性。有一个实际的例子是Shazam[1]服务。用户可以用电话机拨打一个特定的号码,并将电话机的话筒靠近用于播放音乐的扬声器。该项服务会分析正在播放的音乐,并将它于存储在数据库中的已知的散列值进行比较。用户就能够收到被识别的音乐的曲名(需要收取一定的费用)信息安全Hash算法在信息安全方面的应用主要体以下的3个方面:(1)文件校验我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。MD5 Hash算法的"数字指纹"特性,使它成为应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。(2)数字签名Hash算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。对Hash值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。(3) 鉴权协议如下的鉴权协议又被称作挑战—认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。以上就是一些关于hash以及其相关的一些基本预备知识。哈希函数(1)余数法:先估计整个哈希表中的表项目数目大小。然后用这个估计值作为除数去除每个原始值,得到商和余数。用余数作为哈希值。因为这种方法产生冲突的可能性相当大,因此任何搜索算法都应该能够判断冲突是否发生并提出取代算法。 [1](2)折叠法:这种方法是针对原始值为数字时使用,将原始值分为若干部分,然后将各部分叠加,得到的最后四个数字(或者取其他位数的数字都可以)来作为哈希值。(3)基数转换法:当原始值是数字时,可以将原始值的数制基数转为一个不同的数字。例如,可以将十进制的原始值转为十六进制的哈希值。为了使哈希值的长度相同,可以省略高位数字。(4)数据重排法:这种方法只是简单的将原始值中的数据打乱排序。比如可以将第三位到第六位的数字逆序排列,然后利用重排后的数字作为哈希值。哈希函数并不通用,比如在数据库中用能够获得很好效果的哈希函数,用在密码学或错误校验方面就未必可行。在密码学领域有几个著名的哈希函数。这些函数包括MD2、MD4以及MD5,利用散列法将数字签名转换成的哈希值称为信息摘要(message-digest),另外还有安全散列算法(SHA),这是一种标准算法,能够生成更大的(60bit)的信息摘要,有点儿类似于MD4算法。文件的hash值大家都知道emule是基于P2P(Peer-to-peer的缩写,指的是对等体网络下客户到客户文件传输的软件), 它采用了"多源文件传输协议”(MFTP,the Multisource FileTransfer Protocol)。在协议中,定义了一系列传输、压缩和打包还有积分的标准,emule 对于每个文件都有md5-hash的算法设置,这使得该文件,并且在整个网络上都可以追踪得到。MD5-Hash-文件的数字文摘通过Hash函数计算得到。不管文件长度如何,它的Hash函数计算结果是一个固定长度的数字。与加密算法不同,这一个Hash算法是一个不可逆的单向函数。采用安全性高的Hash算法,如MD5、SHA时,两个不同的文件几乎不可能得到相同的Hash结果。因此,一旦文件被修改,就可检测出来。当我们的文件放到emule里面进行共享发布的时候,emule会根据hash算法自动生成这个文件的hash值,他就是这个文件的身份标志,它包含了这个文件的基本信息,然后把它提交到所连接的服务器。当有他人想对这个文件提出下载请求的时候, 这个hash值可以让他人知道他正在下载的文件是不是就是他所想要的。尤其是在文件的其他属性被更改之后(如名称等)这个值就更显得重要。而且服务器还提供了,这个文件当前所在的用户的地址,端口等信息,这样emule就知道到哪里去下载了。一般来讲我们要搜索一个文件,emule在得到了这个信息后,会向被添加的服务器发出请求,要求得到有相同hash值的文件。而服务器则返回持有这个文件的用户信息。这样我们的客户端就可以直接的和拥有那个文件的用户沟通,看看是不是可以从他那里下载所需的文件。对于emule中文件的hash值是固定的,也是的,它就相当于这个文件的信息摘要,无论这个文件在谁的机器上,他的hash值都是不变的,无论过了多长时间,这个值始终如一,当我们在进行文件的下载上传过程中,emule都是通过这个值来确定文件。hash文件我们经常在emule日志里面看到,emule正在hash文件,这里就是利用了hash算法的文件校验性这个功能了,文章前面已经说了一些这些功能,其实这部分是一个非常复杂的过程,在ftp,bt等软件里面都是用的这个基本原理,emule里面是采用文件分块传输,这样传输的每一块都要进行对比校验,如果错误则要进行重新下载,这期间这些相关信息写入met文件,直到整个任务完成,这个时候part文件进行重新命名,然后使用move命令,把它传送到incoming文件里面,然后met文件自动删除,所以我们有的时候会遇到hash文件失败,就是指的是met里面的信息出了错误不能够和part文件匹配,另外有的时候开机也要疯狂hash,有两种情况一种是你在第一次使用,这个时候要hash提取所有文件信息,还有一种情况就是上一次你非法关机,那么这个时候就是要进行排错校验了。关于hash的算法研究,一直是信息科学里面的一个前沿,尤其在网络技术普及的,他的重要性越来越突出,其实我们每天在网上进行的信息交流安全验证,我们在使用的操作系统密钥原理,里面都有它的身影,特别对于那些研究信息安全有兴趣的朋友,这更是一个打开信息世界的钥匙,他在hack世界里面也是一个研究的焦点。userhash道理同上,当我们在第一次使用emule的时候,emule会自动生成一个值,这个值也是的,它是我们在emule世界里面的标志,只要你不卸载,不删除config,你的userhash值也就永远不变,积分制度就是通过这个值在起作用,emule里面的积分保存,身份识别,都是使用这个值,而和你的id和你的用户名无关,你随便怎么改这些东西,你的userhash值都是不变的,这也充分保证了公平性。其实他也是一个信息摘要,只不过保存的不是文件信息,而是我们每个人的信息。散列表播报编辑散列表是散列函数的一个主要应用,使用散列表能够快速的按照关键字查找数据记录。(注意:关键字不是像在加密中所使用的那样是秘密的,但它们都是用来“解锁”或者访问数据的。)例如,在英语字典中的关键字是英文单词,和它们相关的记录包含这些单词的定义。在这种情况下,散列函数必须把按照字母顺序排列的字符串映射到为散列表的内部数组所创建的索引上。散列表散列函数的几乎不可能/不切实际的理想是把每个关键字映射到的索引上(参考散列),因为这样能够保证直接访问表中的每一个数据。一个好的散列函数(包括大多数加密散列函数)具有均匀的真正随机输出,因而平均只需要一两次探测(依赖于装填因子)就能找到目标。同样重要的是,随机散列函数几乎不可能出现非常高的冲突率。但是,少量的可以估计的冲突在实际状况下是不可避免的(参考生日悖论)。在很多情况下,heuristic散列函数所产生的冲突比随机散列函数少的多。Heuristic函数利用了相似关键字的相似性。例如,可以设计一个heuristic函数使得像FILE0000.CHK,FILE0001.CHK,FILE0002.CHK,等等这样的文件名映射到表的连续指针上,也就是说这样的序列不会发生冲突。相比之下,对于一组好的关键字性能出色的随机散列函数,对于一组坏的关键字经常性能很差,这种坏的关键字会自然产生而不仅仅在攻击中才出现。性能不佳的散列函数表意味着查找操作会退化为费时的线性搜索。散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 [5]扩展播报编辑MD5、SHA1的破解2004年8月17日,在美国加州圣芭芭拉召开的国际密码大会上,山东大学王小云教授在国际会议上首次宣布了她及她的研究小组的研究成果——对MD5、HAVAL-128、MD4和RIPEMD四个著名密码算法的破译结果。次年二月宣布破解SHA-1密码。命令描述播报编辑Linux命令——hashhash命令用来显示、添加和清除哈希表。该命令的语法格式如下所示。语法hash [-l] [-r] [-p ] [-t ]选项说明选项说明-l显示哈希表,包括路径-r清除哈希表-p 向哈希表中增加内容-t 显示指定命令的完整路径HASH命令hash 每次传输完数据缓冲区中的数据后就显示一个#号新手上路成长任务编辑入门编辑规则本人编辑我有疑问内容质疑在线客服官方贴吧意见反馈投诉建议举报不良信息未通过词条申诉投诉侵权信息封禁查询与解封©2024 Baidu 使用百度前必读 | 百科协议 | 隐私政策 | 百度百科合作平台 | 京ICP证030173号 京公网安备110000020000

在线哈希值计算

在线哈希值计算

文库

字符

转换

加密

网络

更多

图表

数学

坐标

图片

文件

文库

字符

转换

加密

网络

更多

图表

数学

坐标

图片

文件

在线工具大全

首页

加密

工具

21

评论

收藏

复制链接

分享

在线哈希值计算

标签

前端后端硬件开发哈希

输入内容

上传文件

内容格式

String

Hex

Base64

字符集

ASCII

UTF-8

UTF-16

UTF-32

GBK

GB2312

GB18030

ISO-8859-1

哈希算法

MD2

MD4

MD5

SHA1

SHA224

SHA256

SHA384

SHA512

SHA3-224

SHA3-256

SHA3-384

SHA3-512

计算

清空

计算结果(HEX)

复制

计算结果(Base64)

复制

相关工具

MD5加密

文件HASH计算

在线哈希值计算-工具简介

在线计算文本和文件的哈希值,计算支持MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512,SHA3-224,SHA3-256,SHA3-384,SHA3-512算法。输入数据支持string,hex,base64字符串或者文件,计算对应数据的哈希值,计算结果表示为十六进制字符串和base64字符串。

在线哈希值计算-使用说明

哈希,一般也称散列。是把任意长度的输入数据通过哈希算法变换成固定长度的输出,该输出结果就是哈希值。

上传文件:计算文件的哈希值,支持任意类型的文件,最大支持5MB,打开文件后,内容格式将被自动设置为Hex。

内容格式:输入内容的格式,支持String字符串,Hex十六进制字符串,Base64字符串格式。

字符集:如果内容格式为String,输入内容将使用该字符集转换为字节数组。

哈希算法:将使用选定的哈希算法,计算输入数据的哈希值。当前支持的哈希算法有:MD2,MD4,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3-224,SHA3-256,SHA3-384,SHA3-512。

计算结果(HEX):哈希计算结果的十六进制字符串表示。

计算结果(Base64):哈希计算结果的Base64字符串表示。

© 2020-2024 LDDGO.NET

版权所有

站点地图

苏ICP备20039521号-1

联系方式

简体中文

常见的hash算法及其原理_哈希算法-CSDN博客

>

常见的hash算法及其原理_哈希算法-CSDN博客

常见的hash算法及其原理

最新推荐文章于 2023-12-11 20:38:51 发布

Beyond_2016

最新推荐文章于 2023-12-11 20:38:51 发布

阅读量10w+

收藏

531

点赞数

90

分类专栏:

数据结构与算法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/Beyond_2016/article/details/81286360

版权

数据结构与算法

专栏收录该内容

30 篇文章

4 订阅

订阅专栏

 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

  哈希表是根据设定的哈希函数H(key)和处理冲突方法将一组关键字映射到一个有限的地址区间上,并以关键字在地址区间中的象作为记录在表中的存储位置,这种表称为哈希表或散列,所得存储位置称为哈希地址或散列地址。作为线性数据结构与表格和队列等相比,哈希表无疑是查找速度比较快的一种。

  通过将单向数学函数(有时称为“哈希算法”)应用到任意数量的数据所得到的固定大小的结果。如果输入数据中有变化,则哈希也会发生变化。哈希可用于许多操作,包括身份验证和数字签名。也称为“消息摘要”。

  简单解释:哈希(Hash)算法,即散列函数。它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程。同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出。哈希函数的这种单向特征和输出数据长度固定的特征使得它可以生成消息或者数据。

  

  常用hash算法的介绍:

  (1)MD4

  MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年设计的,MD 是 Message Digest(消息摘要) 的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于 32位操作数的位操作来实现的。

  (2)MD5

  MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。

  (3)SHA-1及其他

  SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。

  常见hash算法的原理

  散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙。

  散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

  比如我们存储70个元素,但我们可能为这70个元素申请了100个元素的空间。70/100=0.7,这个数字称为负载因子。我们之所以这样做,也是为了“快速存取”的目的。我们基于一种结果尽可能随机平均分布的固定函数H为每个元素安排存储位置,这样就可以避免遍历性质的线性搜索,以达到快速存取。但是由于此随机性,也必然导致一个问题就是冲突。所谓冲突,即两个元素通过散列函数H得到的地址相同,那么这两个元素称为“同义词”。这类似于70个人去一个有100个椅子的饭店吃饭。散列函数的计算结果是一个存储单位地址,每个存储单位称为“桶”。设一个散列表有m个桶,则散列函数的值域应为[0,m-1]。

  解决冲突是一个复杂问题。   冲突主要取决于:

  (1)散列函数,一个好的散列函数的值应尽可能平均分布。

  (2)处理冲突方法。

  (3)负载因子的大小。太大不一定就好,而且浪费空间严重,负载因子和散列函数是联动的。

  解决冲突的办法:

  (1)线性探查法:冲突后,线性向前试探,找到最近的一个空位置。缺点是会出现堆积现象。存取时,可能不是同义词的词也位于探查序列,影响效率。

  (2)双散列函数法:在位置d冲突后,再次使用另一个散列函数产生一个与散列表桶容量m互质的数c,依次试探(d+n*c)%m,使探查序列跳跃式分布。

  常用的构造散列函数的方法

  散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位:

  1. 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a?key + b,其中a和b为常数(这种散列函数叫做自身函数)

  2. 数字分析法:分析一组数据,比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。

  3. 平方取中法:取关键字平方后的中间几位作为散列地址。

  4. 折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。

  5. 随机数法:选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。

  6. 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p《=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

  查找的性能分析

  散列表的查找过程基本上和造表过程相同。一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。在介绍的三种处理冲突的方法中,产生冲突后的查找仍然是给定值与关键码进行比较的过程。所以,对散列表查找效率的量度,依然用平均查找长度来衡量。

  查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。影响产生冲突多少有以下三个因素:

  1. 散列函数是否均匀;

  2. 处理冲突的方法;

  3. 散列表的装填因子。

  散列表的装填因子定义为:α= 填入表中的元素个数 / 散列表的长度

  α是散列表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。

  实际上,散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。

  了解了hash基本定义,就不能不提到一些著名的hash算法,MD5 和 SHA-1 可以说是目前应用最广泛的Hash算法,而它们都是以 MD4 为基础设计的。那么他们都是什么意思呢?

  这里简单说一下:

  (1) MD4

  MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。

  (2) MD5

  MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好

  (3) SHA-1 及其他

  SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。

  哈希表不可避免冲突(collision)现象:对不同的关键字可能得到同一哈希地址 即key1≠key2,而hash(key1)=hash(key2)。因此,在建造哈希表时不仅要设定一个好的哈希函数,而且要设定一种处理冲突的方法。可如下描述哈希表:根据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的“象”作为相应记录在表中的存储位置,这种表被称为哈希表。

  对于动态查找表而言,1) 表长不确定;2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字。因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的位置,通常称这个函数f(key)为哈希函数。(注意:这个函数并不一定是数学函数)

  哈希函数是一个映象,即:将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的大小不超出允许范围即可。

  现实中哈希函数是需要构造的,并且构造的好才能使用的好。

  那么这些Hash算法到底有什么用呢?

  Hash算法在信息安全方面的应用主要体现在以下的3个方面:

  

  (1) 文件校验

  我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。

  MD5 Hash算法的“数字指纹”特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。

  (2) 数字签名

  Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。 对 Hash 值,又称“数字摘要”进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。

  (3) 鉴权协议

  如下的鉴权协议又被称作挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。

  文件hash值

  MD5-Hash-文件的数字文摘通过Hash函数计算得到。不管文件长度如何,它的Hash函数计算结果是一个固定长度的数字。与加密算法不同,这一个Hash算法是一个不可逆的单向函数。采用安全性高的Hash算法,如MD5、SHA时,两个不同的文件几乎不可能得到相同的Hash结果。因此,一旦文件被修改,就可检测出来。

  Hash函数还有另外的含义。实际中的Hash函数是指把一个大范围映射到一个小范围。把大范围映射到一个小范围的目的往往是为了节省空间,使得数据容易保存。除此以外,Hash函数往往应用于查找上。所以,在考虑使用Hash函数之前,需要明白它的几个限制:

  1. Hash的主要原理就是把大范围映射到小范围;所以,你输入的实际值的个数必须和小范围相当或者比它更小。不然冲突就会很多。

  2. 由于Hash逼近单向函数;所以,你可以用它来对数据进行加密。

  3. 不同的应用对Hash函数有着不同的要求;比如,用于加密的Hash函数主要考虑它和单项函数的差距,而用于查找的Hash函数主要考虑它映射到小范围的冲突率。

  应用于加密的Hash函数已经探讨过太多了,在作者的博客里面有更详细的介绍。所以,本文只探讨用于查找的Hash函数。

  Hash函数应用的主要对象是数组(比如,字符串),而其目标一般是一个int类型。以下我们都按照这种方式来说明。

  一般的说,Hash函数可以简单的划分为如下几类:

  1. 加法Hash;

  2. 位运算Hash;

  3. 乘法Hash;

  4. 除法Hash;

  5. 查表Hash;

  6. 混合Hash;

  下面详细的介绍以上各种方式在实际中的运用。

  一 加法Hash

  所谓的加法Hash就是把输入元素一个一个的加起来构成最后的结果。标准的加法Hash的构造如下:

  static int additiveHash(String key, int prime)

  {

  int hash, i;

  for (hash = key.length(), i = 0; i 《 key.length(); i++)

  hash += key.charAt(i);

  return (hash % prime);

  }

  这里的prime是任意的质数,看得出,结果的值域为[0,prime-1]。

  二 位运算Hash

  这类型Hash函数通过利用各种位运算(常见的是移位和异或)来充分的混合输入元素。比如,标准的旋转Hash的构造如下:

  static int rotatingHash(String key, int prime)

  {

  int hash, i;

  for (hash=key.length(), i=0; i

  hash = (hash《《4》》28)^key.charAt(i);

  return (hash % prime);

  }

  先移位,然后再进行各种位运算是这种类型Hash函数的主要特点。比如,以上的那段计算hash的代码还可以有如下几种变形:

  hash = (hash《《5》》27)^key.charAt(i);

  hash += key.charAt(i);

  hash += (hash 《《 10);

  hash ^= (hash 》》 6);

  if((i&1) == 0)

  {

  hash ^= (hash《《7》》3);

  }

  else

  {

  hash ^= ~((hash《《11》》5));

  }

  hash += (hash《《5》

  hash = key.charAt(i) + (hash《《6》》16) ? hash;

  hash ^= ((hash《《5》》2));

  三 乘法Hash

  这种类型的Hash函数利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。比如,

  static int bernstein(String key)

  {

  int hash = 0;

  int i;

  for (i=0; i

  return hash;

  }

  jdk5.0里面的String类的hashCode()方法也使用乘法Hash。不过,它使用的乘数是31。推荐的乘数还有:131, 1313, 13131, 131313等等。

  使用这种方式的著名Hash函数还有:

  // 32位FNV算法

  int M_SHIFT = 0;

  public int FNVHash(byte[] data)

  {

  int hash = (int)2166136261L;

  for(byte b : data)

  hash = (hash * 16777619) ^ b;

  if (M_SHIFT == 0)

  return hash;

  return (hash ^ (hash 》》 M_SHIFT)) & M_MASK;

  }

  以及改进的FNV算法:

  public static int FNVHash1(String data)

  {

  final int p = 16777619;

  int hash = (int)2166136261L;

  for(int i=0;i

  hash = (hash ^ data.charAt(i)) * p;

  hash += hash 《《 13;

  hash ^= hash 》》 7;

  hash += hash 《《 3;

  hash ^= hash 》》 17;

  hash += hash 《《 5;

  return hash;

  }

  除了乘以一个固定的数,常见的还有乘以一个不断改变的数,比如:

  static int RSHash(String str)

  {

  int b = 378551;

  int a = 63689;

  int hash = 0;

  for(int i = 0; i 《 str.length(); i++)

  {

  hash = hash * a + str.charAt(i);

  a = a * b;

  }

  return (hash & 0x7FFFFFFF);

  }

  虽然Adler32算法的应用没有CRC32广泛,不过,它可能是乘法Hash里面最有名的一个了。关于它的介绍,大家可以去看RFC 1950规范。

  四 除法Hash

  除法和乘法一样,同样具有表面上看起来的不相关性。不过,因为除法太慢,这种方式几乎找不到真正的应用。需要注意的是,我们在前面看到的hash的 结果除以一个prime的目的只是为了保证结果的范围。如果你不需要它限制一个范围的话,可以使用如下的代码替代”hash%prime”: hash = hash ^ (hash》》10) ^ (hash》》20)。

  五 查表Hash

  查表Hash最有名的例子莫过于CRC系列算法。虽然CRC系列算法本身并不是查表,但是,查表是它的一种最快的实现方式。下面是CRC32的实现:

  static int crctab[256] = {

  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,

  0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,

  0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,

  0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,

  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,

  0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,

  0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,

  0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,

  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,

  0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,

  0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,

  0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,

  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,

  0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,

  0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,

  0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,

  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,

  0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43,

  0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,

  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c,

  0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,

  0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,

  0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,

  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd,

  0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,

  0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,

  0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,

  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e,

  0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d

  };

  int crc32(String key, int hash)

  {

  int i;

  for (hash=key.length(), i=0; i

  hash = (hash 》》 8) ^ crctab[(hash & 0xff) ^ k.charAt(i)];

  return hash;

  }

  查表Hash中有名的例子有:Universal Hashing和Zobrist Hashing。他们的表格都是随机生成的。

  六 混合Hash

  混合Hash算法利用了以上各种方式。各种常见的Hash算法,比如MD5、Tiger都属于这个范围。它们一般很少在面向查找的Hash函数里面使用。

优惠劵

Beyond_2016

关注

关注

90

点赞

531

收藏

觉得还不错?

一键收藏

知道了

3

评论

常见的hash算法及其原理

 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。  哈希表是根据设定...

复制链接

扫一扫

专栏目录

最常用的三种哈希算法

上道的程序员

05-17

3万+

散列算法(Hash Algorithm),又称哈希算法,Hash算法能将将任意长度的二进制明文映射为较短的二进制串的算法,并且不同的明文很难映射为相同的Hash值。也可以理解为空间映射函数,是从一个非常大的取值空间映射到一个非常小的取值空间,由于不是一对一的映射,Hash函数转换后不可逆,意思是不可能通过逆操作和Hash值还原出原始的值。

散列方法的主要思想是根据结点的关键码值来确定其存储地址:...

混沌密码学原理及其应用课件(PDF)

04-08

《混沌密码学原理及其应用》讲述了:混沌密码学是非线性科学与密码学交叉融合的一门新的科学。《混沌密码学原理及其应用》取材新颖,概念清晰,书中不仅介绍了数字混沌学所涉及的基础理论和各种代表性的算法,同时也涵盖了混沌密码学的最新研究成果,以及本学科最新的发展方向。《混沌密码学原理及其应用》全面而详细地介绍了混沌密码学的理论和相关算法。全书共分为6章,包括混沌理论与密码学基础、基于混沌的分组密码、基于混沌的流密码、混沌公钥密码技术、混沌Hash函数、混沌密码学的安全应用等内容。

3 条评论

您还未登录,请先

登录

后发表或查看评论

hash算法原理详解

热门推荐

至道

05-19

24万+

一.概念

哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。

哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。

使用哈希查找有两个步骤:

1. 使用哈希函数将被

HashMap的底层工作原理(详细版)

最新发布

m0_73647713的博客

12-11

969

HashMap的一些特性:譬如HashMap可以接受null键值和值,而HashTable则不能;HashMap是非synchronized;HashMap很快;以及HashMap储存的是键值对等等这一些都是必须知道的。下面来深入了解HashMap的底层工作原理:1 HashMap 的存储机制a在 Java 1.8 中,如果链表的长度超过了 8且数组长度最小要达到64 ,那么链表将转化为红黑树;链表长度低于6,就把红黑树转回链表;

哈希算法简介与常见的哈希生成算法

qq_44684427的博客

11-29

3944

哈希算法简介与常见的哈希生成算法什么是哈希算法哈希哈希表key值与位置的映射关系常见的哈希生成算法折叠法移位叠加边界叠加平方取中法进制转换法取模法伪随机数法哈希算法的特点哈希算法的应用

什么是哈希算法

哈希

哈希(hash)也被称之为散列,是指将任意长度的输入的数据按照某种规则(哈希算法)来变为定长的输出的方式。这个输出也被称之为哈希(散列)值。

哈希表

哈希表(散列表)是一种根据关键码值key来...

密码学基础(一)——哈希算法

奔跑的蜗牛_Kieasr

10-06

4799

由于哈希算法的单向性,可以从前一个数据块原文计算出下一个数据块所用的哈希值输入,但已知一个哈希值输入,难以反推出所有可能的数据块原文。哈希算法:哈希算法不可逆,包括:MD4、MD5、hash1、ripeMD160、SHA256、SHA3、Keccak256、国家标准SM3(国家密码管理局)哈希加“盐”(salt),所谓加“盐”,就是在明文的随机位置加上一串随机的字符串再进行hash,防止彩虹表攻击。加密/解密算法:加密解密算法可逆,但是必须要有秘钥,对称加密,非对称加密,数字签名算法DSA。

哈希算法(哈希函数)基本

AlbenXie的博客

02-01

4258

哈希也称“散列”函数或“杂凑”函数。它是一个不可逆的单向映射,将任意长度的输入消息M(或文件F)映射成为一个较短的定长哈希值H(M),也叫散列值(HashValue)、杂凑值或消息摘要。可见,这是一种单向密码体制,只有加密过程,没有解密过程(因此Hash求逆很困难)。二、哈希的原理和特点单向性:从哈希值不能反向推导原始数据(计算不可行),即从哈希输出无法倒推输入的原始数值。这是哈希函数安全性的基础。灵敏性:对输入数据敏感,哪怕只改了一个Bit,得到的哈希值也大不相同。

哈希(Hash)算法

码墨

11-15

4万+

一、什么是 Hash 算法

散列算法(Hash Algorithm),又称哈希算法,杂凑算法,是一种从任意文件中创造小的数字「指纹」的方法。与指纹一样,散列算法就是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。因此,当原有文件发生改变时,其标志值也会发生改变,从而告诉文件使用者当前的文件已经不是你所需求的文件。

Hash 算法能将将任意长度的二进制...

hash算法详解

Rocky006的博客

06-13

4467

散列算法(Hash Algorithm),又称哈希算法,杂凑算法,是一种从任意文件中创造小的数字「指纹」的方法。与指纹一样,散列算法就是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。因此,当原有文件发生改变时,其标志值也会发生改变,从而告诉文件使用者当前的文件已经不是你所需求的文件。

哈希算法详解

qq_16570607的博客

07-11

2万+

前言

哈希(Hash)或者说散列表,它是一种基础数据结构。Hash 表是一种特殊的数据结构,它同数组、链表以及二叉排序树等相比较有很明显的区别,但它又是是数组和链表的基础上演化而来,既具有数组的有点,又具有链表的有点。能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找。应用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找。

Hash设计思想

试想如果我们对一个数组进行查询,这个数组里,每一个元素都是一个字符串。我们知道数组最快的检索办法是通过数组的

关于Java的Hash算法的深入理解

sinat_31011315的博客

12-03

3万+

我们眼中的哈希

在计算机领域中哈希涉及的范围非常广泛,而且是较长使用的一种算法和数据结构,对此我们在后端开发中不断地使用由jdk提供的方法进行使用。由于长时间的使用,很少人会去对里面的核心进行分析和学习。HashMap是通过一个Entry的数组实现的。而Entry的结构有三个属性,key,value,next。如果在c中,我们遇到next想到的必然是指针,其实在java这就是个指针。每次通过ha

hash算法

HueyLong的博客

11-21

1766

一、hash算法的一些基础知识

概念:hash算法根据一个数的值通过hash函数来确定其存储的位置,尽可能的达到存储和查找都能是O(1)的复杂度

计算hash函数的几种方法:

1、直接取值法

取关键数的某个线性函数作为存储位置

2、取模寻址法

将关键值除以一个固定数,获取余数作为存储位置

但是这两种方法都存在一定的冲突问题,所以需要一些解决冲突的方法:

1、开放寻址法

当存在冲突时,根据获取到的存储位置,顺序寻找不超过hash表长度的存储位置

2、拉链法

将存在冲突的关键值,存储的一个链表中,来解决冲突

Matlab实现感知哈希算法

11-12

参考网上博客的感知哈希算法的理论知识,实现基本的感知哈希算法,内有几张图片用来测试,程序可参考。

混沌密码学原理及其应用

05-12

《混沌密码学原理及其应用》取材新颖,概念清晰,书中不仅介绍了数字混沌学所涉及的基础理论和各种代表性的算法,同时也涵盖了混沌密码学的最新研究成果,以及本学科最新的发展方向。《混沌密码学原理及其应用》全面...

ACM算法竞赛常用代码

11-13

数据结构(广度优先搜索,验证括号匹配,表达式计算,递归的编译,Hash表,分段Hash,并查集,Tarjan算法,二叉堆,左偏树,二斜堆,二项堆,二叉查找树,红黑树,AVL平衡树,Treap,Splay,静态二叉查找树,2-d树,...

典型密码算法C语言实现_附录代码

06-12

典型密码算法及其C语言实现共13章节,详细讲述了一些典型密码算法的算法原理及C语言实现。密码算法包括:序列密码、分组密码、公钥密码和Hash算法。其中序列密码有祖冲之算法,分组密码有DES、3DES和SMS4算法,公钥...

Hash Algorithm

04-16

此一份文件說明SHA-256 及MD5等算法及其原理,藉由一步步的說講解來介紹Hash算法

栈溢出几种情况及解决方案

Beyond_2016的博客

07-30

2万+

一、局部数组过大。当函数内部的数组过大时,有可能导致堆栈溢出。

二、递归调用层次太多。递归函数在运行时会执行压栈操作,当压栈次数太多时,也会导致堆栈溢出。

三、指针或数组越界。这种情况最常见,例如进行字符串拷贝,或处理用户输入等等。

 

解决这类问题的办法有两个,

      一是增大栈空间,二是改用动态分配,使用堆(heap)而不是栈(stack)。 ...

hash算法原理及c++代码

05-27

哈希算法(Hash Algorithm)是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。哈希算法主要用于确保数据的完整性、验证数据的一致性以及类似的安全应用。常见的哈希算法有MD5、SHA-1、SHA-256等。

以下是一个基于SHA-256算法的C++代码示例,用于计算输入字符串的哈希值:

```c++

#include

#include

#include

int main() {

std::string str = "Hello, world!";

unsigned char hash[SHA256_DIGEST_LENGTH];

SHA256_CTX sha256;

SHA256_Init(&sha256);

SHA256_Update(&sha256, str.c_str(), str.length());

SHA256_Final(hash, &sha256);

std::cout << "Hash value: ";

for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {

printf("%02x", hash[i]);

}

std::cout << std::endl;

return 0;

}

```

在上述代码中,我们使用了OpenSSL库中的SHA256算法,首先定义了一个字符串`str`,其次定义一个`unsigned char`类型的数组`hash`,用于存储计算出的哈希值。然后,我们创建了一个SHA256_CTX类型的结构体对象`sha256`,并使用`SHA256_Init()`函数初始化该结构体。接下来,使用`SHA256_Update()`函数将输入字符串添加到哈希计算中,并使用`SHA256_Final()`函数计算最终的哈希值。最后,我们使用循环打印出计算得到的哈希值。

需要注意的是,此示例代码并不一定是最安全、最优秀的哈希算法实现,仅用于演示哈希算法的基本原理和代码实现。

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

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

Beyond_2016

CSDN认证博客专家

CSDN认证企业博客

码龄6年

暂无认证

128

原创

9万+

周排名

71万+

总排名

62万+

访问

等级

4910

积分

109

粉丝

249

获赞

53

评论

1078

收藏

私信

关注

热门文章

常见的hash算法及其原理

215003

【经典】吴恩达《机器学习》课程

30673

处理数据时不进行归一化会有什么影响?归一化的作用是什么?什么时候需要归一化?有哪些归一化的方法?

24508

栈溢出几种情况及解决方案

20159

ValueError: Input contains NaN, infinity or a value too large for dtype('float32').

17388

分类专栏

大数据、云计算

11篇

机器学习

25篇

深度学习

10篇

Python

7篇

Linux

5篇

其他

1篇

计算机网络

12篇

操作系统

25篇

数据结构与算法

30篇

Java

5篇

数据库

最新评论

Ubuntu解决系统图标变大以及分辨率降低问题(ubuntu18.04)

m0_74272734:

谢谢楼主

死锁的处理基本策略和常用方法

浮沉╮┊600:

简单明了

随机森林的随机性体现在哪里?

炒茄子:

假如在这个节点上是年龄,有10-40,现在你需要一分为二,那么10-20, 20-40是一种,10-30,30-40也是一种,你可以想到很多种分法,但是你无法穷尽,所以需要随机选取一些分法(当然越多越好)。然后模型在这些分法里面计算gini之类的,在随机选取的这些分法里面选择最好的那个分法,这是一种随机。

Ubuntu解决系统图标变大以及分辨率降低问题(ubuntu18.04)

LEAF1Q_Q:

太好使啦,谢谢博主

常见的hash算法及其原理

Tiny JoeDuck:

精辟

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

三次握手和四次挥手

深度学习框架darknet:yolov3训练自己数据时遇到的问题(Cannot load image "" STB Reason: can't fopen)

ubuntu18.04 没声音解决方案

2019年5篇

2018年104篇

2017年23篇

目录

目录

分类专栏

大数据、云计算

11篇

机器学习

25篇

深度学习

10篇

Python

7篇

Linux

5篇

其他

1篇

计算机网络

12篇

操作系统

25篇

数据结构与算法

30篇

Java

5篇

数据库

目录

评论 3

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

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

余额充值

HASH中文(简体)翻译:剑桥词典

HASH中文(简体)翻译:剑桥词典

词典

翻译

语法

同义词词典

+Plus

剑桥词典+Plus

Shop

剑桥词典+Plus

我的主页

+Plus 帮助

退出

剑桥词典+Plus

我的主页

+Plus 帮助

退出

登录

/

注册

中文 (简体)

查找

查找

英语-中文(简体)

hash 在英语-中文(简体)词典中的翻译

hashnoun uk

Your browser doesn't support HTML5 audio

/hæʃ/ us

Your browser doesn't support HTML5 audio

/hæʃ/

hash noun

(FOOD)

Add to word list

Add to word list

[ U ] a mixture of meat, potatoes, and vegetables cut into small pieces and baked or fried

肉末土豆泥

corned beef hash

咸牛肉土豆泥

US eggs and hash

鸡蛋和肉末土豆泥

hash noun

(DRUGS)

[ U ] informal for

hashish

(hashish的非正式说法)

hash noun

(SYMBOL)

[ C, usually singular ] the symbol # on a phone or computer keyboard

电话(或计算机键盘)上的#号

Please press the hash key to continue.

请按“#”键继续。

hash noun

(FAILURE)

 make a hash of something [ S ] UK informal

to do something very badly: He made a complete hash of the last question.

最后一道题他答得完全不对。

查看更多

(hash在剑桥英语-中文(简体)词典的翻译 © Cambridge University Press)

B1

hash的翻译

中文(繁体)

食物, 肉末馬鈴薯泥, 毒品…

查看更多内容

西班牙语

plato de ternera con sofrito de verduras y patata, hash, hachís…

查看更多内容

葡萄牙语

picadinho de carne, haxixe, cerquilha…

查看更多内容

更多语言

土耳其语

法语

in Dutch

捷克语

丹麦语

印尼语

泰语

越南语

波兰语

in Swedish

马来语

德语

挪威语

in Ukrainian

diyez, kıymalı patates, haşiş…

查看更多内容

dièse, croisillon, hachis…

查看更多内容

hekje, hachee, hasjiesj…

查看更多内容

dvojitý křížek (poč.), kousky masa s kousky brambor, haš (hovor.)…

查看更多内容

# symbolet, biksemad, hachis…

查看更多内容

simbol pagar, #, perkedel…

查看更多内容

เครื่องหมาย #, อาหารชนิดหนึ่งที่ทำจากเนื้อสับและนฝรั่ง, กัญชา…

查看更多内容

dấu #, món thịt băm, thuốc lá cuộn…

查看更多内容

kratka, mięso siekane z cebulą i ziemniakami, hasz…

查看更多内容

fyrkant, ragu, hasch…

查看更多内容

hash…

查看更多内容

die Raute, ein Gericht aus Hackfleisch und Kartoffeln, das Hasch…

查看更多内容

hasj, moste poteter og kjøtt, hasjaktig…

查看更多内容

решітка, дієз, страва з дрібно нарізаного м'яса та овочів…

查看更多内容

需要一个翻译器吗?

获得快速、免费的翻译!

翻译器工具

hash的发音是什么?

在英语词典中查看 hash 的释义

浏览

harvesting

has

has the cat got your tongue? idiom

has-been

hash

hash browns

hash something out

hash something up

hashish

hash更多的中文(简体)翻译

全部

hash browns

hash, at hashish

hash something out

hash something up

查看全部意思»

词组动词

hash something out

hash something up

查看全部动词词组意思»

“每日一词”

veggie burger

UK

Your browser doesn't support HTML5 audio

/ˈvedʒ.i ˌbɜː.ɡər/

US

Your browser doesn't support HTML5 audio

/ˈvedʒ.i ˌbɝː.ɡɚ/

a type of food similar to a hamburger but made without meat, by pressing together small pieces of vegetables, seeds, etc. into a flat, round shape

关于这个

博客

Forget doing it or forget to do it? Avoiding common mistakes with verb patterns (2)

March 06, 2024

查看更多

新词

stochastic parrot

March 04, 2024

查看更多

已添加至 list

回到页面顶端

内容

英语-中文(简体)翻译

©剑桥大学出版社与评估2024

学习

学习

学习

新词

帮助

纸质书出版

Word of the Year 2021

Word of the Year 2022

Word of the Year 2023

开发

开发

开发

词典API

双击查看

搜索Widgets

执照数据

关于

关于

关于

无障碍阅读

剑桥英语教学

剑桥大学出版社与评估

授权管理

Cookies与隐私保护

语料库

使用条款

京ICP备14002226号-2

©剑桥大学出版社与评估2024

剑桥词典+Plus

我的主页

+Plus 帮助

退出

词典

定义

清晰解释自然的书面和口头英语

英语

学习词典

基础英式英语

基础美式英语

翻译

点击箭头改变翻译方向。

双语词典

英语-中文(简体)

Chinese (Simplified)–English

英语-中文(繁体)

Chinese (Traditional)–English

英语-荷兰语

荷兰语-英语

英语-法语

法语-英语

英语-德语

德语-英语

英语-印尼语

印尼语-英语

英语-意大利语

意大利语-英语

英语-日语

日语-英语

英语-挪威语

挪威语-英语

英语-波兰语

波兰语-英语

英语-葡萄牙语

葡萄牙语-英语

英语-西班牙语

西班牙语-英语

English–Swedish

Swedish–English

半双语词典

英语-阿拉伯语

英语-孟加拉语

英语-加泰罗尼亚语

英语-捷克语

英语-丹麦语

English–Gujarati

英语-印地语

英语-韩语

英语-马来语

英语-马拉地语

英语-俄语

English–Tamil

English–Telugu

英语-泰语

英语-土耳其语

英语-乌克兰语

English–Urdu

英语-越南语

翻译

语法

同义词词典

Pronunciation

剑桥词典+Plus

Shop

剑桥词典+Plus

我的主页

+Plus 帮助

退出

登录 /

注册

中文 (简体)  

Change

English (UK)

English (US)

Español

Русский

Português

Deutsch

Français

Italiano

中文 (简体)

正體中文 (繁體)

Polski

한국어

Türkçe

日本語

Tiếng Việt

हिंदी

தமிழ்

తెలుగు

关注我们

选择一本词典

最近的词和建议

定义

清晰解释自然的书面和口头英语

英语

学习词典

基础英式英语

基础美式英语

语法与同义词词典

对自然书面和口头英语用法的解释

英语语法

同义词词典

Pronunciation

British and American pronunciations with audio

English Pronunciation

翻译

点击箭头改变翻译方向。

双语词典

英语-中文(简体)

Chinese (Simplified)–English

英语-中文(繁体)

Chinese (Traditional)–English

英语-荷兰语

荷兰语-英语

英语-法语

法语-英语

英语-德语

德语-英语

英语-印尼语

印尼语-英语

英语-意大利语

意大利语-英语

英语-日语

日语-英语

英语-挪威语

挪威语-英语

英语-波兰语

波兰语-英语

英语-葡萄牙语

葡萄牙语-英语

英语-西班牙语

西班牙语-英语

English–Swedish

Swedish–English

半双语词典

英语-阿拉伯语

英语-孟加拉语

英语-加泰罗尼亚语

英语-捷克语

英语-丹麦语

English–Gujarati

英语-印地语

英语-韩语

英语-马来语

英语-马拉地语

英语-俄语

English–Tamil

English–Telugu

英语-泰语

英语-土耳其语

英语-乌克兰语

English–Urdu

英语-越南语

词典+Plus

词汇表

选择语言

中文 (简体)  

English (UK)

English (US)

Español

Русский

Português

Deutsch

Français

Italiano

正體中文 (繁體)

Polski

한국어

Türkçe

日本語

Tiếng Việt

हिंदी

தமிழ்

తెలుగు

内容

英语-中文(简体) 

 

Noun 

hash (FOOD)

hash (DRUGS)

hash (SYMBOL)

hash (FAILURE)

make a hash of something

Translations

语法

所有翻译

我的词汇表

把hash添加到下面的一个词汇表中,或者创建一个新词汇表。

更多词汇表

前往词汇表

对该例句有想法吗?

例句中的单词与输入词条不匹配。

该例句含有令人反感的内容。

取消

提交

例句中的单词与输入词条不匹配。

该例句含有令人反感的内容。

取消

提交

什么是 hash? - 知乎

什么是 hash? - 知乎首页知乎知学堂发现等你来答​切换模式登录/注册程序员软件开发算法编程哈希函数什么是 hash?我大概知道一点hash的东西,比如说指定一个hash函数为newkey=oldkey%23,然后来一个值为oldkey的整数,根据该函数出一个新的ke…显示全部 ​关注者1,031被浏览592,842关注问题​写回答​邀请回答​好问题 26​2 条评论​分享​57 个回答默认排序知乎用户谢小圆邀请。首先回答题主的问题。hash(散列、杂凑)函数,是将任意长度的数据映射到有限长度的域上。直观解释起来,就是对一串数据m进行杂糅,输出另一段固定长度的数据h,作为这段数据的特征(指纹)。也就是说,无论数据块m有多大,其输出值h为固定长度。到底是什么原理?将m分成固定长度(如128位),依次进行hash运算,然后用不同的方法迭代即可(如前一块的hash值与后一块的hash值进行异或)。如果不够128位怎么办?用0补全或者用1补全随意,算法中约定好就可以了。原问题回答完毕。但是既然要说hash算法,不妨说的更透彻些。=================分割线==========由于用途的不同,hash在数据结构中的含义和密码学中的含义并不相同,所以在这两种不同的领域里,算法的设计侧重点也不同。预备小知识:抗碰撞能力:对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。抗篡改能力:对于一个数据块,哪怕只改动其一个比特位,其hash值的改动也会非常大。在用到hash进行管理的数据结构中,比如hashmap,hash值(key)存在的目的是加速键值对的查找,key的作用是为了将元素适当地放在各个桶里,对于抗碰撞的要求没有那么高。换句话说,hash出来的key,只要保证value大致均匀的放在不同的桶里就可以了。但整个算法的set性能,直接与hash值产生的速度有关,所以这时候的hash值的产生速度就尤为重要,以JDK中的String.hashCode()方法为例: public int hashCode() {

int h = hash;

//hash default value : 0

if (h == 0 && value.length > 0) {

//value : char storage

char val[] = value;

for (int i = 0; i < value.length; i++) {

h = 31 * h + val[i];

}

hash = h;

}

return h;

}

很简洁的一个乘加迭代运算,在不少的hash算法中,使用的是异或+加法进行迭代,速度和前者差不多。在密码学中,hash算法的作用主要是用于消息摘要和签名,换句话说,它主要用于对整个消息的完整性进行校验。举个例子,我们登陆知乎的时候都需要输入密码,那么知乎如果明文保存这个密码,那么黑客就很容易窃取大家的密码来登陆,特别不安全。那么知乎就想到了一个方法,使用hash算法生成一个密码的签名,知乎后台只保存这个签名值。由于hash算法是不可逆的,那么黑客即便得到这个签名,也丝毫没有用处;而如果你在网站登陆界面上输入你的密码,那么知乎后台就会重新计算一下这个hash值,与网站中储存的原hash值进行比对,如果相同,证明你拥有这个账户的密码,那么就会允许你登陆。银行也是如此,银行是万万不敢保存用户密码的原文的,只会保存密码的hash值而而已。在这些应用场景里,对于抗碰撞和抗篡改能力要求极高,对速度的要求在其次。一个设计良好的hash算法,其抗碰撞能力是很高的。以MD5为例,其输出长度为128位,设计预期碰撞概率为1/2^{64} ,这是一个极小极小的数字——而即便是在MD5被王小云教授破解之后,其碰撞概率上限也高达1/2^{41} ,也就是说,至少需要找2^{40} 次才能有1/2的概率来找到一个与目标文件相同的hash值。而对于两个相似的字符串,MD5加密结果如下:MD5("version1") = "966634ebf2fc135707d6753692bf4b1e";

MD5("version2") = "2e0e95285f08a07dea17e7ee111b21c8";

可以看到仅仅两个比特位(char("1")和char("2"))的改变,二者的MD5值就天差地别了。到这里,读者估计会问,有没有可能找到这么一个算法,如果输出长度为128位,那么把这128位“充分利用到”,让它可以有2^{128} 种不同的hash值,而且分布均匀,抗篡改能力也特别高,一点点改动就会让hash值面目全非,一点都不浪费(这里的表述非常不严格)?稍微严格一点表述,就是:有没有这样一个算法,使得对于任何一个给定的输入,此算法都会输出一个固定的均匀随机的输出?答案是密码学家们也至今没有构造出着这样一个算法,但是倾向于这个算法存在,而且有不少的密码学算法构造和这个假设有关。这个假设的名字叫做随机预言机(Random Oracle)。在密码学中,hash算法有不少有意思的改进思路,以应付不同的使用场景。例如师兄 @刘巍然-学酥前一段时间让我写着玩的变色龙Hash(ChameleonHash),它有一个有趣的特性。在普通情况下,ChameleonHash可以当做普通hash算法使用,从明文(用m表示)得到的hash值(用h表示)抗碰撞能力依然特别强;但是如果使用者在计算这个hash值的时候预先计算一个值(用s表示)并保存,那么通过这个值很容易计算出另一个hash值也为h的明文m' !也就是说,如果你保留这个值的话,hash算法的抗碰撞能力完全被解除了。这意味着,如果某个网站想要作恶的话,那么它可以很容易的替换他们自己的hash算法为ChameleonHash,方便地伪造出一个密钥来窃取用户的所有数据,而这个公司完全可以在对外宣传的时候,依然声称对用户信息严格保密——《教网站如何优雅地耍流氓》。2015首答,写的好干巴巴的没有味道啊喂,有耐心看下来的同学,欢迎指正各种错误:)编辑于 2018-05-11 15:03​赞同 767​​37 条评论​分享​收藏​喜欢收起​腾讯技术工程​编程话题下的优秀答主​ 关注提到hash,相信大多数同学都不会陌生,之前很火现在也依旧很火的技术区块链背后的底层原理之一就是hash,下面就从hash算法的原理和实际应用等几个角度,对hash算法进行一个讲解。1、什么是HashHash也称散列、哈希,对应的英文都是Hash。基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出。这个映射的规则就是对应的Hash算法,而原始数据映射后的二进制串就是哈希值。活动开发中经常使用的MD5和SHA都是历史悠久的Hash算法。echo md5("这是一个测试文案");

// 输出结果:2124968af757ed51e71e6abeac04f98d

在这个例子里,这是一个测试文案是原始值,2124968af757ed51e71e6abeac04f98d 就是经过hash算法得到的Hash值。整个Hash算法的过程就是把原始任意长度的值空间,映射成固定长度的值空间的过程。2、Hash的特点一个优秀的hash算法,需要什么样的要求呢?a)、从hash值不可以反向推导出原始的数据这个从上面MD5的例子里可以明确看到,经过映射后的数据和原始数据没有对应关系b)、输入数据的微小变化会得到完全不同的hash值,相同的数据会得到相同的值echo md5("这是一个测试文案");// 输出结果:2124968af757ed51e71e6abeac04f98decho md5("这是二个测试文案");// 输出结果:bcc2a4bb4373076d494b2223aef9f702可以看到我们只改了一个文字,但是整个得到的hash值产生了非常大的变化。c)、哈希算法的执行效率要高效,长的文本也能快速地计算出哈希值d)、hash算法的冲突概率要小由于hash的原理是将输入空间的值映射成hash空间内,而hash值的空间远小于输入的空间。根据抽屉原理,一定会存在不同的输入被映射成相同输出的情况。那么作为一个好的hash算法,就需要这种冲突的概率尽可能小。桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。这一现象就是我们所说的“抽屉原理”。抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素。” 抽屉原理有时也被称为鸽巢原理。它是组合数学中一个重要的原理3、Hash碰撞的解决方案前面提到了hash算法是一定会有冲突的,那么如果我们如果遇到了hash冲突需要解决的时候应该怎么处理呢?比较常用的算法是链地址法和开放地址法。3.1 链地址法链表地址法是使用一个链表数组,来存储相应数据,当hash遇到冲突的时候依次添加到链表的后面进行处理。链地址在处理的流程如下:添加一个元素的时候,首先计算元素key的hash值,确定插入数组中的位置。如果当前位置下没有重复数据,则直接添加到当前位置。当遇到冲突的时候,添加到同一个hash值的元素后面,行成一个链表。这个链表的特点是同一个链表上的Hash值相同。java的数据结构HashMap使用的就是这种方法来处理冲突,JDK1.8中,针对链表上的数据超过8条的时候,使用了红黑树进行优化。由于篇幅原因,这里不深入讨论相关数据结构,有兴趣的同学可以参考这篇文章:《Java集合之一—HashMap》3.2 开放地址法开放地址法是指大小为 M 的数组保存 N 个键值对,其中 M > N。我们需要依靠数组中的空位解决碰撞冲突。基于这种策略的所有方法被统称为“开放地址”哈希表。线性探测法,就是比较常用的一种“开放地址”哈希表的一种实现方式。线性探测法的核心思想是当冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。简单来说就是:一旦发生冲突,就去寻找下 一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。线性探测法的数学描述是:h(k, i) = (h(k, 0) + i) mod m,i表示当前进行的是第几轮探查。i=1时,即是探查h(k, 0)的下一个;i=2,即是再下一个。这个方法是简单地向下探查。mod m表示:到达了表的底下之后,回到顶端从头开始。对于开放寻址冲突解决方法,除了线性探测方法之外,还有另外两种比较经典的探测方法,二次探测(Quadratic probing)和双重散列(Double hashing)。但是不管采用哪种探测方法,当散列表中空闲位置不多的时候,散列冲突的概率就会大大提高。为了尽可能保证散列表的操作效率,一般情况下,我们会尽可能保证散列表中有一定比例的空闲槽位。我们用装载因子(load factor)来表示空位的多少。散列表的装载因子=填入表中的元素个数/散列表的长度。装载因子越大,说明冲突越多,性能越差。3.3 两种方案的demo示例假设散列长为8,散列函数H(K)=K mod 7,给定的关键字序列为{32,14,23,2, 20}当使用链表法时,相应的数据结构如下图所示:当使用线性探测法时,相应的数据结果如下图所示:这里的两种算法的区别是2这个元素,在链表法中还是在节点2的位置上,但是在线性探测法遇到冲突时会将冲突数据放到下一个空的位置下面。4、hash算法在日常活动中的应用在日常运营活动中,我们活动开发经常遇到的应用场景是信息加密、数据校验、负载均衡。下面分别对这三种应用场景进行讲解。4.1 信息加密首先我们看一下信息加密的应用。2011年CSDN脱库事件,导致超过600W的用户的密码泄露,让人失望的是,CSDN是明文存储用户的注册邮箱和密码的。作为用户的非常隐私的信息,最简单的保护措施就是对密码进行hash加密。在客户端对用户输入的密码进行hash运算,然后在服务端的数据库中保存用户密码的hash值。由于服务器端也没有存储密码的明文,所以目前很多网站也就不再有找回密码的功能了。这里也友情提示一下大家:如果在使用中发现某网站还有提供找回密码的功能,就要好好担心下这个网站的安全性了。看到这里有些同学会觉得那么我们是不是对用户输入的密码进行一次MD5加密就可以了呢,这样就算恶意用户知道了hash值,也没有办法拿到用户的真实密码。假设用户的密码是123456789,经过一次md5以后得到的值是:25f9e794323b453885f5181f1b624d0b那么是不是使用了这个加密后的字符串来存密码就万无一失了呢,理想总是很丰满,而现实总是很骨感的。大家可以看一下这个网站:https://www.cmd5.com/这里是该网站的相关介绍:本站针对md5、sha1等全球通用公开的加密算法进行反向查询,通过穷举字符组合的方式,创建了明文密文对应查询数据库,创建的记录约90万亿条,占用硬盘超过500TB,查询成功率95%以上,很多复杂密文只有本站才可查询。已稳定运行十余年,国内外享有盛誉那么一般针对这种问题,我们的解决之道就是引入salt(加盐),即利用特殊字符(盐)和用户的输入合在一起组成新的字符串进行加密。通过这样的方式,增加了反向查询的复杂度。但是这样的方式也不是万无一失,如果发生了盐被泄露的问题,就需要所有用到的地方来重置密码。针对salt泄露的问题,其实还有一种解决办法,即使用HMAC进行加密(Hash-based Message Authentication Code)。这种算法的核心思路是加密使用的key是从服务器端获取的,每一个用户的是不一样的。如果发生了泄露,那么也就是这一个用户的会被泄露,不会影响到全局。这里也留给大家一个思考点,如果恶意用户直接抓取了你的活动参与链接,也就是拿到了你计算后的hash值,那从技术的角度上说,我们还有没有其他可以提升恶意用户的违法成本呢?4.2 数据校验- git commit id使用过git的同学都应该清楚,每次git提交后都有一个commit id,比如:19d02d2cc358e59b3d04f82677dbf3808ae4fc40就是一次git commit的结果,那么这个id是如何生成出来的呢?查阅了相关资料,使用如下代码可以进行查看:printf "commit %s\0" $(git cat-file commit HEAD | wc -c); git cat-file commit HEAD

git的commit id主要包括了以下几部分内容:Tree 哈希,parent哈希、作者信息和本次提交的备注。针对这些信息进行SHA-1 算法后得到值就是本次提交的commit id。简单来讲,就是对于单次提交的头信息的一个校验和。Linux kernel开创者和Git的开发者——Linus说,Git使用了sha1并非是为了安全性,而是为了数据的完整性;它可以保证,在很多年后,你重新checkout某个commit时,一定是它多年前的当时的状态,完全一摸一样,完全值得信任。但最新研究表明,理论上对其进行哈希碰撞(hash collision,不同的两块数据有相同的hash值)的攻击可以在2^51(2的51次方)左右的次数内实现。不过由于commit id 是针对单个仓库里的,所以实际应用中我们可以认为如果两个文件的SHA-1值是相同的,那么它们确是完全相同的内容。注:对于git里tree、parent等结构感兴趣的同学,可以参考下这篇文章《Git 内部原理 - Git 对象》,这里由于篇幅原因就不进行深入分析了。版权校验在数据校验方面的另一个应用场景就是版权的保护或者违禁信息的打击,比如某个小视频,第一个用户上传的时候,我们认为是版权所有者,计算一个hash值存下来。当第二个用户上传的时候,同样计算hash值,如果hash值一样的话,就算同一个文件。这种方案其实也给用户传播违禁文件提高了一些门槛,不是简单的换一个名字或者改一下后缀名就可以躲避掉打击了。(当然这种方式也是可以绕过的,图片的你随便改一下颜色,视频去掉一帧就又是完全不同的hash值了。注意:我没有教你变坏,我只是和你在讨论这个技术。。。)另外我们在社区里,也会遇到玩家重复上传同一张图片或者视频的情况,使用这种校验的方式,可以有效减少cos服务的存储空间。大文件分块校验使用过bt的同学都有经验,在p2p网络中会把一个大文件拆分成很多小的数据各自传输。这样的好处是如果某个小的数据块在传输过程中损坏了,只要重新下载这个块就好。为了确保每一个小的数据块都是发布者自己传输的,我们可以对每一个小的数据块都进行一个hash的计算,维护一个hash List,在收到所有数据以后,我们对于这个hash List里的每一块进行遍历比对。这里有一个优化点是如果文件分块特别多的时候,如果遍历对比就会效率比较低。可以把所有分块的hash值组合成一个大的字符串,对于这个字符串再做一次Hash运算,得到最终的hash(Root hash)。在实际的校验中,我们只需要拿到了正确的Root hash,即可校验Hash List,也就可以校验每一个数据块了。4.3 负载均衡活动开发同学在应对高星级业务大用户量参与时,都会使用分库分表,针对用户的openid进行hashtime33取模,就可以得到对应的用户分库分表的节点了。如上图所示,这里其实是分了10张表,openid计算后的hash值取模10,得到对应的分表,在进行后续处理就好。对于一般的活动或者系统,我们一般设置10张表或者100张表就好。下面我们来看一点复杂的问题,假设我们活动初始分表了10张,运营一段时间以后发现需要10张不够,需要改到100张。这个时候我们如果直接扩容的话,那么所有的数据都需要重新计算Hash值,大量的数据都需要进行迁移。如果更新的是缓存的逻辑,则会导致大量缓存失效,发生雪崩效应,导致数据库异常。造成这种问题的原因是hash算法本身的缘故,只要是取模算法进行处理,则无法避免这种情况。针对这种问题,我们就需要利用一致性hash进行相应的处理了。一致性hash的基本原理是将输入的值hash后,对结果的hash值进行2^32取模,这里和普通的hash取模算法不一样的点是在一致性hash算法里将取模的结果映射到一个环上。将缓存服务器与被缓存对象都映射到hash环上以后,从被缓存对象的位置出发,沿顺时针方向遇到的第一个服务器,就是当前对象将要缓存于的服务器,由于被缓存对象与服务器hash后的值是固定的,所以,在服务器不变的情况下,一个openid必定会被缓存到固定的服务器上,那么,当下次想要访问这个用户的数据时,只要再次使用相同的算法进行计算,即可算出这个用户的数据被缓存在哪个服务器上,直接去对应的服务器查找对应的数据即可。这里的逻辑其实和直接取模的是一样的。如下图所示:初始情况如下:用户1的数据在服务器A里,用户2、3的数据存在服务器C里,用户4的数据存储在服务器B里下面我们来看一下当服务器数量发生变化的时候,相应影响的数据情况:服务器缩容服务器B发生了故障,进行剔除后,只有用户4的数据发生了异常。这个时候我们需要继续按照顺时针的方案,把缓存的数据放在用户A上面。服务器扩容同样的,我们进行了服务器扩容以后,新增了一台服务器D,位置落在用户2和3之间。按照顺时针原则,用户2依然访问的是服务器C的数据,而用户3顺时针查询后,发现最近的服务器是D,后续数据就会存储到d上面。虚拟节点当然这只是一种理想情况,实际使用中,由于服务器节点数量有限,有可能出现分布不均匀的情况。这个时候会出现大量数据都被映射到某一台服务器的情况,如下图左侧所示。为了解决这个问题,我们采用了虚拟节点的方案。虚拟节点是实际节点(实际的物理服务器)在hash环上的复制品,一个实际节点可以对应多个虚拟节点。虚拟节点越多,hash环上的节点就越多,数据被均匀分布的概率就越大。如右图所示,B、C、D 是原始节点复制出来的虚拟节点,原本都要访问机器D的用户1、4,分别被映射到了B,D。通过这样的方式,起到了一个服务器均匀分布的作用。5、几种hash算法的扩展应用下面介绍几种大家可能不经常遇到的应用,由于篇幅原因,不做深入介绍,只抛砖引玉。5.1 SimHashsimHash是google用于海量文本去重的一种方法,它是一种局部敏感hash。那什么叫局部敏感呢,假定两个字符串具有一定的相似性,在hash之后,仍然能保持这种相似性,就称之为局部敏感hash。普通的hash是不具有这种属性的。simhash被Google用来在海量文本中去重。simHash算法的思路大致如下:将Doc进行关键词抽取(其中包括分词和计算权重),抽取出n个(关键词,权重)对, 即图中的多个(feature, weight)。记为 feature_weight_pairs = [fw1, fw2 … fwn],其中 fwn = (feature_n,weight_n)。对每个feature_weight_pairs中的feature进行hash。然后对hash_weight_pairs进行位的纵向累加,如果该位是1,则+weight,如果是0,则-weight,最后生成bits_count个数字,大于0标记1,小于0标记0最后转换成一个64位的字节,判断重复只需要判断他们的特征字的距离是不是哈希算法 - 廖雪峰的官方网站

哈希算法 - 廖雪峰的官方网站

Index

廖雪峰的官方网站

Blog

Java教程

手写Spring

手写Tomcat

Makefile教程

Python教程

JavaScript教程

区块链教程

SQL教程

Git教程

文章

问答

More

Java教程

手写Spring

手写Tomcat

Makefile教程

Python教程

JavaScript教程

区块链教程

SQL教程

Git教程

文章

问答

Java教程

手写Spring

手写Tomcat

Makefile教程

Python教程

JavaScript教程

区块链教程

SQL教程

Git教程

文章

问答

 

Profile

Passkey

Sign Out

Sign In

English

简体中文

Index

Java教程

Java快速入门

Java简介

安装JDK

第一个Java程序

Java代码助手

使用IDE

使用IDE练习插件

Java程序基础

Java程序基本结构

变量和数据类型

整数运算

浮点数运算

布尔运算

字符和字符串

数组类型

流程控制

输入和输出

if判断

switch多重选择

while循环

do while循环

for循环

break和continue

数组操作

遍历数组

数组排序

多维数组

命令行参数

面向对象编程

面向对象基础

方法

构造方法

方法重载

继承

多态

抽象类

接口

静态字段和静态方法

作用域

内部类

classpath和jar

class版本

模块

Java核心类

字符串和编码

StringBuilder

StringJoiner

包装类型

JavaBean

枚举类

记录类

BigInteger

BigDecimal

常用工具类

异常处理

Java的异常

捕获异常

抛出异常

自定义异常

NullPointerException

使用断言

使用JDK Logging

使用Commons Logging

使用Log4j

使用SLF4J和Logback

反射

Class类

访问字段

调用方法

调用构造方法

获取继承关系

动态代理

注解

使用注解

定义注解

处理注解

泛型

什么是泛型

使用泛型

编写泛型

擦拭法

extends通配符

super通配符

泛型和反射

集合

Java集合简介

使用List

编写equals方法

使用Map

编写equals和hashCode

使用EnumMap

使用TreeMap

使用Properties

使用Set

使用Queue

使用PriorityQueue

使用Deque

使用Stack

使用Iterator

使用Collections

IO

File对象

InputStream

OutputStream

Filter模式

操作Zip

读取classpath资源

序列化

Reader

Writer

PrintStream和PrintWriter

使用Files

日期与时间

基本概念

Date和Calendar

LocalDateTime

ZonedDateTime

DateTimeFormatter

Instant

最佳实践

单元测试

编写JUnit测试

使用Fixture

异常测试

条件测试

参数化测试

正则表达式

正则表达式简介

匹配规则

复杂匹配规则

分组匹配

非贪婪匹配

搜索和替换

加密与安全

编码算法

哈希算法

BouncyCastle

Hmac算法

对称加密算法

口令加密算法

密钥交换算法

非对称加密算法

签名算法

数字证书

多线程

多线程基础

创建新线程

线程的状态

中断线程

守护线程

线程同步

同步方法

死锁

使用wait和notify

使用ReentrantLock

使用Condition

使用ReadWriteLock

使用StampedLock

使用Semaphore

使用Concurrent集合

使用Atomic

使用线程池

使用Future

使用CompletableFuture

使用ForkJoin

使用ThreadLocal

使用虚拟线程

Maven基础

Maven介绍

依赖管理

构建流程

使用插件

模块管理

使用mvnw

发布Artifact

网络编程

网络编程基础

TCP编程

UDP编程

发送Email

接收Email

HTTP编程

RMI远程调用

XML与JSON

XML简介

使用DOM

使用SAX

使用Jackson

使用JSON

JDBC编程

JDBC简介

JDBC查询

JDBC更新

JDBC事务

JDBC Batch

JDBC连接池

函数式编程

Lambda基础

方法引用

使用Stream

创建Stream

使用map

使用filter

使用reduce

输出集合

其他操作

设计模式

创建型模式

工厂方法

抽象工厂

生成器

原型

单例

结构型模式

适配器

桥接

组合

装饰器

外观

享元

代理

行为型模式

责任链

命令

解释器

迭代器

中介

备忘录

观察者

状态

策略

模板方法

访问者

Web开发

Web基础

Servlet入门

Servlet开发

Servlet进阶

重定向与转发

使用Session和Cookie

JSP开发

MVC开发

MVC高级开发

使用Filter

修改请求

修改响应

使用Listener

部署

Spring开发

IoC容器

IoC原理

装配Bean

使用Annotation配置

定制Bean

使用Resource

注入配置

使用条件装配

使用AOP

装配AOP

使用注解装配AOP

AOP避坑指南

访问数据库

使用JDBC

使用声明式事务

使用DAO

集成Hibernate

集成JPA

集成MyBatis

设计ORM

开发Web应用

使用Spring MVC

使用REST

集成Filter

使用Interceptor

处理CORS

国际化

异步处理

使用WebSocket

集成第三方组件

集成JavaMail

集成JMS

使用Scheduler

集成JMX

Spring Boot开发

第一个Spring Boot应用

使用开发者工具

打包Spring Boot应用

瘦身Spring Boot应用

使用Actuator

使用Profiles

使用Conditional

加载配置文件

禁用自动配置

添加Filter

集成第三方组件

集成Open API

访问Redis

集成Artemis

集成RabbitMQ

集成Kafka

Spring Cloud开发

项目架构设计

搭建项目框架

设计交易引擎

设计资产系统

设计订单系统

设计撮合引擎

设计清算系统

完成交易引擎

设计定序系统

设计API系统

设计行情系统

设计推送系统

编写UI

项目总结

关注公众号不定期领红包:

加入知识星球社群:

关注微博获取实时动态:

哈希算法

Last updated: ...

/

Reads: 3427386

Edit

哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。

哈希算法最重要的特点就是:

相同的输入一定得到相同的输出;

不同的输入大概率得到不同的输出。

哈希算法的目的就是为了验证原始数据是否被篡改。

Java字符串的hashCode()就是一个哈希算法,它的输入是任意字符串,输出是固定的4字节int整数:

"hello".hashCode(); // 0x5e918d2

"hello, java".hashCode(); // 0x7a9d88e8

"hello, bob".hashCode(); // 0xa0dbae2f

两个相同的字符串永远会计算出相同的hashCode,否则基于hashCode定位的HashMap就无法正常工作。这也是为什么当我们自定义一个class时,覆写equals()方法时我们必须正确覆写hashCode()方法。

哈希碰撞

哈希碰撞是指,两个不同的输入得到了相同的输出:

"AaAaAa".hashCode(); // 0x7460e8c0

"BBAaBB".hashCode(); // 0x7460e8c0

有童鞋会问:碰撞能不能避免?答案是不能。碰撞是一定会出现的,因为输出的字节长度是固定的,String的hashCode()输出是4字节整数,最多只有4294967296种输出,但输入的数据长度是不固定的,有无数种输入。所以,哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞。

碰撞不可怕,我们担心的不是碰撞,而是碰撞的概率,因为碰撞概率的高低关系到哈希算法的安全性。一个安全的哈希算法必须满足:

碰撞概率低;

不能猜测输出。

不能猜测输出是指,输入的任意一个bit的变化会造成输出完全不同,这样就很难从输出反推输入(只能依靠暴力穷举)。假设一种哈希算法有如下规律:

hashA("java001") = "123456"

hashA("java002") = "123457"

hashA("java003") = "123458"

那么很容易从输出123459反推输入,这种哈希算法就不安全。安全的哈希算法从输出是看不出任何规律的:

hashB("java001") = "123456"

hashB("java002") = "580271"

hashB("java003") = ???

常用的哈希算法有:

算法输出长度(位)输出长度(字节)

MD5128 bits16 bytes

SHA-1160 bits20 bytes

RipeMD-160160 bits20 bytes

SHA-256256 bits32 bytes

SHA-512512 bits64 bytes

根据碰撞概率,哈希算法的输出长度越长,就越难产生碰撞,也就越安全。

Java标准库提供了常用的哈希算法,并且有一套统一的接口。我们以MD5算法为例,看看如何对输入计算哈希:

import java.math.BigInteger;

import java.security.MessageDigest;

----

public class Main {

public static void main(String[] args) throws Exception {

// 创建一个MessageDigest实例:

MessageDigest md = MessageDigest.getInstance("MD5");

// 反复调用update输入数据:

md.update("Hello".getBytes("UTF-8"));

md.update("World".getBytes("UTF-8"));

byte[] result = md.digest(); // 16 bytes: 68e109f0f40ca72a15e05cc22786f8e6

System.out.println(new BigInteger(1, result).toString(16));

}

}

使用MessageDigest时,我们首先根据哈希算法获取一个MessageDigest实例,然后,反复调用update(byte[])输入数据。当输入结束后,调用digest()方法获得byte[]数组表示的摘要,最后,把它转换为十六进制的字符串。

运行上述代码,可以得到输入HelloWorld的MD5是68e109f0f40ca72a15e05cc22786f8e6。

哈希算法的用途

因为相同的输入永远会得到相同的输出,因此,如果输入被修改了,得到的输出就会不同。

我们在网站上下载软件的时候,经常看到下载页显示的哈希:

如何判断下载到本地的软件是原始的、未经篡改的文件?我们只需要自己计算一下本地文件的哈希值,再与官网公开的哈希值对比,如果相同,说明文件下载正确,否则,说明文件已被篡改。

哈希算法的另一个重要用途是存储用户口令。如果直接将用户的原始口令存放到数据库中,会产生极大的安全风险:

数据库管理员能够看到用户明文口令;

数据库数据一旦泄漏,黑客即可获取用户明文口令。

不存储用户的原始口令,那么如何对用户进行认证?

方法是存储用户口令的哈希,例如,MD5。

在用户输入原始口令后,系统计算用户输入的原始口令的MD5并与数据库存储的MD5对比,如果一致,说明口令正确,否则,口令错误。

因此,数据库存储用户名和口令的表内容应该像下面这样:

usernamepassword

bobf30aa7a662c728b7407c54ae6bfd27d1

alice25d55ad283aa400af464c76d713c07ad

timbed128365216c019988915ed3add75fb

这样一来,数据库管理员看不到用户的原始口令。即使数据库泄漏,黑客也无法拿到用户的原始口令。想要拿到用户的原始口令,必须用暴力穷举的方法,一个口令一个口令地试,直到某个口令计算的MD5恰好等于指定值。

使用哈希口令时,还要注意防止彩虹表攻击。

什么是彩虹表呢?上面讲到了,如果只拿到MD5,从MD5反推明文口令,只能使用暴力穷举的方法。

然而黑客并不笨,暴力穷举会消耗大量的算力和时间。但是,如果有一个预先计算好的常用口令和它们的MD5的对照表:

常用口令MD5

hello123f30aa7a662c728b7407c54ae6bfd27d1

1234567825d55ad283aa400af464c76d713c07ad

passw0rdbed128365216c019988915ed3add75fb

19700101570da6d5277a646f6552b8832012f5dc

……

202012316879c0ae9117b50074ce0a0d4c843060

这个表就是彩虹表。如果用户使用了常用口令,黑客从MD5一下就能反查到原始口令:

bob的MD5:f30aa7a662c728b7407c54ae6bfd27d1,原始口令:hello123;

alice的MD5:25d55ad283aa400af464c76d713c07ad,原始口令:12345678;

tim的MD5:bed128365216c019988915ed3add75fb,原始口令:passw0rd。

这就是为什么不要使用常用密码,以及不要使用生日作为密码的原因。

即使用户使用了常用口令,我们也可以采取措施来抵御彩虹表攻击,方法是对每个口令额外添加随机数,这个方法称之为加盐(salt):

digest = md5(salt+inputPassword)

经过加盐处理的数据库表,内容如下:

usernamesaltpassword

bobH1r0aa5022319ff4c56955e22a74abcc2c210

alice7$p2we5de688c99e961ed6e560b972dab8b6a

timz5Sk91eee304b92dc0d105904e7ab58fd2f64

加盐的目的在于使黑客的彩虹表失效,即使用户使用常用口令,也无法从MD5反推原始口令。

SHA-1

SHA-1也是一种哈希算法,它的输出是160 bits,即20字节。SHA-1是由美国国家安全局开发的,SHA算法实际上是一个系列,包括SHA-0(已废弃)、SHA-1、SHA-256、SHA-512等。

在Java中使用SHA-1,和MD5完全一样,只需要把算法名称改为"SHA-1":

import java.math.BigInteger;

import java.security.MessageDigest;

----

public class Main {

public static void main(String[] args) throws Exception {

// 创建一个MessageDigest实例:

MessageDigest md = MessageDigest.getInstance("SHA-1");

// 反复调用update输入数据:

md.update("Hello".getBytes("UTF-8"));

md.update("World".getBytes("UTF-8"));

byte[] result = md.digest(); // 20 bytes: db8ac1c259eb89d4a131b253bacfca5f319d54f2

System.out.println(new BigInteger(1, result).toString(16));

}

}

类似的,计算SHA-256,我们需要传入名称"SHA-256",计算SHA-512,我们需要传入名称"SHA-512"。Java标准库支持的所有哈希算法可以在这里查到。

注意:MD5因为输出长度较短,短时间内破解是可能的,目前已经不推荐使用。

小结

哈希算法可用于验证数据完整性,具有防篡改检测的功能;

常用的哈希算法有MD5、SHA-1等;

用哈希存储口令时要考虑彩虹表攻击。

Comments

Make a comment

Sign in to

make a comment

Index

Java教程

Java快速入门

Java简介

安装JDK

第一个Java程序

Java代码助手

使用IDE

使用IDE练习插件

Java程序基础

Java程序基本结构

变量和数据类型

整数运算

浮点数运算

布尔运算

字符和字符串

数组类型

流程控制

输入和输出

if判断

switch多重选择

while循环

do while循环

for循环

break和continue

数组操作

遍历数组

数组排序

多维数组

命令行参数

面向对象编程

面向对象基础

方法

构造方法

方法重载

继承

多态

抽象类

接口

静态字段和静态方法

作用域

内部类

classpath和jar

class版本

模块

Java核心类

字符串和编码

StringBuilder

StringJoiner

包装类型

JavaBean

枚举类

记录类

BigInteger

BigDecimal

常用工具类

异常处理

Java的异常

捕获异常

抛出异常

自定义异常

NullPointerException

使用断言

使用JDK Logging

使用Commons Logging

使用Log4j

使用SLF4J和Logback

反射

Class类

访问字段

调用方法

调用构造方法

获取继承关系

动态代理

注解

使用注解

定义注解

处理注解

泛型

什么是泛型

使用泛型

编写泛型

擦拭法

extends通配符

super通配符

泛型和反射

集合

Java集合简介

使用List

编写equals方法

使用Map

编写equals和hashCode

使用EnumMap

使用TreeMap

使用Properties

使用Set

使用Queue

使用PriorityQueue

使用Deque

使用Stack

使用Iterator

使用Collections

IO

File对象

InputStream

OutputStream

Filter模式

操作Zip

读取classpath资源

序列化

Reader

Writer

PrintStream和PrintWriter

使用Files

日期与时间

基本概念

Date和Calendar

LocalDateTime

ZonedDateTime

DateTimeFormatter

Instant

最佳实践

单元测试

编写JUnit测试

使用Fixture

异常测试

条件测试

参数化测试

正则表达式

正则表达式简介

匹配规则

复杂匹配规则

分组匹配

非贪婪匹配

搜索和替换

加密与安全

编码算法

哈希算法

BouncyCastle

Hmac算法

对称加密算法

口令加密算法

密钥交换算法

非对称加密算法

签名算法

数字证书

多线程

多线程基础

创建新线程

线程的状态

中断线程

守护线程

线程同步

同步方法

死锁

使用wait和notify

使用ReentrantLock

使用Condition

使用ReadWriteLock

使用StampedLock

使用Semaphore

使用Concurrent集合

使用Atomic

使用线程池

使用Future

使用CompletableFuture

使用ForkJoin

使用ThreadLocal

使用虚拟线程

Maven基础

Maven介绍

依赖管理

构建流程

使用插件

模块管理

使用mvnw

发布Artifact

网络编程

网络编程基础

TCP编程

UDP编程

发送Email

接收Email

HTTP编程

RMI远程调用

XML与JSON

XML简介

使用DOM

使用SAX

使用Jackson

使用JSON

JDBC编程

JDBC简介

JDBC查询

JDBC更新

JDBC事务

JDBC Batch

JDBC连接池

函数式编程

Lambda基础

方法引用

使用Stream

创建Stream

使用map

使用filter

使用reduce

输出集合

其他操作

设计模式

创建型模式

工厂方法

抽象工厂

生成器

原型

单例

结构型模式

适配器

桥接

组合

装饰器

外观

享元

代理

行为型模式

责任链

命令

解释器

迭代器

中介

备忘录

观察者

状态

策略

模板方法

访问者

Web开发

Web基础

Servlet入门

Servlet开发

Servlet进阶

重定向与转发

使用Session和Cookie

JSP开发

MVC开发

MVC高级开发

使用Filter

修改请求

修改响应

使用Listener

部署

Spring开发

IoC容器

IoC原理

装配Bean

使用Annotation配置

定制Bean

使用Resource

注入配置

使用条件装配

使用AOP

装配AOP

使用注解装配AOP

AOP避坑指南

访问数据库

使用JDBC

使用声明式事务

使用DAO

集成Hibernate

集成JPA

集成MyBatis

设计ORM

开发Web应用

使用Spring MVC

使用REST

集成Filter

使用Interceptor

处理CORS

国际化

异步处理

使用WebSocket

集成第三方组件

集成JavaMail

集成JMS

使用Scheduler

集成JMX

Spring Boot开发

第一个Spring Boot应用

使用开发者工具

打包Spring Boot应用

瘦身Spring Boot应用

使用Actuator

使用Profiles

使用Conditional

加载配置文件

禁用自动配置

添加Filter

集成第三方组件

集成Open API

访问Redis

集成Artemis

集成RabbitMQ

集成Kafka

Spring Cloud开发

项目架构设计

搭建项目框架

设计交易引擎

设计资产系统

设计订单系统

设计撮合引擎

设计清算系统

完成交易引擎

设计定序系统

设计API系统

设计行情系统

设计推送系统

编写UI

项目总结

廖雪峰的官方网站

©Copyright 2019-2021

Powered by iTranswarp

Feedback

License

通俗地理解哈希函数 - 知乎

通俗地理解哈希函数 - 知乎首发于老生谈科技切换模式写文章登录/注册通俗地理解哈希函数徐启已经不是小朋友了,但我还是有很多问号哈希函数不是指某种特定的函数,而是一类函数,它有各种各样的实现。百度百科给出的定义是:Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。维基百科则直接将哈希函数的词条重定向到散列函数中,定义如下:散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。百度百科与维基百科都提及了一个共同的概念:哈希函数(散列函数)能够将任意长度的输入值转变成固定长度的值输出,该值称为散列值,输出值通常为字母与数字组合。在对哈希函数有了一个定义层面的基本理解后,我在下方列举了整理后的哈希函数属性列表:定义里面讲的是哈希函数接收任意长度的输入,但在实际实现中,大家都会指明一个具体可接收的阈值,例如SHA-2最高接受(2^64-1)/8长度的字节字符串。此处需要理解的是哈希函数拥有较为庞大的输入值域,它接受长度非常长的输入值。产生固定长度的输出值。 不可逆性,已知哈希函数fn与x的哈希值无法反向求出x,当然这里的不可逆是指计算上行不通,正着算很好算,反着算在当前的计算机计算能力条件下做不到。对于特定的哈希函数,只要输入值不变,那么输出的值也是唯一不变的。哈希函数的计算时间不应过长,即通过输入值求出输出值的时间不宜过长。无冲突性,即对于输入值x,与哈希函数fn,无法求出一个值y,使得x与y的哈希值相等。但是由于上文我们知道,由于哈希函数实际上代表着一种映射(对应关系),将一个大区间上的数值映射到一个小区间上,它一定是有冲突的,这里的无冲突同样是指“求冲突在计算上行不通”,正向地计算很容易,但是反向的计算在当前的计算机能力条件下做不到,但是这种冲突的概率发生了怎么办我们后面再说。即使修改了输入值的一个比特位,也会使得输出值发送巨大的变化。哈希函数产生的映射应当保持均匀,即不要使得映射结果堆积在小区间的某一块区域。为了方便理解,我们还是来举一个例子。手机电话簿我们都知道,里面的人名依据首字母从a-z的顺序排列着的,这种排列方式能让我们快速地找到某个人,如下图所示:电话簿我们不妨认定这种映射过程为一个简陋的哈希函数,并称这个简陋的哈希函数为“电话簿哈希”。我们可以看到,“电话簿哈希”的运行机制很简单:对于任意输入值,“电话簿哈希”都取第一个字的拼音首字母输出。这个哈希函数实际上满足我们在上方列举的8条属性中的前5条的。但是从第6条开始,我们定义的这个电话簿哈希就不满足了。我们来分析一下,由于这个这个函数过于简陋,它的冲突概率是较高的,比如我们分别输入“张三”、“章五”,“电话簿哈希”都输出了“z”,对于这种冲突,在哈希函数具体实现中处理方法有多种,例如“链地址法”、“再哈希法”等,文章也有很多,需要理解的是为啥它们要这么做,好处都有啥,此处不谈。回到我们的电话簿哈希中,针对此处的冲突我们修改一下哈希函数:“将取第一个字的首字母改为取每个字的首字母”。也就是说输入“张三”与“章五”输出值变成了“zs”与“zw”,之后我们再来通过输出值执行名字到电话簿位置的映射。存放到具体位置遵循以下规则,定位依然遵循从a到z的顺序,但是出现冲突后取第二个字的首字母再排序。那么咱们这个升级后的“电话簿哈希”对于上方的输入,就有了更为具体的电话簿位置映射。此时,“张三”与“章五”无需冲突在位置“z”上,而是在位置“z”上冲突后,执行了冲突解决方法,即以第二个字首字母对冲突对象再排序,“s”排在“w”之前,因此,“张三”与“章五”应当排在电话簿的“z”下,且“张三”的位置在“章五”前面。但是这个升级后的哈希函数依然有漏洞,它还有冲突未解决,但是此处主要为了说清楚哈希函数解决冲突的一个大致套路与思想,这个哈希函数的漏洞由读者(然而一个读者也没有)自行发掘,不妨碍此处的说明。即使我们已完美解决了冲突的问题,但是回顾咱们“电话簿哈希”这个哈希函数的设计原理,咱们的电话簿哈希依然存在问题——假设我姓“刘”,那么由于我会保存很多姓“刘”的亲戚,电话簿中大量的联系人都映射在了“L”这个地址下。即使我们有了升级版的解决办法,能解决冲突的问题,但是由于映射的不均匀,大量的数据堆积在了一块区域,那么冲突发生的概率顿时就高了许多。由此导致本来查找速度极快的哈希函数速度降下来许多了——因为它需要继续执行冲突之后的遍历。这个与现实生活中的体验是一致的:我们能通过一次查找定位人名在“L”下,但是我们要具体找到目标甚至需要遍历“L”下挂着的所有对象,这是一个优秀的哈希函数所难以容忍的。我们的哈希函数“电话簿哈希”还需要升级,使得映射能够更均匀一些。这里就不再继续开脑洞如何升级“电话簿哈希”这个函数了。但是需要说明的是,就算我们将来能解决这个映射不均匀的问题,我们也会引入一个新的问题:这个哈希函数计算起来变复杂了,它为了兼顾前文我们列举的种种要求种种属性,函数考虑的东西越来越多应对的情况越来越丰富,以至于函数本身体积膨胀,计算哈希值(输出值)变的很耗费CPU(脑细胞)。试想,我们发明这个哈希函数目的就是为了快点找到目标人名,但是在找到这个人名之前我们得经过一系列的计算,那岂不是违背设计这个函数以达到“快速查找”的初衷。所以这里往往要做一个权衡,实际上很多类似的函数设计都有这个权衡在里面。手机中的电话簿实现到了这一步基本就停止了,没有再去解决映射不均匀的情况实际上也是权衡的结果。人脑根据拼音首字母来定位到特定字母目录下,而不用遍历一整个电话簿已经帮了很大忙了,而且人脑完成这一映射的速度也非常快(计算简单),所需要的仅仅是费些时间遍历某个字母下挂靠着的节点而已。哈希函数的通俗说明到这里已经说的差不多了,上文列举了哈希函数所具备的属性,也通过一个通俗的例子来辅助理解了哈希函数的种种属性与用于“快速查找”的应用场景。哈希函数十分强大,除了上文的“快速查找”场景以外,还有许多经典的场景。以下是从维基百科抄过来的关于哈希函数的应用场景。保护数据,散列值可用于唯一地识别机密信息,这个应用场景是基于属性“无冲突”的特性,但是本文关于无冲突还是太浅显,实际上各种散列函数为了实现更强的抗碰撞,都有各自更加复杂的设计。确保传递真实的消息,这个实际上是“数字签名”的内容。人们通过哈希函数获得“指纹”(摘要),打包原文与“摘要”一同发送,接收者只需要将原文进行一次哈希后与“摘要”进行匹配即可。那么如果有人将“摘要”与原文配套修改了怎么办,那我岂不是被欺骗了?实际上摘要的安全性一般还要由加密来保证,关于公钥私钥的加密解密的内容好文也有很多,此处超纲不谈。散列表,这应当是最经典的用法了,在学校我们学习散列表时都会提及,散列表是数组加链表的组成,上文我们举的关于“电话簿”的例子其实就类似于散列表的定义。性能不佳的散列函数表意味着查找操作会退化为费时的线性搜索。上方引用来自维基百科下的最后一句,对于这句引用代入到例子中同样好理解,在我们所举的“电话簿”例子中,假设电话簿中所存名字都是“刘”姓,那么所有的映射都集中到了“L”地址下了,所有的姓名挂靠在“L”地址节点下,整个哈希表退化成了一个链表,那么链表的查询能力大家是有目共睹。因此,一个优秀的散列函数对于查询是至关重要的。错误校正,这个概念同样很好理解,假设小A给小B发送一封信件,由于此信件过大,发送的时候需要拆分成三分标序后发送,到达目的地再行组装。那么,如何保证组装的数据顺序没错呢?如何保证数据发送的过程中没有丢包呢?我们只需要携带一份原完整信件的哈希值(摘要)一同发送即可,到达目的地的数据拼装好后,调用哈希函数进行一次哈希,将得到的数据与摘要进行匹配,无误则说明数据完整。语音识别,这个就触及到笔者的知识盲海了,为了不误人,附上维基百科原文截图一份。语音识别(维基百科)编辑于 2019-11-28 14:42哈希函数Java​赞同 409​​27 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录老生谈科技内容包括大数据、人工智能、物联网、web3

字符串哈希 - OI Wiki

希 - OI Wiki 跳转至 OI Wiki 字符串哈希 正在初始化搜索引擎 OI-wiki/OI-wiki 简介 比赛相关 工具软件 语言基础 算法基础 搜索 动态规划 字符串 数学 数据结构 图论 计算几何 杂项 专题 关于 Hulu OI Wiki OI-wiki/OI-wiki 简介 简介 Getting Started 关于本项目 如何参与 OI Wiki 不是什么 格式手册 数学符号表 F.A.Q. 用 Docker 部署 OI Wiki 镜像站列表 致谢 比赛相关 比赛相关 比赛相关简介 赛事 赛事 OI 赛事与赛制 ICPC/CCPC 赛事与赛制 题型 题型 题型概述 交互题 学习路线 学习资源 技巧 技巧 读入、输出优化 分段打表 常见错误 常见技巧 出题 工具软件 工具软件 工具软件简介 代码编辑工具 代码编辑工具 Vim Emacs VS Code Atom Eclipse Notepad++ Kate Dev-C++ CLion Geany Xcode GUIDE Sublime Text CP Editor 评测工具 评测工具 评测工具简介 Arbiter Cena CCR Plus Lemon 命令行 编译器 WSL (Windows 10) Special Judge Testlib Testlib Testlib 简介 通用 Generator Validator Interactor Checker Polygon OJ 工具 LaTeX 入门 Git 语言基础 语言基础 语言基础简介 C++ 基础 C++ 基础 Hello, World! C++ 语法基础 变量 运算 流程控制语句 流程控制语句 分支 循环 高级数据类型 高级数据类型 数组 结构体 联合体 指针 函数 文件操作 C++ 标准库 C++ 标准库 C++ 标准库简介 STL 容器 STL 容器 STL 容器简介 迭代器 序列式容器 关联式容器 无序关联式容器 容器适配器 STL 算法 bitset string pair C++ 进阶 C++ 进阶 类 命名空间 值类别 重载运算符 引用 常值 新版 C++ 特性 Lambda 表达式 pb_ds pb_ds pb_ds 简介 堆 平衡树 编译优化 C++ 与其他常用语言的区别 Pascal 转 C++ 急救 Python 速成 Java 速成 Java 进阶 算法基础 算法基础 算法基础简介 复杂度 枚举 模拟 递归 & 分治 贪心 排序 排序 排序简介 选择排序 冒泡排序 插入排序 计数排序 基数排序 快速排序 归并排序 堆排序 桶排序 希尔排序 锦标赛排序 tim排序 排序相关 STL 排序应用 前缀和 & 差分 二分 倍增 构造 搜索 搜索 搜索部分简介 DFS(搜索) BFS(搜索) 双向搜索 启发式搜索 A* 迭代加深搜索 IDA* 回溯法 Dancing Links Alpha-Beta 剪枝 优化 动态规划 动态规划 动态规划部分简介 动态规划基础 记忆化搜索 背包 DP 区间 DP DAG 上的 DP 树形 DP 状压 DP 数位 DP 插头 DP 计数 DP 动态 DP 概率 DP DP 优化 DP 优化 单调队列/单调栈优化 斜率优化 四边形不等式优化 状态设计优化 其它 DP 方法 字符串 字符串 字符串部分简介 字符串基础 标准库 字符串匹配 字符串哈希 字符串哈希 目录 定义 Hash 的思想 性质 解释 实现 Hash 的分析与改进 错误率 多次询问子串哈希 Hash 的应用 字符串匹配 允许  次失配的字符串匹配 最长回文子串 最长公共子字符串 确定字符串中不同子字符串的数量 例题 字典树 (Trie) 前缀函数与 KMP 算法 Boyer–Moore 算法 Z 函数(扩展 KMP) 自动机 AC 自动机 后缀数组 (SA) 后缀数组 (SA) 后缀数组简介 最优原地后缀排序算法 后缀自动机 (SAM) 后缀平衡树 广义后缀自动机 后缀树 Manacher 回文树 序列自动机 最小表示法 Lyndon 分解 Main–Lorentz 算法 数学 数学 数学部分简介 符号 进位制 位运算 二进制集合操作 平衡三进制 高精度计算 快速幂 置换和排列 弧度制与坐标系 复数 数论 数论 数论基础 素数 最大公约数 数论分块 欧拉函数 筛法 Meissel–Lehmer 算法 分解质因数 裴蜀定理 类欧几里德算法 欧拉定理 & 费马小定理 乘法逆元 线性同余方程 中国剩余定理 升幂引理 威尔逊定理 卢卡斯定理 同余方程 二次剩余 原根 离散对数 剩余 莫比乌斯反演 杜教筛 Powerful Number 筛 Min_25 筛 洲阁筛 连分数 Stern–Brocot 树与 Farey 序列 二次域 循环连分数 Pell 方程 多项式与生成函数 多项式与生成函数 多项式与生成函数简介 代数基本定理 快速傅里叶变换 快速数论变换 快速沃尔什变换 Chirp Z 变换 多项式牛顿迭代 多项式多点求值|快速插值 多项式初等函数 常系数齐次线性递推 多项式平移|连续点值平移 符号化方法 普通生成函数 指数生成函数 狄利克雷生成函数 组合数学 组合数学 排列组合 抽屉原理 容斥原理 康托展开 斐波那契数列 错位排列 卡特兰数 斯特林数 贝尔数 伯努利数 Entringer Number Eulerian Number 分拆数 范德蒙德卷积 图论计数 线性代数 线性代数 线性代数简介 向量 内积和外积 矩阵 初等变换 行列式 线性空间 线性基 线性映射 特征多项式 对角化 Jordan标准型 线性规划 线性规划 线性规划简介 单纯形算法 群论 群论 群论简介 置换群 概率论 概率论 基本概念 条件概率与独立性 随机变量 随机变量的数字特征 概率不等式 博弈论 博弈论 博弈论简介 公平组合游戏 非公平组合游戏 反常游戏 数值算法 数值算法 插值 数值积分 高斯消元 牛顿迭代法 傅里叶-莫茨金消元法 序理论 杨氏矩阵 Schreier–Sims 算法 Berlekamp–Massey 算法 数据结构 数据结构 数据结构部分简介 栈 队列 链表 哈希表 并查集 并查集 并查集 并查集复杂度 堆 堆 堆简介 二叉堆 配对堆 左偏树 块状数据结构 块状数据结构 分块思想 块状数组 块状链表 树分块 Sqrt Tree 单调栈 单调队列 ST 表 树状数组 线段树 李超线段树 区间最值操作 & 区间历史最值 划分树 二叉搜索树 & 平衡树 二叉搜索树 & 平衡树 二叉搜索树 & 平衡树 Treap Splay 树 WBLT Size Balanced Tree AVL 树 B 树 B+ 树 替罪羊树 Leafy Tree 笛卡尔树 红黑树 左偏红黑树 AA 树 2-3 树 2-3-4 树 跳表 可持久化数据结构 可持久化数据结构 可持久化数据结构简介 可持久化线段树 可持久化块状数组 可持久化平衡树 可持久化字典树 可持久化可并堆 树套树 树套树 线段树套线段树 平衡树套线段树 线段树套平衡树 树状数组套权值线段树 分块套树状数组 K-D Tree 动态树 动态树 Link Cut Tree 全局平衡二叉树 Euler Tour Tree Top Tree 析合树 PQ 树 手指树 霍夫曼树 图论 图论 图论部分简介 图论相关概念 图的存储 DFS(图论) BFS(图论) 树上问题 树上问题 树基础 树的直径 最近公共祖先 树的重心 树链剖分 树上启发式合并 虚树 树分治 动态树分治 AHU 算法 树哈希 树上随机游走 矩阵树定理 有向无环图 拓扑排序 最小生成树 斯坦纳树 最小树形图 最小直径生成树 最短路 拆点 差分约束 k 短路 同余最短路 连通性相关 连通性相关 强连通分量 双连通分量 割点和桥 圆方树 点/边连通度 环计数问题 2-SAT 欧拉图 哈密顿图 二分图 最小环 平面图 图的着色 网络流 网络流 网络流简介 最大流 最小割 费用流 上下界网络流 Stoer–Wagner 算法 图的匹配 图的匹配 图匹配 增广路 二分图最大匹配 二分图最大权匹配 一般图最大匹配 一般图最大权匹配 Prüfer 序列 LGV 引理 弦图 最大团搜索算法 支配树 图上随机游走 计算几何 计算几何 计算几何部分简介 二维计算几何基础 三维计算几何基础 距离 Pick 定理 三角剖分 凸包 扫描线 旋转卡壳 半平面交 平面最近点对 随机增量法 反演变换 计算几何杂项 杂项 杂项 杂项简介 离散化 双指针 离线算法 离线算法 离线算法简介 CDQ 分治 整体二分 莫队算法 莫队算法 莫队算法简介 普通莫队算法 带修改莫队 树上莫队 回滚莫队 二维莫队 莫队二次离线 莫队配合 bitset 分数规划 随机化 随机化 随机函数 随机化技巧 爬山算法 模拟退火 悬线法 计算理论基础 字节顺序 约瑟夫问题 格雷码 表达式求值 在一台机器上规划任务 主元素问题 Garsia–Wachs 算法 15-puzzle Kahan 求和 珂朵莉树/颜色段均摊 专题 专题 RMQ 并查集应用 括号序列 线段树与离线询问 关于 Hulu 关于 Hulu 关于 Hulu 目录 定义 Hash 的思想 性质 解释 实现 Hash 的分析与改进 错误率 多次询问子串哈希 Hash 的应用 字符串匹配 允许  次失配的字符串匹配 最长回文子串 最长公共子字符串 确定字符串中不同子字符串的数量 例题 字符串哈希定义我们定义一个把字符串映射到整数的函数 ,这个 称为是 Hash 函数。我们希望这个函数 可以方便地帮我们判断两个字符串是否相等。Hash 的思想Hash 的核心思想在于,将输入映射到一个值域较小、可以方便比较的范围。Warning 这里的「值域较小」在不同情况下意义不同。 在 哈希表 中,值域需要小到能够接受线性的空间与时间复杂度。 在字符串哈希中,值域需要小到能够快速比较(、 都是可以快速比较的)。 同时,为了降低哈希冲突率,值域也不能太小。性质具体来说,哈希函数最重要的性质可以概括为下面两条:在 Hash 函数值不一样的时候,两个字符串一定不一样;在 Hash 函数值一样的时候,两个字符串不一定一样(但有大概率一样,且我们当然希望它们总是一样的)。 我们将 Hash 函数值一样但原字符串不一样的现象称为哈希碰撞。解释我们需要关注的是什么?时间复杂度和 Hash 的准确率。通常我们采用的是多项式 Hash 的方法,对于一个长度为 的字符串 来说,我们可以这样定义多项式 Hash 函数:。例如,对于字符串 ,其哈希函数值为 。特别要说明的是,也有很多人使用的是另一种 Hash 函数的定义,即 ,这种定义下,同样的字符串 的哈希值就变为了 了。显然,上面这两种哈希函数的定义函数都是可行的,但二者在之后会讲到的计算子串哈希值时所用的计算式是不同的,因此千万注意 不要弄混了这两种不同的 Hash 方式。由于前者的 Hash 定义计算更简便、使用人数更多、且可以类比为一个 进制数来帮助理解,所以本文下面所将要讨论的都是使用 来定义的 Hash 函数。下面讲一下如何选择 和计算哈希碰撞的概率。这里 需要选择一个素数(至少要比最大的字符要大), 可以任意选择。如果我们用未知数 替代 ,那么 实际上是多项式环 上的一个多项式。考虑两个不同的字符串 ,有 。我们记 ,其中 。可以发现 是一个 阶的非零多项式。如果 与 在 的情况下哈希碰撞,则 是 的一个根。由于 在 是一个域(等价于 是一个素数,这也是为什么 要选择素数的原因)的时候,最多有 个根,如果我们保证 是从 之间均匀随机选取的,那么 与 碰撞的概率可以估计为 。简单验算一下,可以发现如果两个字符串长度都是 的时候,哈希碰撞的概率为 ,此时不可能发生碰撞。实现参考代码:(效率低下的版本,实际使用时一般不会这么写)C++Python 1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18using std::string;

const int M = 1e9 + 7;

const int B = 233;

typedef long long ll;

int get_hash(const string& s) {

int res = 0;

for (int i = 0; i < s.size(); ++i) {

res = ((ll)res * B + s[i]) % M;

}

return res;

}

bool cmp(const string& s, const string& t) {

return get_hash(s) == get_hash(t);

}

1

2

3

4

5

6

7

8

9

10

11M = int(1e9 + 7)

B = 233

def get_hash(s):

res = 0

for char in s:

res = (res * B + ord(char)) % M

return res

def cmp(s, t):

return get_hash(s) == get_hash(t)

Hash 的分析与改进错误率假定哈希函数将字符串随机地映射到大小为 的值域中,总共有 个不同的字符串,那么未出现碰撞的概率是 (第 次进行哈希时,有 的概率不会发生碰撞)。在随机数据下,若 ,,未出现碰撞的概率是极低的。所以,进行字符串哈希时,经常会对两个大质数分别取模,这样的话哈希函数的值域就能扩大到两者之积,错误率就非常小了。多次询问子串哈希单次计算一个字符串的哈希值复杂度是 ,其中 为串长,与暴力匹配没有区别,如果需要多次询问一个字符串的子串的哈希值,每次重新计算效率非常低下。一般采取的方法是对整个字符串先预处理出每个前缀的哈希值,将哈希值看成一个 进制的数对 取模的结果,这样的话每次就能快速求出子串的哈希了:令 表示 ,即原串长度为 的前缀的哈希值,那么按照定义有 现在,我们想要用类似前缀和的方式快速求出 ,按照定义有字符串 的哈希值为 对比观察上述两个式子,我们发现 成立(可以手动代入验证一下),因此我们用这个式子就可以快速得到子串的哈希值。其中 可以 的预处理出来然后 的回答每次询问(当然也可以快速幂 的回答每次询问)。Hash 的应用字符串匹配求出模式串的哈希值后,求出文本串每个长度为模式串长度的子串的哈希值,分别与模式串的哈希值比较即可。允许 次失配的字符串匹配问题:给定长为 的源串 ,以及长度为 的模式串 ,要求查找源串中有多少子串与模式串匹配。 与 匹配,当且仅当 与 长度相同,且最多有 个位置字符不同。其中 ,。这道题无法使用 KMP 解决,但是可以通过哈希 + 二分来解决。枚举所有可能匹配的子串,假设现在枚举的子串为 ,通过哈希 + 二分可以快速找到 与 第一个不同的位置。之后将 与 在这个失配位置及之前的部分删除掉,继续查找下一个失配位置。这样的过程最多发生 次。总的时间复杂度为 。最长回文子串二分答案,判断是否可行时枚举回文中心(对称轴),哈希判断两侧是否相等。需要分别预处理正着和倒着的哈希值。时间复杂度 。这个问题可以使用 manacher 算法 在 的时间内解决。通过哈希同样可以 解决这个问题,具体方法就是记 表示以 作为结尾的最长回文的长度,那么答案就是 。考虑到 ,因此我们只需要暴力从 开始递减,直到找到第一个回文即可。记变量 表示当前枚举的 ,初始时为 ,则 在每次 增大的时候都会增大 ,之后每次暴力循环都会减少 ,故暴力循环最多发生 次,总的时间复杂度为 。最长公共子字符串问题:给定 个总长不超过 的非空字符串,查找所有字符串的最长公共子字符串,如果有多个,任意输出其中一个。其中 。很显然如果存在长度为 的最长公共子字符串,那么 的公共子字符串也必定存在。因此我们可以二分最长公共子字符串的长度。假设现在的长度为 ,check(k) 的逻辑为我们将所有所有字符串的长度为 的子串分别进行哈希,将哈希值放入 个哈希表中存储。之后求交集即可。时间复杂度为 。确定字符串中不同子字符串的数量问题:给定长为 的字符串,仅由小写英文字母组成,查找该字符串中不同子串的数量。为了解决这个问题,我们遍历了所有长度为 的子串。对于每个长度为 ,我们将其 Hash 值乘以相同的 的幂次方,并存入一个数组中。数组中不同元素的数量等于字符串中长度不同的子串的数量,并此数字将添加到最终答案中。为了方便起见,我们将使用 作为 Hash 的前缀字符,并定义 。参考代码 1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25int count_unique_substrings(string const& s) {

int n = s.size();

const int b = 31;

const int m = 1e9 + 9;

vector b_pow(n);

b_pow[0] = 1;

for (int i = 1; i < n; i++) b_pow[i] = (b_pow[i - 1] * b) % m;

vector h(n + 1, 0);

for (int i = 0; i < n; i++)

h[i + 1] = (h[i] + (s[i] - 'a' + 1) * b_pow[i]) % m;

int cnt = 0;

for (int l = 1; l <= n; l++) {

set hs;

for (int i = 0; i <= n - l; i++) {

long long cur_h = (h[i + l] + m - h[i]) % m;

cur_h = (cur_h * b_pow[n - i - 1]) % m;

hs.insert(cur_h);

}

cnt += hs.size();

}

return cnt;

}

例题CF1200E Compress Words 给你若干个字符串,答案串初始为空。第 步将第 个字符串加到答案串的后面,但是尽量地去掉重复部分(即去掉一个最长的、是原答案串的后缀、也是第 个串的前缀的字符串),求最后得到的字符串。 字符串个数不超过 ,总长不超过 。 题解 每次需要求最长的、是原答案串的后缀、也是第 个串的前缀的字符串。枚举这个串的长度,哈希比较即可。 当然,这道题也可以使用 KMP 算法 解决。 参考代码 1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80#include <bits/stdc++.h>

using namespace std;

const int L = 1e6 + 5;

const int HASH_CNT = 2;

int hashBase[HASH_CNT] = {29, 31};

int hashMod[HASH_CNT] = {int(1e9 + 9), 998244353};

struct StringWithHash {

char s[L];

int ls;

int hsh[HASH_CNT][L];

int pwMod[HASH_CNT][L];

void init() { // 初始化

ls = 0;

for (int i = 0; i < HASH_CNT; ++i) {

hsh[i][0] = 0;

pwMod[i][0] = 1;

}

}

StringWithHash() { init(); }

void extend(char c) {

s[++ls] = c; // 记录字符数和每一个字符

for (int i = 0; i < HASH_CNT; ++i) { // 双哈希的预处理

pwMod[i][ls] =

1ll * pwMod[i][ls - 1] * hashBase[i] % hashMod[i]; // 得到b^ls

hsh[i][ls] = (1ll * hsh[i][ls - 1] * hashBase[i] + c) % hashMod[i];

}

}

vector getHash(int l, int r) { // 得到哈希值

vector res(HASH_CNT, 0);

for (int i = 0; i < HASH_CNT; ++i) {

int t =

(hsh[i][r] - 1ll * hsh[i][l - 1] * pwMod[i][r - l + 1]) % hashMod[i];

t = (t + hashMod[i]) % hashMod[i];

res[i] = t;

}

return res;

}

};

bool equal(const vector &h1, const vector &h2) {

assert(h1.size() == h2.size());

for (unsigned i = 0; i < h1.size(); i++)

if (h1[i] != h2[i]) return false;

return true;

}

int n;

StringWithHash s, t;

char str[L];

void work() {

int len = strlen(str); // 取字符串长度

t.init();

for (int j = 0; j < len; ++j) t.extend(str[j]);

int d = 0;

for (int j = min(len, s.ls); j >= 1; --j) {

if (equal(t.getHash(1, j), s.getHash(s.ls - j + 1, s.ls))) { // 比较哈希值

d = j;

break;

}

}

for (int j = d; j < len; ++j) s.extend(str[j]); // 更新答案数组

}

int main() {

scanf("%d", &n);

for (int i = 1; i <= n; ++i) {

scanf("%s", str);

work();

}

printf("%s\n", s.s + 1);

return 0;

}

本页面部分内容译自博文 строковый хеш 与其英文翻译版 String Hashing。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。本页面最近更新:2023/10/4 21:50:08,更新历史发现错误?想一起完善? 在 GitHub 上编辑此页!本页面贡献者:iamtwz, 1292224662, algoriiiiithm, dkz051, Enter-tainer, GldHkkowo, Haohu Shen, HeRaNO, ImpleLee, Ir1d, kenlig, ksyx, Marcythm, Menci, mgt, ouuan, shawlleyw, ShuYuMo2003, sshwy, szdytom, taodaling, Tiphereth-A, wangchong, wendajiang, Xeonacid, Yanjun-Zhao, zyouxam本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用Copyright © 2016 - 2024 OI Wiki Team Made with Material for MkDocs 最近更新:7ff011ae, 2024-03-

Python hash() 函数 | 菜鸟教程

Python hash() 函数 | 菜鸟教程

菜鸟教程 -- 学的不仅是技术,更是梦想!

首页

HTML

CSS

JavaScript

Vue

Bootstrap

NodeJS

Python3

Python2

Java

C

C++

C#

Go

SQL

Linux

jQuery

本地书签

首页

HTML

CSS

JS

本地书签

Search

Python3 教程

Python2 教程

Vue3 教程

vue2 教程

Bootstrap3 教程

Bootstrap4 教程

Bootstrap5 教程

Bootstrap2 教程

Python 基础教程

Python 基础教程

Python 简介

Python 环境搭建

Python 中文编码

Python 基础语法

Python 变量类型

Python 运算符

Python 条件语句

Python 循环语句

Python While 循环语句

Python for 循环语句

Python 循环嵌套

Python break 语句

Python continue 语句

Python pass 语句

Python Number(数字)

Python 字符串

Python 列表(List)

Python 元组

Python 字典(Dictionary)

Python 日期和时间

Python 函数

Python 模块

Python 文件I/O

Python File 方法

Python 异常处理

Python OS 文件/目录方法

Python 内置函数

Python 高级教程

Python 面向对象

Python 正则表达式

Python CGI 编程

Python MySQL

Python 网络编程

Python SMTP

Python 多线程

Python XML 解析

Python GUI 编程(Tkinter)

Python2.x 与 3​​.x 版本区别

Python IDE

Python JSON

Python AI 绘画

Python 100例

Python 测验

Python complex() 函数

Python set() 函数

Python hash() 函数

Python 内置函数

描述

hash() 用于获取取一个对象(字符串或者数值等)的哈希值。

语法

hash 语法:

hash(object)

参数说明:

object -- 对象;

返回值

返回对象的哈希值。

实例

以下实例展示了 hash 的使用方法:

>>>hash('test') # 字符串

2314058222102390712

>>> hash(1) # 数字

1

>>> hash(str([1,2,3])) # 集合

1335416675971793195

>>> hash(str(sorted({'1':1}))) # 字典

7666464346782421378

>>>

Python 内置函数

Python complex() 函数

Python set() 函数

3 篇笔记

写笔记

#0   忘忧北萱草  wyb***qq.com 34hash() 函数可以应用于数字、字符串和对象,不能直接应用于 list、set、dictionary。

在 hash() 对对象使用时,所得的结果不仅和对象的内容有关,还和对象的 id(),也就是内存地址有关。

class Test:

def __init__(self, i):

self.i = i

for i in range(10):

t = Test(1)

print(hash(t), id(t))

输出结果:

(277855628, 4445690048)

(277855637, 4445690192)

(277855628, 4445690048)

(277855637, 4445690192)

(277855628, 4445690048)

(277855637, 4445690192)

(277855628, 4445690048)

(277855637, 4445690192)

(277855628, 4445690048)

(277855637, 4445690192)忘忧北萱草   忘忧北萱草  wyb***qq.com6年前 (2018-04-06)

#0   冷梦  149***2305@qq.com 29hash() 函数的用途

hash() 函数的对象字符不管有多长,返回的 hash 值都是固定长度的,也用于校验程序在传输过程中是否被第三方(木马)修改,如果程序(字符)在传输过程中被修改hash值即发生变化,如果没有被修改,则 hash 值和原始的 hash 值吻合,只要验证 hash 值是否匹配即可验证程序是否带木马(病毒)。

name1='正常程序代码'

name2='正常程序代码带病毒'

print(hash(name1)) # 2403189487915500087

print(hash(name2)) # -8751655075885266653

冷梦   冷梦  149***2305@qq.com5年前 (2018-10-10)

#0   cnvsss  xia***oud1@hotmail.com 14对于 忘忧北萱草 的笔记进行一下补充:

在 hash() 对对象使用时,所得的结果和对象的内容无关,只和对象的 id(),也就是内存地址有关。

class foo(object):

def __init__(self,x):

self.x=x

def get_x(self):

return self.x

def set_x(self,x):

self.x=x

test=foo(1)

print(hash(test),test.get_x(),id(test))

test.set_x(0)

print(hash(test),test.get_x(),id(test))

输出:

3518817 1 56301072

3518817 0 56301072cnvsss   cnvsss  xia***oud1@hotmail.com3年前 (2020-12-12)

点我分享笔记

取消

分享笔记

昵称昵称 (必填)

邮箱邮箱 (必填)

引用地址引用地址

分类导航

HTML / CSSHTML 教程HTML5 教程CSS 教程CSS3 教程Bootstrap3 教程Bootstrap4 教程Bootstrap5 教程Font Awesome 教程Foundation 教程 JavaScriptJavaScript 教程HTML DOM 教程jQuery 教程AngularJS 教程AngularJS2 教程Vue.js 教程Vue3 教程React 教程TypeScript 教程jQuery UI 教程jQuery EasyUI 教程Node.js 教程AJAX 教程JSON 教程Echarts 教程Chart.js 教程Highcharts 教程Google 地图 教程 服务端Python 教程Python2.x 教程Linux 教程Docker 教程Ruby 教程Java 教程C 教程C++ 教程Perl 教程Servlet 教程JSP 教程Lua 教程Rust 教程Scala 教程Go 教程PHP 教程数据结构与算法Django 教程FastAPI 教程Zookeeper 教程设计模式正则表达式Maven 教程Verilog 教程ASP 教程AppML 教程VBScript 教程 数据库SQL 教程MySQL 教程PostgreSQL 教程SQLite 教程MongoDB 教程Redis 教程Memcached 教程 数据分析Python 教程NumPy 教程Pandas 教程Matplotlib 教程Scipy 教程R 教程Julia 教程 移动端Android 教程Swift 教程jQuery Mobile 教程ionic 教程Kotlin 教程 XML 教程XML 教程DTD 教程XML DOM 教程XSLT 教程XPath 教程XQuery 教程XLink 教程XPointer 教程XML Schema 教程XSL-FO 教程SVG 教程 ASP.NETASP.NET 教程C# 教程Web Pages 教程Razor 教程MVC 教程Web Forms 教程 Web ServiceWeb Service 教程WSDL 教程SOAP 教程RSS 教程RDF 教程 开发工具Eclipse 教程Git 教程Svn 教程Markdown 教程 网站建设HTTP 教程网站建设指南浏览器信息网站主机教程TCP/IP 教程W3C 教程网站品质

Advertisement

反馈/建议

在线实例

·HTML 实例

·CSS 实例

·JavaScript 实例

·Ajax 实例

·jQuery 实例

·XML 实例

·Java 实例

字符集&工具

· HTML 字符集设置

· HTML ASCII 字符集

· JS 混淆/加密

· PNG/JPEG 图片压缩

· HTML 拾色器

· JSON 格式化工具

· 随机数生成器

最新更新

·

Rust 宏

·

Seaborn 教程

·

Pandas 相关性分析

·

31.2k star, 免...

·

Dev Home —...

·

免费开源的 AI ...

·

11.2k star, 免...

站点信息

·

意见反馈

·

免责声明

·

关于我们

·

文章归档

关注微信

Copyright © 2013-2024 菜鸟教程 

runoob.com All Rights Reserved. 备案号:闽ICP备15012807号-1

微信关注