散列和encryptionalgorithm之间的根本区别

我看到了哈希和encryptionalgorithm之间的混乱,我想听到更多的专家build议:

  1. 何时使用哈希与encryption

  2. 什么使散列或encryptionalgorithm不同(从理论/math水平),即什么使得散列不可逆(没有彩虹树的帮助)

这里有一些类似的 SO问题没有像我期待的那么详细:

混淆,散列和encryption有什么区别?
encryption和散列之间的区别

那么,你可以在维基百科查看它…但是既然你想要一个解释,我会尽我所能:

哈希函数

它们提供了任意长度input和(通常)固定长度(或更小长度)输出之间的映射。 它可以是从简单的crc32到完整的encryption散列函数,如MD5或SHA1 / 2/256/512。 关键是有一个单向映射正在进行。 因为每个函数产生的输出都小于它的input(如果你把每个可能的1mb文件送到MD5中,你将会碰到很多的冲突),它总是一个多:1的映射(意味着总会有冲突)。

他们很难(或不可能实际上)扭转的原因是因为他们如何在内部工作。 大多数密码散列函数迭代input集多次以产生输出。 所以,如果我们看看每个固定长度的input块(这是与algorithm有关的),散列函数将调用当前状态。 然后它将遍历状态并将其更改为新状态,并将其用作自身反馈(MD5对每个512位数据块执行64次)。 然后它以某种方式将来自所有这些迭代的结果状态合并在一起以形成结果散列。

现在,如果你想解码哈希,你首先需要弄清楚如何将给定的哈希分解为它的迭代状态(1个input的可能性小于一个数据块的大小,许多用于较大的input)。 那么你需要颠倒每个状态的迭代。 现在,为了解释为什么这是非常困难的,试想从下面的公式推导ab10 = a + b 。 有10个正面组合可以工作。 现在循环一堆: tmp = a + b; a = b; b = tmp tmp = a + b; a = b; b = tmp tmp = a + b; a = b; b = tmp 。 对于64次迭代,你将有超过10 ^ 64个可能性尝试。 这只是一个简单的补充,其中一些状态从迭代到迭代都保留下来。 真正的哈希函数做了大于1次的操作(MD5对4个状态variables执行了大约15次操作)。 而且由于下一次迭代取决于前一次的状态,前一次在创build当前状态时被破坏,所以要确定导致给定输出状态的input状态(每次迭代不less于几次)几乎是不可能的。 结合这一点,涉及大量的可能性,甚至解码MD5将花费近乎无限的(但不是无限的)资源量。 如此多的资源,如果您对input的大小(对于较小的input)有一个想法,甚至比尝试解码这个散列还要便宜得多。

encryption函数

它们提供了任意长度input和输出之间的1:1映射。 它们总是可逆的。 重要的是要注意的是,使用某种方法是可逆的。 对于给定的键,它总是1:1。 现在,有多个input:密钥对可能会生成相同的输出(事实上,通常取决于encryption函数)。 良好的encryption数据与随机噪声无法区分。 这不同于始终具有一致格式的良好散列输出。

用例

当你想比较一个值,但不能存储简单表示(出于任何原因)时,使用散列函数。 密码应该非常适合这个用例,因为出于安全原因(不应该)将它们存储为纯文本。 但是如果你想检查盗版音乐文件的文件系统呢? 每个音乐文件存储3 MB是不切实际的。 所以相反,采取文件的散列,并存储(MD5将存储16字节,而不是3MB)。 这样,你只需散列每个文件,并与存储的散列数据库进行比较(由于重新编码,更改文件头等,实际上这并不起作用,但是这是一个示例用例)。

在检查input数据的有效性时使用散列函数。 这就是他们所devise的。 如果你有2个input,并且想检查它们是否相同,那么通过散列函数运行这两个input。 对于小的input大小,假设一个好的散列函数,碰撞的概率是天文数字低的。 这就是为什么build议使用密码。 对于最多32个字符的密码,md5具有4倍的输出空间。 SHA1有6倍的输出空间(大约)。 SHA512的输出空间约为16倍。 你并不在乎密码什么,你关心的是和存储的一样。 这就是为什么你应该使用哈希密码。

只要需要将input数据取出,请使用encryption。 注意这个词的需要 。 如果您要存储信用卡号码,则需要在某个时间点将其退出,但不要将其存储为纯文本。 所以,相反,存储encryption版本,并保持尽可能安全的关键。

