我看到散列和加密算法之间有很多混淆,我想听听一些有关以下方面的专家建议:
何时使用散列与加密
是什么使哈希算法或加密算法与理论/数学水平不同(即,使哈希值不可逆(无需借助彩虹树))
这里有一些类似的 SO问题,没有像我想要的那样详细:
我看到散列和加密算法之间有很多混淆,我想听听一些有关以下方面的专家建议:
何时使用散列与加密
是什么使哈希算法或加密算法与理论/数学水平不同(即,使哈希值不可逆(无需借助彩虹树))
这里有一些类似的 SO问题,没有像我想要的那样详细:
Answers:
好吧,您可以在Wikipedia中查找它。但是,由于您需要一个解释,因此我将尽力而为:
它们提供了任意长度的输入和(通常)固定长度(或更短的长度)输出之间的映射。从简单的crc32到完整的加密哈希函数(例如MD5或SHA1 / 2/256/512),它可以是任何东西。关键是正在进行单向映射。由于每个函数产生的输出都比其输入的输出要小(如果将每个可能的1mb文件都馈入MD5中,则会产生大量的冲突),因此总是有很多:1映射(这意味着总是会有冲突)。
它们很难(或实际上不可能)逆转的原因是由于它们在内部如何工作。大多数密码哈希函数会多次遍历输入集以产生输出。因此,如果我们查看每个固定长度的输入块(取决于算法),则哈希函数将调用该状态。然后,它将遍历状态并将其更改为新状态,并将其用作对自身的反馈(MD5对每个512位数据块执行64次此操作)。然后,它将以某种方式将所有这些迭代的结果状态组合在一起,以形成结果哈希。
现在,如果您想对哈希进行解码,则首先需要弄清楚如何将给定的哈希拆分为迭代状态(对于小于数据块大小的输入,存在一种可能性,对于较大的输入,存在许多可能性)。然后,您需要为每个状态反转迭代。现在,为了解释为什么这是很辛苦的,试想一下推断a
并b
从以下公式: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。现在,有多个input:key对可能会生成相同的输出(实际上通常取决于加密功能)。好的加密数据与随机噪声是无法区分的。这与始终具有一致格式的良好哈希输出不同。
当您想比较一个值但不能存储普通表示形式时(由于多种原因),请使用哈希函数。密码应该非常适合此用例,因为出于安全原因(并且不应),您不想以纯文本形式存储密码。但是,如果您要检查文件系统中是否存在盗版音乐文件,该怎么办?每个音乐文件存储3 mb是不切实际的。因此,取而代之的是,获取文件的哈希值并存储该哈希值(md5将存储16个字节而不是3mb)。这样,您只需对每个文件进行哈希处理,然后将其与存储的哈希数据库进行比较(在实践中,由于重新编码,更改文件头等原因,效果不佳,但这是一个示例用例)。
检查输入数据的有效性时,请使用哈希函数。这就是他们的目的。如果您有2个输入,并且想要检查它们是否相同,则通过哈希函数运行这两个输入。对于较小的输入大小(假设哈希函数良好),发生碰撞的可能性在天文上较低。这就是为什么建议使用密码的原因。对于不超过32个字符的密码,md5的输出空间为4倍。SHA1具有大约六倍的输出空间。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);
}
还有其他更标准的实现,例如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!
}
其原因与碰撞有关。请记住,所有哈希函数都有冲突,因为可能的输出空间(可能的输出数量)小于输入空间。要了解原因,让我们看看会发生什么。首先,让我们假设发生碰撞的可能性为0.001%sha1()
(实际发生的可能性要低得多,但仅出于演示目的)。
hash1 = sha1(password + salt);
现在,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);
}
与本机sha512
函数具有相同的碰撞机会。你想要哪一个。改用它。
哈希函数可以视为与烤面包相同。首先从输入(面粉,水,酵母等)开始,然后应用哈希函数(混合+烘焙),最后得到一个输出:一条面包。
换种方式非常困难-您无法真正将面包分成面粉,水和酵母-其中一些是在烘焙过程中损失的,而且您永远无法确切地分辨出多少水,面粉或酵母用于一个特定的面包,因为该信息被哈希函数(又称烤箱)破坏了。
理论上,许多不同的输入变量将产生相同的面包(例如2杯水和1 tsbp的酵母与2.1杯水和0.9 tsbp的酵母产生的面包完全相同),但是鉴于其中一条,您无法分辨正是输入的组合产生了它。
另一方面,加密可以看作是一个保险箱。只要您拥有将它锁定在第一位的钥匙,无论放在那里的东西都会回来。这是一个对称操作。给定一个键和一些输入,您将获得一定的输出。给定该输出和相同的键,您将取回原始输入。这是1:1映射。
当您不想获取原始输入时,请使用哈希,在您这样做时,请使用加密。
散列接受一些输入并将其转换为一些位(通常认为是数字,例如32位整数,64位整数等)。相同的输入将始终产生相同的哈希,但是您在此过程中会原则上丢失信息,因此您无法可靠地重现原始输入(但是有一些警告)。
加密原则上会保留您输入到加密功能中的所有信息,只会使任何人都很难(理想情况下)在不拥有特定密钥的情况下退回到原始输入。
散列的简单示例
这是一个简单的示例,可以帮助您理解为什么哈希(通常情况下)无法取回原始输入。假设我正在创建一个1位哈希。我的哈希函数将一个位字符串作为输入,如果在输入字符串中设置了偶数个位,则将哈希设置为1;如果有一个奇数,则将哈希设置为0。
例:
Input Hash
0010 0
0011 1
0110 1
1000 0
请注意,有许多输入值会导致散列为0,而许多输入值会导致散列为1。如果您知道散列为0,则无法确定原始输入是什么。
顺便说一下,这个1位散列并不是完全伪造的……看看奇偶校验位。
加密的简单示例
您可以使用简单的字母替换来加密文本,例如,如果输入为A,则输入B。如果输入为B,则输入C。一直到字母末尾,如果输入为Z,则表示再次写A。
Input Encrypted
CAT DBU
ZOO APP
哈希和加密/解密技术的基本概述。
散列:
如果再次对任何纯文本进行哈希处理,则无法从哈希文本中获得相同的纯文本。简单来说,这是一个单向过程。
加密和解密:
如果再次用密钥加密任何纯文本,则可以通过使用相同(对称)/不同(非对称)密钥对加密文本进行解密来获得相同的纯文本。
更新: 解决已编辑问题中提到的要点。
1.何时使用散列与加密
如果要向某人发送文件,则散列很有用。但是您担心其他人可能会截取该文件并进行更改。因此,如果您公开发布哈希值,则收件人可以确保它是正确文件的一种方式。这样,接收者可以计算接收到的文件的哈希值,并检查它是否与哈希值匹配。
如果您说有消息要发送给某人,则加密是很好的。您使用密钥对邮件进行加密,而收件人使用相同(或什至可能是不同)的密钥解密以获取原始邮件。 学分
2.什么使哈希或加密算法与理论/数学水平不同(即,使哈希不可逆(无需彩虹树))?
基本上,哈希是一种丢失信息但不会丢失加密的操作。为了便于理解,让我们以简单的数学方式看一下它们的区别,当然两者都具有更复杂的数学运算,并且其中涉及重复
加密/解密(可逆):
加法:
4 + 3 = 7
可以通过求和并减去加数之一来逆转
7 - 3 = 4
乘法:
4 * 5 = 20
通过取乘积并除以以下因素之一可以逆转这种情况
20 / 4 = 5
因此,在这里我们可以假设加数/因数之一是解密密钥,而result(7,20)是一个加密的文本。
散列(不可逆):
模数部门:
22 % 7 = 1
这不能撤消,因为您无法对商和被除数进行任何运算来重构除数(反之亦然)。
您可以找到一个运算符来填充“'”的位置吗?是吗
1 ? 7 = 22 1 ? 22 = 7
因此,哈希函数具有与模除相同的数学质量,并且会丢失信息。
我的一个班轮...一般来说,面试官想要下面的答案。
散列是一种方法。您无法从哈希码转换数据/字符串。
加密有两种方式-如果您拥有密钥,则可以再次解密加密的字符串。
甲Hash函数变成文本的可变大小的量成固定大小的文本。
资料来源:https : //en.wikipedia.org/wiki/Hash_function
PHP中的哈希函数
哈希将字符串转换为哈希字符串。见下文。
哈希:
$str = 'My age is 29';
$hash = hash('sha1', $str);
echo $hash; // OUTPUT: 4d675d9fbefc74a38c89e005f9d776c75d92623e
密码通常以其哈希表示形式而不是可读文本形式存储。如果最终用户希望访问受密码保护的应用程序,则必须在身份验证期间输入密码。当用户提交密码时,有效的身份验证系统将接收密码并对该给定密码进行哈希处理。将此密码哈希与系统已知的哈希进行比较。在平等的情况下授予访问权限。
散列:
SHA1是单向哈希。这意味着您不能对哈希进行散列。
但是,您可以对哈希进行暴力破解。请参阅:https : //hashkiller.co.uk/sha1-decrypter.aspx。
MD5,是另一个哈希。可以在以下网站上找到MD5清除器:https://www.md5online.org/ 。
为了阻止对哈希的暴力攻击,可以添加盐。在php中,您可以password_hash()
用来创建密码哈希。该功能password_hash()
自动创建盐。要验证密码哈希(含盐)上的密码,请使用password_verify()
。
// 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
一个密码可以由一个以上的哈希表示。当您通过使用验证具有不同密码散列password_verify()
的密码时,该密码将被接受为有效密码。
$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
的加密功能 通过使用加密密钥,反之亦然变换文本成无意义的密文。
资料来源:https : //zh.wikipedia.org/wiki/加密
PHP中的加密
让我们深入研究一些处理加密的PHP代码。
-Mcrypt扩展-
加密:
$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)
-OpenSSL扩展-
Mcrypt扩展在7.1中已弃用。并在php 7.2中删除。OpenSSL扩展应该在php 7中使用。请参见下面的代码段:
$key = 'A_KEY';
$data = 'My age is 29';
// ENCRYPT
$encryptedData = openssl_encrypt($data , 'AES-128-CBC', $key, 0, 'IV_init_vector01');
var_dump($encryptedData);
// DECRYPT
$decryptedData = openssl_decrypt($encryptedData, 'AES-128-CBC', $key, 0, 'IV_init_vector01');
var_dump($decryptedData);
//OUTPUT
string '4RJ8+18YkEd7Xk+tAMLz5Q==' (length=24)
string 'My age is 29' (length=12)
A_KEY
是不是一个AES / Rijndael算法-128密钥; 这是密码,而不是盟友。
对称加密:
对称加密也可以称为共享密钥或共享秘密加密。在对称加密中,单个密钥用于加密和解密流量。
非对称加密:
非对称加密也称为公钥加密。非对称加密与对称加密的主要区别在于,使用了两个密钥:一个用于加密,一个用于解密。最常见的非对称加密算法是RSA
。
与对称加密相比,非对称加密会带来较高的计算负担,并且往往要慢得多。因此,它通常不用于保护有效载荷数据。相反,它的主要优势在于它能够在非安全介质(例如Internet)上建立安全通道。这通过交换只能用于加密数据的公共密钥来完成。从未共享的互补私钥用于解密。
散列:
最后,散列是一种不同于加密的加密安全性。加密是用于首先加密然后解密消息的两步过程,而散列将消息压缩为不可逆的固定长度值或散列。在网络中最常见的两种哈希算法是MD5
和SHA-1
。
在此处阅读更多信息:http : //packetlife.net/blog/2010/nov/23/symmetric-asymmetric-encryption-hashing/
当您只需要一种方式时,请使用哈希。例如,对于系统中的密码,您使用哈希,因为您将仅验证哈希后用户输入的值是否与存储库中的值匹配。使用加密,您可以采用两种方法。
哈希算法和加密算法只是数学算法。因此,在这方面,它们没有什么不同-只是数学公式。但是,在语义方面明智的做法是,在哈希(单向)和加密(双向)之间存在很大的区别。为什么哈希是不可逆的?因为它们是按这种方式设计的,因为有时您需要单向操作。
在传输数据的安全性方面,即双向通信,您使用加密。所有加密都需要一个密钥
当涉及授权时,您使用哈希。哈希中没有密钥
散列接受任何数量的数据(二进制或文本),并创建表示数据校验和的定长散列。例如,哈希可能是16个字节。不同的哈希算法产生不同的大小哈希。您显然无法从哈希表重新创建原始数据,但是可以再次对数据进行哈希表以查看是否生成了相同的哈希值。基于Unix的单向密码以这种方式工作。密码将存储为哈希值,并登录到系统时,将对您输入的密码进行哈希处理,然后将哈希值与实际密码的哈希值进行比较。如果它们匹配,那么您必须输入正确的密码
为什么哈希不可逆:
散列不可逆,因为输入到散列的映射不是一对一的。 将两个输入映射到相同的哈希值通常称为“哈希冲突”。为了安全起见,“良好”哈希函数的特性之一是在实际使用中很少发生冲突。
密码学处理数字和字符串。基本上,整个宇宙中的每个数字事物都是数字。当我说数字时,它的0和1。你知道它们是什么,二进制。您在屏幕上看到的图像,通过耳机收听的音乐以及所有内容都是二进制文件。但是我们的耳朵和眼睛不会理解二进制文件吗?只有大脑才能理解这一点,即使它能理解二进制文件,也无法享受二进制文件。因此,我们将二进制文件转换为人类可以理解的格式,例如mp3,jpg等。我们将该过程称为Encoding。这是两种方式,可以很容易地解码回其原始形式。
散列
散列是另一种加密技术,其中数据一旦转换为其他形式就永远无法恢复。用Layman的术语来说,没有所谓的散列处理。有许多哈希函数可以完成这项工作,例如sha-512,md5等。
如果无法恢复原始值,那么我们将在哪里使用它呢?密码!为手机或PC设置密码时,会创建密码的哈希并将其存储在安全的地方。下次尝试登录时,将使用相同的算法(哈希函数)再次对输入的字符串进行哈希处理,并将输出与存储的值进行匹配。如果相同,则登录。否则,您将被丢弃。
信用:Wikimedia通过对密码应用哈希,我们可以确保即使攻击者窃取了存储的密码文件,也永远不会获得我们的密码。攻击者将拥有密码的哈希值。他可能会找到最常用的密码列表,并将sha-512应用于每个密码,并将其与手中的值进行比较。这被称为字典攻击。但是他要这样做多久?如果您的密码足够随机,那么您认为这种破解方法可行吗?Facebook,Google和Amazon数据库中的所有密码都会被哈希,或者至少应该被哈希。
然后是加密
加密介于散列和编码之间。编码是一种双向过程,不应用于提供安全性。加密也是一种双向过程,但是只有在知道加密密钥的情况下,才可以检索原始数据。如果您不知道加密的工作原理,请放心,我们将在这里讨论基础知识。这足以了解SSL的基础知识。因此,有两种加密类型,即对称加密和非对称加密。
对称密钥加密
我试图使事情尽可能简单。因此,让我们通过移位算法来了解对称加密。该算法用于通过将字母向左或向右移动来加密字母。让我们以字符串CRYPTO来考虑数字+3。然后,CRYPTO的加密格式将为FUBSWR。这意味着每个字母向右移3个位置。在这里,单词CRYPTO被称为纯文本,输出FUBSWR被称为密文,值+3被称为加密 密钥(对称密钥),整个过程是一个密码。这是最古老且基本的对称密钥加密算法之一,在朱利叶斯·凯撒(Julius Caesar)时代曾首次报道其用法。因此,它以他的名字命名,并且是著名的凯撒密码。任何知道加密密钥并可以应用凯撒算法相反方法并检索原始纯文本的人。因此,它称为对称加密。
非对称密钥加密
我们知道,在对称加密中,相同的密钥用于加密和解密。一旦密钥被盗,所有数据都将消失。那是巨大的风险,我们需要更复杂的技术。1976年,Whitfield Diffie和Martin Hellman首次发表了非对称加密的概念,该算法被称为Diffie-Hellman密钥交换。然后在1978年,麻省理工学院的Ron Rivest,Adi Shamir和Leonard Adleman发表了RSA算法。这些可以被认为是非对称密码学的基础。
与对称加密相比,在非对称加密中,将有两个密钥而不是一个。一个称为公钥,另一个称为私钥。从理论上讲,在启动过程中,我们可以生成公共-私人我们机器的密钥对。私钥应保存在安全的地方,并且绝不应该与任何人共享。顾名思义,公钥可以与希望向您发送加密文本的任何人共享。现在,拥有您的公共密钥的人可以使用它来加密秘密数据。如果密钥对是使用RSA算法生成的,则它们在加密数据时应使用相同的算法。通常,算法将在公钥中指定。加密的数据只能用您拥有的私钥解密。
来源:用于假人的SSL / TLS第1部分:密码套件,哈希,加密| WST(https://www.wst.space/ssl-part1-ciphersuite-hashing-encryption/)
加密加密的目的是对数据进行转换,以使其保持机密(例如,向某人发送他们只能读取的机密文本,并通过Internet发送密码)。
而不是着眼于可用性,目标是确保可以秘密发送数据发送,并且只能由您发送的用户看到。
它将数据加密为另一种格式,将其转换为独特的模式,可以使用密钥对其进行加密,拥有密钥的用户可以通过可逆过程来查看消息。例如:AES,BLOWFISH,RSA
加密可能看起来像这样:FhQp6U4N28GITVGjdt37hZN
散列从技术上讲,我们可以说它是任意输入并产生了固定长度的字符串。
其中最重要的是您不能从输出转到输入,它会产生强大的输出,即给定的信息没有被修改。该过程是获取输入并对其进行哈希处理,然后在接收方收到接收者可以使用发送者的公钥对其进行验证后,使用发送者的私钥进行发送。
如果哈希错误并且与哈希不匹配,我们将看不到任何信息。例如(MD5,SHA .....)