我看到哈希和加密算法之间存在很多混淆,我希望听到一些更专业的建议:
-
何时使用哈希与加密
-
什么使哈希或加密算法不同(从理论/数学水平),即什么使哈希不可逆(没有彩虹树的帮助)
以下是一些类似的SO问题,没有像我想要的那样详细说明:
What is the difference between Obfuscation, Hashing, and Encryption?
Difference between encryption and hashing
我看到哈希和加密算法之间存在很多混淆,我希望听到一些更专业的建议:
何时使用哈希与加密
什么使哈希或加密算法不同(从理论/数学水平),即什么使哈希不可逆(没有彩虹树的帮助)
以下是一些类似的SO问题,没有像我想要的那样详细说明:
What is the difference between Obfuscation, Hashing, and Encryption?
Difference between encryption and hashing
12 回答
加密和哈希算法以类似的方式工作 . 在每种情况下,都需要在这些位中创建confusion and diffusion . 归结起来,混淆是在密钥和密文之间创建一个复杂的关系,并且扩散正在传播每个位的信息 .
许多哈希函数实际上使用加密算法(或加密算法的原语 . 例如,SHA-3候选Skein使用Threefish作为处理每个块的基础方法 . 区别在于它们不是保留每个密文块,而是破坏性的,确定性地合并到一个固定的长度
好吧,你可以在Wikipedia查找...但是既然你想要一个解释,我会尽力在这里:
哈希函数
它们提供任意长度输入和(通常)固定长度(或较小长度)输出之间的映射 . 它可以是从简单的crc32到完整的加密散列函数,如MD5或SHA1 / 2/256/512 . 重点是正在进行单向映射 . 它总是很多:1映射(意味着总会有碰撞),因为每个函数产生的输出都比输入能力小(如果你将每个可能的1mb文件输入到MD5中,你会得到大量的碰撞) .
他们很难(或实际上不可能)扭转的原因是因为他们在内部的工作方式 . 大多数加密散列函数多次迭代输入集以产生输出 . 因此,如果我们查看每个固定长度的输入块(这取决于算法),哈希函数将调用当前状态 . 然后它将遍历状态并将其更改为新状态并将其用作自身的反馈(MD5为每个512位数据块执行64次此操作) . 然后它以某种方式将来自所有这些迭代的结果状态组合在一起以形成结果散列 .
现在,如果你想解码哈希,你需要为每个状态反转迭代 . 现在,为了解释为什么这很难,想象一下从下面的公式中推断
a
和b
:10 = a + b
.a
和b
有10种正面组合可以使用 . 现在循环多次:tmp = a + b; a = b; b = tmp
. 对于64次迭代,你只是一个简单的加法,其中一些状态从迭代到迭代保留 . 实际散列函数执行的操作多于1次(MD5对4个状态变量执行大约15次操作) . 并且由于下一次迭代取决于前一次的状态,而前一次迭代在创建当前状态时被破坏,如果您对输入的大小有所了解,那么它实际上要大大降低哈希强制哈希值(对于较小的输入)而不是甚至尝试解码哈希 .加密功能
它们在任意长度的输入和输出之间提供1:1映射 . 而且他们总是可逆的 . 需要注意的重要一点是,使用某种方法是可逆的 . 对于给定的密钥,它总是1:1 . 现在,有多个输入:密钥对可能会生成相同的输出(实际上通常有,具体取决于加密函数) . 良好的加密数据与随机噪声无法区分 . 这与良好的散列输出不同,散列输出始终是一致的格式 .
用例
如果要比较值但不能存储普通表示(出于多种原因),请使用哈希函数 . 密码应该非常适合这种用例,因为出于安全原因(不应该),您不希望将它们存储为纯文本 . 但是如果你想检查一个文件系统是否有盗版音乐文件怎么办?每个音乐文件存储3 MB是不切实际的 . 所以相反,取出文件的哈希值并存储(md5将存储16个字节而不是3mb) . 这样,你只需散列每个文件并与存储的哈希数据库进行比较(由于重新编码,更改文件头等等,这在实践中不起作用,但这是一个用例示例) .
当你设计它们时,使用哈希函数 . 如果您有2个输入,并想要检查它们是否相同,则通过哈希函数运行 . 对于小输入大小,碰撞的概率是天文数字低(假设具有良好的散列函数) . 那个's why it'建议用于密码 . 对于最多32个字符的密码,md5的输出空间是4倍 . SHA1的输出空间是大约6倍(大约) . SHA512的输出空间约为16倍 . 你真的不在乎密码是什么,你关心它是否应该使用哈希密码 .
无论何时需要取回输入数据,都要使用加密 . 注意单词 need . 如果你想要将它们存储为纯文本 . 因此,存储加密版本并尽可能保持密钥安全 .
散列函数也非常适合签名数据 . 例如,如果您正在使用HMAC,则通过获取与已知但未传输的值(秘密值)连接的数据的哈希值来签署一条数据 . 因此,您发送纯文本和HMAC哈希 . 然后,接收器简单使用已知值散列提交的数据,并检查它是否与传输的HMAC匹配 . 如果它是相同的,你知道它没有被没有秘密值的一方篡改 . 这通常用于HTTP框架的安全cookie系统,以及HTTP上数据的消息传输,您希望在数据中保证完整性 .
关于密码哈希的注释:
加密哈希函数的一个关键特性是它们应该非常快速地创建,并且很难/慢速地反转(以至于它实际上是不可能的) . 这会造成密码问题 . 如果存储
sha512(password)
,则攻击者只需通过哈希函数运行字典并测试每个结果即可 .添加盐有助于解决问题,因为它会向哈希添加一些未知数据 . 因此,他们不需要找到与
md5(foo)
相匹配的任何东西,而是需要找到一些东西,当添加到已知的盐中时会产生md5(foo.salt)
(这是非常难做的) . 但它仍然没有通过运行字典的问题 .所以,有办法解决这个问题 . 一种流行的方法叫做key strengthening(或键拉伸) . 基本上,您多次遍历哈希(通常是数千个) . 这样做有两件事 . 首先,它显着减慢了散列算法的运行时间 . 其次,如果正确实现(在每次迭代时将输入和盐传回),实际上会增加输出的熵(可用空间),从而减少冲突的可能性 . 一个简单的实现是:
还有其他更标准的实现,例如PBKDF2,BCrypt . 但是这种技术被很多安全相关系统(例如PGP,WPA,Apache和OpenSSL)使用 .
底线
hash(password)
还不够好 .hash(password + salt)
更好,但仍然不够好...使用拉伸哈希机制生成密码哈希值...关于琐碎拉伸的另一个注释
Do not under any circumstances feed the output of one hash directly back into the hash function :
其原因与碰撞有关 . 请记住,所有散列函数都有冲突,因为可能的输出空间(可能的输出数量)小于输入空间 . 为了了解原因,让's look at what happens. To preface this, let'假设
sha1()
碰撞的概率为0.001%(实际上它低于 much ,但出于演示目的) .现在,
hash1
的碰撞概率为0.001% . 但是当我们做下一个hash2 = sha1(hash1);
, all collisions of hash1 automatically become collisions of hash2 时 . 所以现在,我们将hash1的速率设置为0.001%,并且第二个sha1()
调用增加了这一点 . 所以现在,hash2
的碰撞概率为0.002% . 这是机会的两倍!每次迭代都会为结果添加另一个碰撞机会 . 因此,在1000次迭代中,碰撞的几率从0.001%上升到1% . 现在,退化是线性的,并且实际概率更小,但效果是相同的(估计与md5
发生单次碰撞的概率约为1 /(2128)或1 /(3x1038) . 很小,多亏了the birthday attack它并不像看起来那么小 . )相反,通过每次重新附加salt和密码,您将重新将数据引入哈希函数 . 因此,任何特定回合的任何碰撞都不再是下一回合的碰撞 . 所以:
与本机
sha512
函数具有相同的碰撞机会 . 这是你想要的 . 改用它 .哈希函数可以被认为与烘焙一条面包相同 . 你从输入(面粉,水,酵母等......)开始,在应用哈希函数(混合烘焙)之后,你得到一个输出:一条面包 .
走另一条路是非常困难的 - 你无法真正将面包分成面粉,水,酵母 - 其中一些在烘焙过程中丢失了,你永远无法确切知道用了多少水或面粉或酵母一个特别的面包,因为该信息被散列功能(也就是烤箱)破坏了 .
从理论上讲,许多不同的输入变体会产生相同的面包(例如2杯水和1汤匙酵母产生的面包与2.1杯水和0.9平方英尺酵母完全相同),但鉴于其中一个面包,你无法分辨究竟是什么组合的投入产生了它 .
另一方面,加密可以被视为一个保险箱 . 无论你放在哪里都会回来,只要你拥有它首先被锁定的钥匙 . 这是一个对称的操作 . 给定一个键和一些输入,您将获得一定的输出 . 给定输出和相同的键,您将获得原始输入 . 这是一个1:1的映射 .
当涉及到传输数据的安全性,即双向通信时,您使用加密 . 所有加密都需要密钥
在授权方面,你使用散列 . 散列中没有键
散列接受任意数量的数据(二进制或文本)并创建表示数据校验和的常量长度散列 . 例如,散列可能是16个字节 . 不同的散列算法产生不同大小的散列 . 您显然无法从散列重新创建原始数据,但您可以再次散列数据以查看是否生成了相同的散列值 . 单向基于Unix的密码以这种方式工作 . 密码存储为哈希值,要登录系统,您键入的密码将被哈希,并将哈希值与实际密码的哈希值进行比较 . 如果匹配,则必须输入正确的密码
为什么哈希不可逆转:
Hashing isn't reversible because the input-to-hash mapping is not 1-to-1. 将两个输入映射到相同的散列值通常称为"hash collision" . 出于安全考虑,"good"散列函数的一个属性是碰撞在实际使用中很少见 .
当您不希望能够取回原始输入时使用哈希,请在执行时使用加密 .
哈希需要一些输入并将其转换为一些位(通常被认为是一个数字,如32位整数,64位整数等) . 相同的输入将始终产生相同的哈希,但您主要输了过程中的信息,因此您无法可靠地重现原始输入(但有一些警告) .
加密主要保留您加入到加密函数中的所有信息,只是让任何人在没有特定密钥的情况下反向回原始输入变得困难(理想情况下是不可能的) .
Simple Example of Hashing
这是一个简单的例子,可以帮助您理解为什么散列不能(在一般情况下)取回原始输入 . 假设我正在创建一个1位哈希 . 我的散列函数将一个字符串作为输入,如果输入字符串中设置了偶数位,则将散列设置为1,否则如果存在奇数则为0 .
例:
请注意,有许多输入值导致散列为0,而许多导致散列为1.如果您知道散列为0,则无法确定原始输入是什么 .
顺便说一句,这个1位哈希并不是完全人为的......看看parity bit .
Simple Example of Encryption
您可以使用简单的字母替换来加密文本,例如,如果输入是A,则写入B.如果输入是B,则写入C.一直到字母表的末尾,如果输入是Z,则再写一次 .
就像简单的哈希示例一样,这种类型的加密有been used historically .
散列和加密/解密技术的基本概述是 .
UPDATE: 解决编辑问题中提到的要点 .
我的一个班轮...一般面试官想要下面的答案 .
哈希是一种方式 . 您无法从哈希代码转换数据/字符串 .
加密是双向的 - 如果你有密钥,你可以再次解密加密的字符串 .
Hash function 将可变大小的文本转换为固定大小的文本 .
资料来源:https://en.wikipedia.org/wiki/Hash_function
让我们看看它在行动 . 我用它来做它 .
HASH:
DEHASH:
SHA1是单向散列 . 这意味着你无法取消散列哈希 . 但是,您可以强制执行哈希 . 请参阅:https://hashkiller.co.uk/sha1-decrypter.aspx .
MD5,是另一个哈希 . 可在此网站上找到MD5 dehasher:https://www.md5online.org/ .
Encryption function 使用加密密钥将文本转换为无意义的密文,反之亦然 .
资料来源:https://en.wikipedia.org/wiki/Encryption
---示例:PHP中的Mcrypt扩展---
加密:
解密:
---示例:PHP中的OpenSSL扩展---
Mcrypt扩展在7.1中被弃用 . 并在PHP 7.2中删除 . 应该在php 7中使用OpenSSL扩展 . 请参阅下面的代码片段:
Symmetric Encryption:
对称加密也可以称为共享密钥或共享秘密加密 . 在对称加密中,单个密钥用于加密和解密流量 .
Asymmetric Encryption:
非对称加密也称为公钥加密 . 非对称加密与对称加密的不同之处主要在于使用了两个密钥:一个用于加密,一个用于解密 . 最常见的非对称加密算法是
RSA
.与对称加密相比,非对称加密会带来很高的计算负担,并且往往会慢得多 . 因此,通常不采用它来保护有效载荷数据 . 相反,它的主要优势在于它能够在非安全媒体(例如,互联网)上 Build 安全通道 . 这是通过交换公钥来实现的,公钥只能用于加密数据 . 从不共享的互补私钥用于解密 .
Hashing:
最后,散列是一种加密安全形式,它与加密不同 . 加密是用于首先加密然后解密消息的两步过程,而散列将消息压缩为不可逆的固定长度值或散列 . 在网络中看到的两种最常见的哈希算法是
MD5
和SHA-1
.在这里阅读更多:http://packetlife.net/blog/2010/nov/23/symmetric-asymmetric-encryption-hashing/
当你只需要单程时使用哈希 . 例如,对于系统中的密码,您使用散列,因为您只会验证用户在散列后输入的值是否与存储库中的值匹配 . 通过加密,您可以采用两种方式 .
哈希算法和加密算法只是数学算法 . 所以在这方面他们并没有什么不同 - 它只是数学公式 . 但语义学上,散列(单向)和加密(双向)之间存在很大的区别 . 为什么哈希不可逆转?因为它们的设计是这样的,因为有时你需要单向操作 .
密码学处理数字和字符串 . 基本上整个宇宙中的每一个数字事物都是数字 . 当我说数字时,它是0和1.你知道它们是什么,二进制 . 你在屏幕上看到的图像,你通过耳机收听的音乐,一切都是二进制文件 . 但是我们的耳朵和眼睛不会理解二进制文件吗?只有大脑才能理解这一点,即使它能够理解二进制文件,它也无法享受二进制文件 . 因此,我们将二进制文件转换为人类可理解的格式,如mp3,jpg等 . 我们把这个过程称为 Encoding . 它是双向处理,可以很容易地解码回原始形式 .
Hashing
Hashing 是另一种加密技术,其中一旦转换为其他形式的数据永远无法恢复 . 在Layman的术语中,没有名为 de-hashing 的过程 . 有很多 hash functions 可以完成sha-512,md5等工作 .
如果原始值无法恢复,那么我们在哪里使用它?密码!为移动设备或PC设置密码时,会创建密码哈希并存储在安全的位置 . 当您下次进行登录尝试时,再次使用相同的算法(散列函数)对输入的字符串进行散列,并将输出与存储的值进行匹配 . 如果它是相同的,你就会登录 . 否则你就会被抛弃 .
致谢:wikimedia通过对密码应用哈希,我们可以确保攻击者即使窃取存储的密码文件也永远不会得到我们的密码 . 攻击者将拥有密码的哈希值 . 他可能会找到最常用密码的列表,并对每个密码应用 sha-512 并将其与手中的值进行比较 . 它被称为 dictionary attack . 但他会这样做多久?如果您的密码足够随机,您认为这种破解方法是否有效? Facebook,Google和亚马逊数据库中的所有密码都经过哈希处理,或者至少它们应该被哈希化 .
Then there is Encryption
加密位于散列和编码之间 . 编码是一个双向过程,不应用于提供安全性 . 加密也是一个双向过程,但当且仅当加密密钥已知时才能检索原始数据 . 如果您不知道加密的工作原理,请不要担心,我们将在此讨论基础知识 . 这足以理解SSL的基础知识 . 因此,有两种类型的加密,即对称加密和非对称加密 .
Symmetric Key Encryption
我想尽可能简单地保持事情 . 因此,让我们通过移位算法来理解对称加密 . 此算法用于通过将字母向左或向右移动来加密字母表 . 让我们取一个字符串CRYPTO并考虑一个数字3.然后,CRYPTO的加密格式将是FUBSWR . 这意味着每个字母向右移动3个位置 . 这里,单词CRYPTO被称为 Plaintext ,输出FUBSWR被称为 Ciphertext ,值3被称为 Encryption key (对称密钥),整个过程是 cipher . 这是最古老和最基本的对称密钥加密算法之一,其首次使用是在Julius Caesar时期报道的 . 因此,它以他的名字命名,它是着名的 Caesar Cipher . 任何知道加密密钥并且可以应用凯撒算法的反向并检索原始明文的人 . 因此它被称为 Symmetric Encryption .
Asymmetric Key Encryption
我们知道,在对称加密中,相同的密钥用于加密和解密 . 一旦该密钥被盗,所有数据都将消失 . 这是一个巨大的风险,我们需要更复杂的技术 . 1976年,Whitfield Diffie和Martin Hellman首次发布了非对称加密的概念,该算法被称为 Diffie–Hellman key exchange . 然后在1978年,麻省理工学院的Ron Rivest,Adi Shamir和Leonard Adleman发表了 RSA 算法 . 这些可以被视为非对称加密的基础 .
与对称加密相比,在 Asymmetric encryption 中,将有两个键而不是一个 . 一个叫 Public key ,另一个叫 Private key . 从理论上讲,在启动过程中,我们可以为我们的机器生成 Public-Private 密钥对 . 私钥应保存在安全的地方,绝不应与任何人共享 . 顾名思义,公钥可以与希望向您发送加密文本的任何人共享 . 现在,那些拥有您的公钥的人可以使用它加密秘密数据 . 如果密钥对是使用RSA算法生成的,那么它们应该在加密数据时使用相同的算法 . 通常,算法将在公钥中指定 . 加密数据只能使用您拥有的私钥解密 .
来源:傻瓜的SSL / TLS第1部分:密码套件,哈希,加密| WST(https://www.wst.space/ssl-part1-ciphersuite-hashing-encryption/)