散列和加密算法之间的根本区别

Ken*_*son 494 security encryption hash cryptography

我看到哈希和加密算法之间存在很多混淆,我希望听到一些更专业的建议:

  1. 何时使用哈希与加密

  2. 什么使哈希或加密算法不同(从理论/数学水平),即什么使哈希不可逆(没有彩虹树的帮助)

以下是一些类似的 SO问题,没有像我想要的那样详细说明:

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

irc*_*ell 719

嗯,你可以在维基百科中查找......但既然你想要一个解释,我会尽力在这里:

散列函数

它们提供任意长度输入和(通常)固定长度(或较小长度)输出之间的映射.它可以是从简单的crc32到完整的加密散列函数,如MD5或SHA1/2/256/512.重点是正在进行单向映射.它总是很多:1映射(意味着总会有碰撞),因为每个函数产生的输出都比输入能力小(如果你将每个可能的1mb文件输入到MD5中,你会得到大量的碰撞).

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

现在,如果你想解码哈希,你首先需要弄清楚如何将给定的哈希分割成它的迭代状态(输入小于一大块数据的输入的可能性是1,对于更大的输入来说很多).然后你需要反转每个状态的迭代.现在,为了解释为什么这是很辛苦的,试想一下推断ab从以下公式:10 = a + b.有10个积极的组合a,并b能正常工作.现在循环一遍:tmp = a + b; a = b; b = tmp.对于64次迭代,您可以尝试超过10 ^ 64种可能性.这只是一个简单的添加,其中一些状态从迭代到迭代保留.实际哈希函数执行的操作多于1次(MD5对4个状态变量执行大约15次操作).并且由于下一次迭代取决于前一次的状态而前者在创建当前状态时被破坏,因此几乎不可能确定导致给定输出状态的输入状态(对于每次迭代不少).再加上所涉及的大量可能性,甚至MD5的解码将需要几乎无限(但不是无限)的资源量.如果你知道输入的大小(对于较小的输入)而不是甚至尝试解码哈希,那么实际上要大大降低哈希的资源实际上便宜得多.

加密功能

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

用例

如果要比较值但不能存储普通表示(出于多种原因),请使用哈希函数.密码应该非常适合这种用例,因为出于安全原因(不应该),您不希望将它们存储为纯文本.但是如果你想检查文件系统中的盗版音乐文件怎么办?每个音乐文件存储3 MB是不切实际的.所以相反,取出文件的哈希值并存储(md5将存储16个字节而不是3mb).这样,您只需散列每个文件并与存储的哈希数据库进行比较(由于重新编码,更改文件头等等,这在实践中不起作用,但这是一个示例用例).

在检查输入数据的有效性时使用哈希函数.这就是他们的设计目标.如果您有2条输入,并想要检查它们是否相同,则通过哈希函数运行.对于小输入大小,碰撞的概率是天文数字低(假设具有良好的散列函数).这就是为什么建议使用密码.对于最多32个字符的密码,md5的输出空间是4倍.SHA1的输出空间是大约6倍(大约).SHA512的输出空间约为16倍.你真的不在乎密码什么,你关心它是否与存储的密码相同.这就是为什么你应该使用哈希密码.

无论何时需要取回输入数据,都要使用加密.注意这个词需要.如果您要存储信用卡号,则需要在某些时候将其退回,但不要将它们存储为纯文本.因此,存储加密版本并尽可能保持密钥安全.

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

关于密码哈希的说明:

加密哈希函数的一个关键特性是它们应该非常快速地创建,并且非常难以/慢地反转(以至于它实际上是不可能的).这会造成密码问题.如果你存储sha512(password),你没有做任何事情来防范彩虹表或暴力攻击.请记住,哈希函数是为速度而设计的.因此,攻击者只需通过哈希函数运行字典并测试每个结果,这是微不足道的.

添加盐有助于解决问题,因为它会向哈希添加一些未知数据.因此md5(foo),他们不需要找到匹配的东西,而是需要找到添加到已知盐产生的东西md5(foo.salt)(这是非常难做的).但它仍然无法解决速度问题,因为如果他们知道盐只是运行字典的问题.