哈希函数也非常适合签署数据。 例如,如果您使用的是HMAC,则通过对已知但未传输的值(秘密值)连接的数据进行散列来签署一段数据。 所以,你发送纯文本和HMAC散列。 然后,接收器简单地用提供的数据散列已知的值,并检查它是否匹配发送的HMAC。 如果是相同的,你知道没有秘密价值的一方的篡改。 这通常用于HTTP框架的安全cookie系统,以及通过HTTP进行消息传输,您希望在数据中保证完整性。

有关密码散列的说明:

密码散列函数的一个关键特征是它们应该非常快速地创build,而且很难/很慢地反转(以至于几乎不可能)。 这带来了密码问题。 如果你存储sha512(password) ,你没有做一个防止彩虹表或蛮力攻击的事情。 请记住,哈希函数是为了速度而devise的。 所以攻击者通过哈希函数运行一个字典并testing每个结果是微不足道的。

添加一个盐有助于解决问题,因为它将一些未知的数据添加到哈希中。 因此,他们不需要find与md5(foo)相匹配的东西,而是需要find一些添加到已知盐中的东西,从而生成md5(foo.salt) (这是非常困难的)。 但是,如果他们知道盐的含义,就不能解决速度问题。

所以,有办法处理这个。 一种stream行的方法被称为关键强化 (或关键拉伸)。 基本上,你迭代一个哈希多次(通常是数千)。 这有两件事。 首先,它大大减慢了哈希algorithm的运行时间。 其次,如果执行得当(在每次迭代中传递input和返回的盐)实际上增加了输出的熵(可用空间),从而减less了冲突的可能性。 一个简单的实现是:

 var hash = password + salt; for (var i = 0; i < 5000; i++) { hash = sha512(hash + password + salt); } 

还有其他更标准的实现,例如PBKDF2 , BCrypt 。 但是这个技术被很多安全相关的系统(如PGP,WPA,Apache和OpenSSL)所使用。

底线, hash(password)不够好。 hash(password + salt)是更好的,但仍然不够好…使用拉伸哈希机制来产生你的密码哈希…

另一个关于微不足道的说明