所以,有办法解决这个问题.一种流行的方法称为键加强(或键拉伸).基本上,你多次遍历哈希(通常是数千).这样做有两件事.首先,它显着减慢了散列算法的运行时间.其次,如果正确实现(在每次迭代时将输入和盐传回),实际上会增加输出的熵(可用空间),从而减少冲突的可能性.一个简单的实现是:

var hash = password + salt;
for (var i = 0; i < 5000; i++) {
    hash = sha512(hash + password + salt);
}
Run Code Online (Sandbox Code Playgroud)

还有其他更标准的实现,如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!
}
Run Code Online (Sandbox Code Playgroud)

其原因与碰撞有关.请记住,所有散列函数都有冲突,因为可能的输出空间(可能的输出数量)小于输入空间.为了了解原因,让我们来看看会发生什么.在前言中,让我们假设碰撞的可能性为0.001%sha1()(实际情况得多,但出于演示目的).

hash1 = sha1(password + salt);
Run Code Online (Sandbox Code Playgroud)

现在,hash1碰撞概率为0.001%.但是当我们做下一个时hash2 = sha1(hash1);,所有的碰撞都会hash1自动变成碰撞hash2.所以现在,我们将hash1的速率设置为0.001%,第二次sha1()调用增加了它.所以现在,hash2碰撞概率为0.002%.这是机会的两倍!每次迭代都会0.001%为结果增加另一次碰撞机会.因此,在1000次迭代中,碰撞的几率从0.001%上升到1%.现在,退化是线性的,并且实际概率小得多,但效果是相同的(单次碰撞机会的估计md5约为1 /(2 128)或1 /(3x10 38).看起来很小,多亏了生日攻击它并不像看起来那么小.)

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

hash = sha512(password + salt);
for (i = 0; i < 1000; i++) {
    hash = sha512(hash + password + salt);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 糟糕的是LinkedIn的程序员在将密码存储为未加盐的SHA1哈希之前没有读过这个... http://money.cnn.com/2012/06/06/technology/linkedin-password-hack/index.htm (28认同)
  • 很好的答案.我唯一的挑剔是,平凡拉伸的退化不能是线性的,否则最终会超过100%.我认为在你的例子中,.001%的第二步应该是.001 +(1 - 0.001)*.001,或0.001999. (7认同)
  • @Pacerier:它也强调了哈希.它详细介绍了密码散列... (2认同)

Mar*_*c B 157

哈希函数可以被认为与烘焙一条面包相同.你从输入(面粉,水,酵母等......)开始,在应用哈希函数(混合+烘焙)之后,你得到一个输出:一条面包.

走另一条路是非常困难的 - 你无法真正将面包分成面粉,水,酵母 - 其中一些在烘焙过程中丢失了,你永远无法确切知道用​​了多少水或面粉或酵母一个特别的面包,因为该信息被散列函数(也就是烤箱)破坏了.

理论上,许多不同的输入变体会产生相同的面包(例如2杯水和1汤匙酵母产生的面包与2.1杯水和0.9平方公尺的酵母完全相同),但鉴于其中一个面包,你无法分辨究竟是什么组合的投入产生了它.

另一方面,加密可以被视为一个保险箱.无论你放在哪里,只要你拥有它首先被锁定的钥匙就会回来.这是一个对称的操作.给定一个键和一些输入,您将获得一定的输出.给定输出和相同的键,您将获得原始输入.这是一个1:1的映射.

  • 除了你不能轻易地表明一个特定的汉堡完全来自一个特定的牛,这是一个哈希的基本属性,所以这是一个有趣的想法,但一个可怕的类比. (2认同)

Eri*_* J. 43

当您不希望能够取回原始输入时使用哈希,请在执行时使用加密.

哈希需要一些输入并将其转换为一些位(通常被认为是一个数字,如32位整数,64位整数等).相同的输入将始终产生相同的散列,但您在过程中主要丢失信息,因此您无法可靠地重现原始输入(但有一些警告).

加密主要保留您加入到加密函数中的所有信息,这使得任何人在没有特定密钥的情况下反向回原始输入变得困难(理想情况下是不可能的).

哈希的简单例子

这是一个简单的例子,可以帮助您理解为什么哈希不能(在一般情况下)获取原始输入.假设我正在创建一个1位哈希.我的散列函数将一个字符串作为输入,如果输入字符串中设置了偶数位,则将散列设置为1,否则如果存在奇数则为0.

例:

Input    Hash
0010     0
0011     1
0110     1
1000     0
Run Code Online (Sandbox Code Playgroud)

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

顺便说一句,这个1位散列并不是完全人为的......看看奇偶校验位.

简单的加密示例

您可以使用简单的字母替换来加密文本,例如,如果输入为A,则编写B.如果输入为B,则编写C.一直到字母表的末尾,如果输入为Z,则再写一次.

Input   Encrypted
CAT     DBU
ZOO     APP
Run Code Online (Sandbox Code Playgroud)

就像简单的哈希示例一样,历史一直使用这种类型的加密.


mrs*_*vas 38

散列和加密/解密技术的基本概述是.

哈希:

如果再次散列任何纯文本,则无法从散列文本中获取相同的纯文本.简单来说,这是一个单向的过程.

散列


加密和解密:

如果再次使用密钥加密任何纯文本,则可以通过使用相同(symetric)/ diffrent(asymentric)密钥对加密文本进行解密来获得相同的纯文本.

加密和解密


更新: 解决编辑问题中提到的要点.

1.何时使用哈希与加密

如果要向某人发送文件,散列非常有用.但是你担心其他人可能会截取该文件并进行更改.因此,如果您公开发布哈希值,收件人可以确保它是正确的文件的方式.这样,收件人可以计算收到的文件的哈希值,并检查它是否与哈希值匹配.

如果您说要发送给某人的消息,加密就很好.您使用密钥对邮件进行加密,并且收件人使用相同(或者甚至可能是不同的)密钥进行解密以获取原始邮件. 学分


2.什么使哈希或加密算法不同(从理论/数学水平),即什么使哈希不可逆(没有彩虹树的帮助)

基本上,散列是一种丢失信息但不加密的操作.让我们以简单的数学方式看待差异,以便我们轻松理解,当然两者都有更复杂的数学运算,其中涉及重复

加密/解密(可逆):

增加:

4 + 3 = 7  
Run Code Online (Sandbox Code Playgroud)

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

7 - 3 = 4     
Run Code Online (Sandbox Code Playgroud)

乘法:

4 * 5 = 20  
Run Code Online (Sandbox Code Playgroud)

这可以通过取出产品并除以其中一个因素来逆转

20 / 4 = 5    
Run Code Online (Sandbox Code Playgroud)

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


哈希(不可逆):

模数师:

22 % 7 = 1   
Run Code Online (Sandbox Code Playgroud)

这是无法逆转的,因为你没有可以对商进行操作而红利可以重构除数(反之亦然).

你能找到一个填写"?"的操作吗?是什么?

1  ?  7 = 22  
1  ?  22 = 7
Run Code Online (Sandbox Code Playgroud)

因此散列函数具有与模除法相同的数学质量并且丢失信息.

学分


Shi*_*han 26

我的一个班轮...一般面试官想要下面的答案.

哈希是一种方式.您无法从哈希代码转换数据/字符串.

加密是双向的 - 如果你有密钥,你可以再次解密加密的字符串.


Jul*_*ian 16

Hash函数变成文本的可变大小的量成固定大小的文本.

哈希

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

让我们看看它在行动.我用它来做它.

HASH:

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

DEHASH:

SHA1是单向散列.这意味着你无法取消散列哈希.但是,您可以强制执行哈希.请参阅:https://hashkiller.co.uk/sha1-decrypter.aspx.

MD5,是另一个哈希.可在此网站上找到MD5 dehasher:https://www.md5online.org/ .


加密功能 通过使用加密密钥,反之亦然变换文本成无意义的密文. 在此输入图像描述

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

让我们深入研究一些处理加密的PHP代码.

--- Mcrypt延伸---

加密:

// Invoke this little script 3 times, and it will give you everytime a new hash
$password = '1234';  
$hash = password_hash($password, PASSWORD_DEFAULT);  

echo $hash; 
// OUTPUT 

$2y$10$ADxKiJW/Jn2DZNwpigWZ1ePwQ4il7V0ZB4iPeKj11n.iaDtLrC8bu 

$2y$10$H8jRnHDOMsHFMEZdT4Mk4uI4DCW7/YRKjfdcmV3MiA/WdzEvou71u 

$2y$10$qhyfIT25jpR63vCGvRbEoewACQZXQJ5glttlb01DmR4ota4L25jaW
Run Code Online (Sandbox Code Playgroud)

解密:

$password = '1234';  

$hash = '$2y$10$ADxKiJW/Jn2DZNwpigWZ1ePwQ4il7V0ZB4iPeKj11n.iaDtLrC8bu';  
var_dump( password_verify($password, $hash) );  

$hash = '$2y$10$H8jRnHDOMsHFMEZdT4Mk4uI4DCW7/YRKjfdcmV3MiA/WdzEvou71u';  
var_dump( password_verify($password, $hash) );  

$hash = '$2y$10$qhyfIT25jpR63vCGvRbEoewACQZXQJ5glttlb01DmR4ota4L25jaW';  
var_dump( password_verify($password, $hash) );

// OUTPUT 

boolean true 

boolean true 

boolean true
Run Code Online (Sandbox Code Playgroud)

--- OpenSSL扩展---

Mcrypt扩展在7.1中被弃用.并在PHP 7.2中删除.应该在php 7中使用OpenSSL扩展.请参阅下面的代码片段:

$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)
Run Code Online (Sandbox Code Playgroud)