在任何情况下都不要将一个散列的输出直接送回散列函数

 hash = sha512(password + salt); for (i = 0; i < 1000; i++) { hash = sha512(hash); // <-- Do NOT do this! } 

这个原因与碰撞有关。 请记住,所有哈希函数都有冲突,因为可能的输出空间(可能的输出数)小于input空间。 为了明白为什么,让我们看看会发生什么。 为了说明这一点,让我们假设sha1()的碰撞几率为0.001%(实际情况得多 ,但是出于演示的目的)。

 hash1 = sha1(password + salt); 

现在, hash1的冲突概率为0.001%。 但是当我们做下一个hash2 = sha1(hash1);hash1所有冲突hash1自动成为hash2冲突 。 所以现在,我们有hash1的速率为0.001%,第二个sha1()调用增加了。 所以现在hash2的碰撞概率是0.002%。 这是机会的两倍! 每次迭代将增加0.001%的碰撞机会。 所以,经过1000次迭代,碰撞的概率从一个微小的0.001%跳到了1%。 现在,退化是线性的,实际的概率小得多,但效果是一样的(对md5单次碰撞的概率估计为1 /(2 128 )或1 /(3×10 38 )。这似乎很小,感谢生日的攻击,它并不像看起来那么小)。

相反,通过每次重新添加salt和密码,您都将数据重新引入哈希函数。 所以任何特定轮次的碰撞不再是下一轮的碰撞。 所以:

 hash = sha512(password + salt); for (i = 0; i < 1000; i++) { hash = sha512(hash + password + salt); } 

与原生sha512函数具有相同的碰撞机会。 这是你想要的。 改用它。

散列函数可以被认为是烘烤一块面包。 你从input(面粉,水,酵母等等)开始,在应用散列函数(混合+烘烤)后,最终输出:一条面包。

换一种方式是非常困难的 – 你不能真正把面包分离成面粉,水,酵母 – 在烘烤过程中有一些丢失了,你永远无法确切知道有多less水或面粉或酵母被用于一个特定的面包,因为这个信息被哈希函数(又名烤箱)破坏了。

许多不同的inputvariables理论上会产生相同的面包(例如2杯水和1茶匙酵母产生与2.1杯水和0.9tsbp酵母完全相同的面包),但是给出这些面包之一,你不能说究竟是什么组合的投入产生了它。

另一方面,encryption可以被视为一个保险箱。 无论你放在哪里,只要你拥有锁在首位的钥匙,就会回来。 这是一个对称操作。 给定一个键和一些input,你会得到一个确定的输出。 鉴于输出和相同的关键,​​你会回到原来的input。 这是一个1:1的映射。

当你不想恢复原始input时使用散列,当你这样做的时候使用encryption。

哈希需要一些input,并把它变成一些比特(通常被认为是一个数字,如32位整数,64位整数等)。 同样的input将总是产生相同的散列,但是你在这个过程中主要丢失了信息,所以你不能可靠地再现原始input(然而有一些注意事项)。

encryption主要是保留你joinencryptionfunction的所有信息,只是使任何人都难以(不可能)任何人在没有特定密钥的情况下回到原始input。

简单的哈希例子

这里有一个简单的例子来帮助你理解为什么哈希不能(在一般情况下)取回原始input。 假设我正在创build一个1位散列。 我的散列函数需要一个位串作为input,如果在inputstring中设置了偶数位,则将散列设置为1;否则,如果存在奇数,则设置为0。

例:

 Input Hash 0010 0 0011 1 0110 1 1000 0 

请注意,有许多input值导致散列值为0,导致散列值为1的许多input值。如果您知道散列值为0,则无法确定原始input是什么。

顺便说一句,这个1位散列不是完全devise的…看看奇偶校验位 。

encryption的简单例子

你可以使用一个简单的字母replace来encryption文本,比如说如果input是A,那么你写的是B.如果input是B,那么你写C。一直到字母的末尾,如果input是Z,那么你再写一次。

 Input Encrypted CAT DBU ZOO APP 

就像简单的哈希示例一样,这种types的encryption在历史上一直使用 。

我的一个class轮…总的来说访员想要下面的答案。

散列是一种方式。 你不能从一个哈希代码转换你的数据/string。

encryption是2种方式 – 如果您有密钥,您可以再次解密encryption的string。

让我添加一些有关散列和encryption/解密技术的基本概述。

哈希:

如果您再次散列任何纯文本则无法从散列文本中获取相同的纯文本 。 简而言之,这是一个单向的过程。

散列


encryption和解密:

如果使用密钥再次encryption任何纯文本 ,则可以通过对具有相同(对称)/不同(非对称) 密钥的encryption文本进行解密 来获得相同的纯文本

加密和解密


更新:解决编辑问题中提到的问题。

1.何时使用哈希与encryption

如果你想发送一个文件, 哈希是有用的。 但是你担心别人可能会拦截文件并改变它。 因此,接收者可以确保它是正确的文件的方式是如果您公开发布散列值。 这样收件人可以计算接收到的文件的散列值,并检查它是否与散列值相匹配。

如果你说有一个消息发送给某人, encryption是好的。 您使用密钥encryption消息,接收方使用相同的密钥(或甚至不同的密钥)进行解密,以获取原始消息。 学分


2.什么使散列或encryptionalgorithm不同(从理论/math水平),即什么使得哈希不可逆(没有彩虹树的帮助)

基本上, 哈希是一种丢失信息但不encryption的操作 。 让我们来看看简单的math方法的差异, 以便我们容易理解 ,当然两者都有更复杂的math运算和重复涉及

encryption/解密(可逆):

增加

 4 + 3 = 7 

这可以通过取和和减去其中一个加数来逆转

 7 - 3 = 4 

乘法

 4 * 5 = 20 

这可以通过采取产品和其中一个因素来扭转

 20 / 4 = 5 

所以,在这里我们可以假设其中一个加数/因子是一个decrpytion键,结果(7,20)是一个excrypted文本。


哈希(不可逆):

模块划分

 22 % 7 = 1 

这是不能逆转的,因为您不能对商和分红进行操作来重构除数(反之亦然)。

你能find一个操作来填写'?'的位置吗? 是什么?

 1 ? 7 = 22 1 ? 22 = 7 

所以散列函数具有与模分割相同的math质量并丢失信息。

学分

哈希函数将可变大小的文本转换为固定大小的文本。

哈希

来源: https : //en.wikipedia.org/wiki/Hash_function

encryption函数通过使用encryption密钥将文本转换为无意义的密文,反之亦然。 在这里输入图像描述

来源: https : //en.wikipedia.org/wiki/Encryption

让我们看看它的行动。 我用它的PHP。

HASH:

 $str = 'My age is 29'; $hash = hash('sha1', $str); echo $hash; // OUTPUT: 4d675d9fbefc74a38c89e005f9d776c75d92623e 

DEHASH:

SHA1是单向散列。 这意味着你不能去散列哈希。

但是,你可以蛮力的哈希。

请参阅: https : //hashkiller.co.uk/sha1-decrypter.aspx 。

你可以在这个网站find一个MD5 dehasher: http ://md5portal.com/。

encryption:

 $cipher = MCRYPT_RIJNDAEL_128; $key = 'A_KEY'; $data = 'My age is 29'; $mode = MCRYPT_MODE_ECB; $encryptedData = mcrypt_encrypt($cipher, $key , $data , $mode); var_dump($encryptedData); //OUTPUT: string '„Ùòyªq³¿ì¼üÀpå' (length=16) 

解密:

 $decryptedData = mcrypt_decrypt($cipher, $key , $encryptedData, $mode); $decryptedData = rtrim($decryptedData, "\0\4"); // Remove the nulls and EOTs at the END var_dump($decryptedData); //OUTPUT: string 'My age is 29' (length=12) 

对称encryption:

对称encryption也可以被称为共享密钥或共享秘密encryption。 在对称encryption中,单个密钥既用于encryption,也用于解密stream量。

在这里输入图像描述

不对称encryption:

非对称encryption也被称为公钥密码术。 非对称encryption与对称encryption的不同之处主要在于使用两个密钥:一个用于encryption,一个用于解密。 最常见的非对称encryptionalgorithm是RSA

与对称encryption相比,非对称encryption会带来很高的计算负担,并且往往会慢得多。 因此,通常不用于保护有效载荷数据。 相反,它的主要优势是能够通过非安全的媒介(例如互联网)build立一个安全的渠道。 这是通过交换公钥来完成的,公钥只能用来encryption数据。 互补的私钥,永远不会共享,用于解密。

在这里输入图像描述

哈希:

最后,哈希是一种不同于encryption的encryption安全forms。 鉴于encryption是一个用于首先encryption和解密消息的两步过程,散列将消息凝聚成不可逆的固定长度值或散列。 networking中常见的两种哈希algorithm是MD5SHA-1

在这里输入图像描述

在这里阅读更多: http : //packetlife.net/blog/2010/nov/23/symmetric-asymmetric-encryption-hashing/

当涉及到传输数据的安全性,即使用encryption的双向通信。所有的encryption都需要一个密钥

当涉及到授权你使用哈希。哈希没有关键

散列可以获取任意数量的数据(二进制或文本),并创build代表数据校验和的恒定长度散列。 例如,散列可能是16个字节。 不同的哈希algorithm产生不同大小的哈希。 您显然不能从哈希中重新创build原始数据,但是您可以再次哈希数据以查看是否生成了相同的哈希值。 基于Unix的单向口令以这种方式工作。 密码存储为一个散列值,并login到系统上,您键入的密码被散列,散列值与真实密码的散列进行比较。 如果他们匹配,那么你必须input正确的密码

为什么哈希不可逆转:

散列是不可逆的,因为input到散列映射不是1对1。 有两个input映射到相同的散列值通常被称为“散列冲突”。 出于安全的目的,“良好”哈希函数的一个特性是在实际使用中碰撞是罕见的。

  1. 当你只需要一个方法时使用散列。 例如,对于系统中的密码,您使用散列,因为您将只validation用户在散列之后input的值与存储库中的值匹配。 有了encryption,你可以用两种方法。

  2. 哈希algorithm和encryptionalgorithm只是mathalgorithm。 所以在这方面,他们没有什么不同 – 它只是math公式。 虽然语义上明智,散列(单向)和encryption(双向)之间有很大的区别。 为什么哈希不可逆转? 因为他们被devise成这样,因为有时候你想要一个单向的操作。

encryption和散列algorithm以类似的方式工作。 在每种情况下,都需要在这些位之间产生混淆和扩散 。 下来, 混淆正在造成密钥和密文之间的复杂关系,而扩散正在传播每一个位的信息。

许多散列函数实际上使用encryptionalgorithm(或encryptionalgorithm的原语),例如,SHA-3候选人Skein使用Threefish作为处理每个块的底层方法,不同之处在于不是保留每个密文块,而是破坏性地,确定性地合并到一个固定的长度

encryptionencryption的目的是转换数据,以保持它的秘密例如(发送给他人一个秘密的文本,他们只能读,通过互联网发送密码)。

而不是集中可用性的目标是确保数据发送可以分开发送,只能由您发送的用户看到。

它将数据encryption成另一种将其转换为唯一模式的格式,可以使用密钥encryption,具有密钥的用户可以通过可逆过程查看消息。 EG(AES,河豚,RSA)

encryption可能看起来像这样FhQp6U4N28GITVGjdt37hZN

散列在技​​术上,我们可以说这是一个随意的input,并产生一个固定长度的string。

其中最重要的是你不能从输出到input,它促使了给定的信息没有被修改的强大的输出。 这个过程是接收一个input并且散列它,然后一旦发送者的私钥被发送者的私钥发送,他们就可以用发送者的公钥来validation它。

如果散列错误,并且不匹配哈希,我们就看不到任何信息。 如(MD5,SHA …..)