Vah*_*ian 10

对称加密:

对称加密也可以称为共享密钥或共享秘密加密.在对称加密中,单个密钥用于加密和解密流量.

在此输入图像描述

非对称加密:

非对称加密也称为公钥加密.非对称加密与对称加密的不同之处主要在于使用了两个密钥:一个用于加密,一个用于解密.最常见的非对称加密算法是RSA.

与对称加密相比,非对称加密带来了高计算负担,并且往往要慢得多.因此,通常不用于保护有效载荷数据.相反,它的主要优势在于能够在非安全媒体(例如,互联网)上建立安全通道.这是通过交换公钥来实现的,公钥只能用于加密数据.从不共享的互补私钥用于解密.

在此输入图像描述

哈希:

最后,散列是一种加密安全形式,它与加密不同.加密是用于首先加密然后解密消息的两步过程,而散列将消息压缩为不可逆的固定长度值或散列.在网络中看到的两种最常见的哈希算法是MD5SHA-1.

在此输入图像描述

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

  • @Abdul非对称加密具有很高的计算负担,因此不能用于保护通过网络以数据包(有效负载)形式发送的数据。相反,它用于通过交换公共密钥来保护数据来建立安全的网络连接。 (2认同)

hvg*_*des 6

  1. 当您只需要走一种方式时,请使用哈希。例如,对于系统中的密码,您使用散列,因为您只会在散列后验证用户输入的值是否与存储库中的值匹配。通过加密,您可以采用两种方式。

  2. 散列算法和加密算法只是数学算法。所以在这方面它们并没有什么不同——它只是数学公式。但是,在语义方面,散列(单向)和加密(双向)之间存在很大区别。为什么哈希是不可逆的?因为它们被设计成那样,因为有时你想要一种单向操作。


ayu*_*ush 5

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

当涉及到授权时,您使用散列。散列中没有密钥

散列获取任意数量的数据(二进制或文本)并创建一个表示数据校验和的恒定长度散列。例如,散列可能是 16 个字节。不同的散列算法产生不同大小的散列。您显然无法从散列重新创建原始数据,但您可以再次散列数据以查看是否生成了相同的散列值。单向基于 Unix 的密码就是这样工作的。密码以散列值的形式存储,为了登录系统,您输入的密码会经过散列处理,并将散列值与真实密码的散列值进行比较。如果它们匹配,那么您必须输入正确的密码

为什么散列不可逆:

散列是不可逆的,因为输入到散列的映射不是 1 对 1 的。 将两个输入映射到相同的哈希值通常称为“哈希冲突”。出于安全目的,“好”散列函数的特性之一是在实际使用中很少发生冲突。


Jus*_*gan 5

加密和散列算法的工作方式类似。在每种情况下,都需要在位之间造成混淆和扩散。归根结底,混淆是在密钥和密文之间创建复杂的关系,而扩散是在散布每一位的信息。

许多散列函数实际使用的加密算法(或加密算法的基元。例如,SHA-3候选绞纱使用Threefish以处理每个块中的底层的方法,所不同的是,与其保持的密文的各个块中,它们是破坏性地,确定性地合并到一个固定的长度