“双重散列”密码不仅仅是一次散列吗?
在存储任何更安全或更不安全的哈希值之前两次哈希密码?
我在说的是这样做的:
$hashed_password = hash(hash($plaintext_password));
而不仅仅是这个:
$hashed_password = hash($plaintext_password);
如果它不太安全,你能提供一个很好的解释(或链接到一个)吗?
另外,使用的散列函数是否有所作为? 如果你混合使用md5和sha1(而不是重复相同的散列函数),它有什么区别吗?
注1:当我说“双重哈希”时,我正在讨论两次密码哈希以试图使其更加模糊。 我不是在谈论解决冲突的技巧。
注2:我知道我需要添加一个随机盐来确保它的安全。 问题是用相同的算法两次散列是否有助于或伤害散列。
散列密码一次是不安全的
不,多重哈希不安全; 它们是安全密码使用的重要组成部分。
迭代散列会增加攻击者在其候选人列表中尝试每个密码所需的时间。 您可以轻松地将攻击密码所需的时间从几小时增加到几年。
简单的迭代是不够的
仅仅将哈希输出链接到输入对安全性来说是不够的。 迭代应该在保留密码熵的算法的上下文中进行。 幸运的是,有几个已发布的算法已经进行了足够的审查,以提高其设计的信心。
一个好的密钥派生算法,如PBKDF2将密码输入到每一轮哈希中,减轻了对哈希输出中的冲突的担忧。 PBKDF2可用于原样密码验证。 Bcrypt通过加密步骤跟踪密钥派生; 这样,如果发现一种快速的方法来反转密钥派生,攻击者仍然必须完成已知明文攻击。
如何破解密码
存储的密码需要防止脱机攻击。 如果密码不是盐渍的,可以用预先计算的字典攻击来破解密码(例如,使用彩虹表)。 否则,攻击者必须花时间计算每个密码的散列值,并查看它是否与存储的散列值相匹配。
所有密码的可能性不尽相同。 攻击者可能会彻底搜索所有短密码,但他们知道,每个额外角色的暴力成功机会急剧下降。 相反,他们使用最有可能的密码的有序列表。 他们从“password123”开始,并进入不经常使用的密码。
假设攻击者名单很长,有100亿候选人; 还假设一个桌面系统可以计算每秒100万次哈希值。 如果只使用一次迭代,攻击者可以测试整个列表少于三个小时。 但如果只使用2000次迭代,那么时间将延长至近8个月。 为了击败一个更复杂的攻击者 - 例如能够下载可以挖掘GPU功能的程序 - 你需要更多的迭代。
多少钱就够了?
要使用的迭代次数是安全性和用户体验之间的折衷。 攻击者可以使用的专用硬件很便宜,但它仍然可以每秒执行数亿次迭代。 攻击者系统的性能决定了在多次迭代中破解密码需要多长时间。 但是你的应用程序不太可能使用这个专用硬件。 在不加重用户的情况下,您可以执行多少次迭代取决于您的系统。
您可能可以让用户在认证过程中等待大约3/4秒左右。 剖析您的目标平台,并尽可能多地使用迭代。 我测试过的平台(移动设备上的一个用户,或者服务器平台上的许多用户)可以轻松地支持PBKDF2,其迭代次数为60,000到120,000次,或者成本因子为12或13的bcrypt。
更多的背景
阅读PKCS#5,以获取有关盐和迭代在散列中作用的权威信息。 即使PBKDF2是用于从密码生成加密密钥的,它也可以用作密码验证的单向散列。 bcrypt的每次迭代比SHA-2哈希要昂贵,所以你可以使用更少的迭代,但这个想法是相同的。 通过使用派生密钥对众所周知的纯文本进行加密,Bcrypt也超越了大多数基于PBKDF2的解决方案。 结果密文被存储为“散列”,以及一些元数据。 但是,没有什么能阻止你对PBKDF2做同样的事情。
以下是我在这个主题上写的其他答案:
对于那些说安全的人来说,他们总体上是正确的 。 如果使用得当 ,针对特定关注的“双师型”散列(或该逻辑扩展,迭代散列函数)是绝对安全的。
对于那些说不安全的人来说,他们在这种情况下是正确的。 发布在问题中的代码是不安全的。 让我们来谈谈为什么:
$hashed_password1 = md5( md5( plaintext_password ) );
$hashed_password2 = md5( plaintext_password );
我们关心的散列函数有两个基本属性:
Pre-Image Resistance - 给定一个散列$h
,应该很难找到一条消息$m
例如$h === hash($m)
第二预映像阻力 - 给定消息$m1
,应该很难找到不同的消息$m2
这样hash($m1) === hash($m2)
防碰撞 - 应该很难找到一对消息($m1, $m2)
,使得hash($m1) === hash($m2)
(注意这与第二预映像抵抗相似,但是不同的是在这里攻击者可以控制两个消息)...
为了存储密码 ,我们真正关心的是Pre-Image Resistance。 另外两个是没有意义的,因为$m1
是我们试图保证安全的用户密码。 所以如果攻击者已经拥有它,散列没有任何保护措施......
免责声明
接下来的所有事情都是基于我们关心的是Pre-Image Resistance的前提。 哈希函数的其他两个基本属性可能不会(通常不会)以相同的方式保持。 所以本文的结论只适用于使用散列函数来存储密码。 他们通常不适用...
让我们开始吧
为了讨论,我们来创建我们自己的散列函数:
function ourHash($input) {
$result = 0;
for ($i = 0; $i < strlen($input); $i++) {
$result += ord($input[$i]);
}
return (string) ($result % 256);
}
现在它应该是非常明显的这个散列函数。 它将输入的每个字符的ASCII值汇总在一起,然后以256结果取模。
所以我们来测试一下:
var_dump(
ourHash('abc'), // string(2) "38"
ourHash('def'), // string(2) "47"
ourHash('hij'), // string(2) "59"
ourHash('klm') // string(2) "68"
);
现在,让我们看看如果我们围绕函数运行几次会发生什么:
$tests = array(
"abc",
"def",
"hij",
"klm",
);
foreach ($tests as $test) {
$hash = $test;
for ($i = 0; $i < 100; $i++) {
$hash = ourHash($hash);
}
echo "Hashing $test => $hashn";
}
输出:
Hashing abc => 152
Hashing def => 152
Hashing hij => 155
Hashing klm => 155
哇,哇。 我们已经产生了碰撞! 让我们试着看看为什么:
以下是散列每个可能的散列输出的字符串的输出:
Hashing 0 => 48
Hashing 1 => 49
Hashing 2 => 50
Hashing 3 => 51
Hashing 4 => 52
Hashing 5 => 53
Hashing 6 => 54
Hashing 7 => 55
Hashing 8 => 56
Hashing 9 => 57
Hashing 10 => 97
Hashing 11 => 98
Hashing 12 => 99
Hashing 13 => 100
Hashing 14 => 101
Hashing 15 => 102
Hashing 16 => 103
Hashing 17 => 104
Hashing 18 => 105
Hashing 19 => 106
Hashing 20 => 98
Hashing 21 => 99
Hashing 22 => 100
Hashing 23 => 101
Hashing 24 => 102
Hashing 25 => 103
Hashing 26 => 104
Hashing 27 => 105
Hashing 28 => 106
Hashing 29 => 107
Hashing 30 => 99
Hashing 31 => 100
Hashing 32 => 101
Hashing 33 => 102
Hashing 34 => 103
Hashing 35 => 104
Hashing 36 => 105
Hashing 37 => 106
Hashing 38 => 107
Hashing 39 => 108
Hashing 40 => 100
Hashing 41 => 101
Hashing 42 => 102
Hashing 43 => 103
Hashing 44 => 104
Hashing 45 => 105
Hashing 46 => 106
Hashing 47 => 107
Hashing 48 => 108
Hashing 49 => 109
Hashing 50 => 101
Hashing 51 => 102
Hashing 52 => 103
Hashing 53 => 104
Hashing 54 => 105
Hashing 55 => 106
Hashing 56 => 107
Hashing 57 => 108
Hashing 58 => 109
Hashing 59 => 110
Hashing 60 => 102
Hashing 61 => 103
Hashing 62 => 104
Hashing 63 => 105
Hashing 64 => 106
Hashing 65 => 107
Hashing 66 => 108
Hashing 67 => 109
Hashing 68 => 110
Hashing 69 => 111
Hashing 70 => 103
Hashing 71 => 104
Hashing 72 => 105
Hashing 73 => 106
Hashing 74 => 107
Hashing 75 => 108
Hashing 76 => 109
Hashing 77 => 110
Hashing 78 => 111
Hashing 79 => 112
Hashing 80 => 104
Hashing 81 => 105
Hashing 82 => 106
Hashing 83 => 107
Hashing 84 => 108
Hashing 85 => 109
Hashing 86 => 110
Hashing 87 => 111
Hashing 88 => 112
Hashing 89 => 113
Hashing 90 => 105
Hashing 91 => 106
Hashing 92 => 107
Hashing 93 => 108
Hashing 94 => 109
Hashing 95 => 110
Hashing 96 => 111
Hashing 97 => 112
Hashing 98 => 113
Hashing 99 => 114
Hashing 100 => 145
Hashing 101 => 146
Hashing 102 => 147
Hashing 103 => 148
Hashing 104 => 149
Hashing 105 => 150
Hashing 106 => 151
Hashing 107 => 152
Hashing 108 => 153
Hashing 109 => 154
Hashing 110 => 146
Hashing 111 => 147
Hashing 112 => 148
Hashing 113 => 149
Hashing 114 => 150
Hashing 115 => 151
Hashing 116 => 152
Hashing 117 => 153
Hashing 118 => 154
Hashing 119 => 155
Hashing 120 => 147
Hashing 121 => 148
Hashing 122 => 149
Hashing 123 => 150
Hashing 124 => 151
Hashing 125 => 152
Hashing 126 => 153
Hashing 127 => 154
Hashing 128 => 155
Hashing 129 => 156
Hashing 130 => 148
Hashing 131 => 149
Hashing 132 => 150
Hashing 133 => 151
Hashing 134 => 152
Hashing 135 => 153
Hashing 136 => 154
Hashing 137 => 155
Hashing 138 => 156
Hashing 139 => 157
Hashing 140 => 149
Hashing 141 => 150
Hashing 142 => 151
Hashing 143 => 152
Hashing 144 => 153
Hashing 145 => 154
Hashing 146 => 155
Hashing 147 => 156
Hashing 148 => 157
Hashing 149 => 158
Hashing 150 => 150
Hashing 151 => 151
Hashing 152 => 152
Hashing 153 => 153
Hashing 154 => 154
Hashing 155 => 155
Hashing 156 => 156
Hashing 157 => 157
Hashing 158 => 158
Hashing 159 => 159
Hashing 160 => 151
Hashing 161 => 152
Hashing 162 => 153
Hashing 163 => 154
Hashing 164 => 155
Hashing 165 => 156
Hashing 166 => 157
Hashing 167 => 158
Hashing 168 => 159
Hashing 169 => 160
Hashing 170 => 152
Hashing 171 => 153
Hashing 172 => 154
Hashing 173 => 155
Hashing 174 => 156
Hashing 175 => 157
Hashing 176 => 158
Hashing 177 => 159
Hashing 178 => 160
Hashing 179 => 161
Hashing 180 => 153
Hashing 181 => 154
Hashing 182 => 155
Hashing 183 => 156
Hashing 184 => 157
Hashing 185 => 158
Hashing 186 => 159
Hashing 187 => 160
Hashing 188 => 161
Hashing 189 => 162
Hashing 190 => 154
Hashing 191 => 155
Hashing 192 => 156
Hashing 193 => 157
Hashing 194 => 158
Hashing 195 => 159
Hashing 196 => 160
Hashing 197 => 161
Hashing 198 => 162
Hashing 199 => 163
Hashing 200 => 146
Hashing 201 => 147
Hashing 202 => 148
Hashing 203 => 149
Hashing 204 => 150
Hashing 205 => 151
Hashing 206 => 152
Hashing 207 => 153
Hashing 208 => 154
Hashing 209 => 155
Hashing 210 => 147
Hashing 211 => 148
Hashing 212 => 149
Hashing 213 => 150
Hashing 214 => 151
Hashing 215 => 152
Hashing 216 => 153
Hashing 217 => 154
Hashing 218 => 155
Hashing 219 => 156
Hashing 220 => 148
Hashing 221 => 149
Hashing 222 => 150
Hashing 223 => 151
Hashing 224 => 152
Hashing 225 => 153
Hashing 226 => 154
Hashing 227 => 155
Hashing 228 => 156
Hashing 229 => 157
Hashing 230 => 149
Hashing 231 => 150
Hashing 232 => 151
Hashing 233 => 152
Hashing 234 => 153
Hashing 235 => 154
Hashing 236 => 155
Hashing 237 => 156
Hashing 238 => 157
Hashing 239 => 158
Hashing 240 => 150
Hashing 241 => 151
Hashing 242 => 152
Hashing 243 => 153
Hashing 244 => 154
Hashing 245 => 155
Hashing 246 => 156
Hashing 247 => 157
Hashing 248 => 158
Hashing 249 => 159
Hashing 250 => 151
Hashing 251 => 152
Hashing 252 => 153
Hashing 253 => 154
Hashing 254 => 155
Hashing 255 => 156
注意趋向于更高的数字。 结果是我们的失败。 对每个元素运行散列4次($ hash = ourHash($ hash)`)给我们:
Hashing 0 => 153
Hashing 1 => 154
Hashing 2 => 155
Hashing 3 => 156
Hashing 4 => 157
Hashing 5 => 158
Hashing 6 => 150
Hashing 7 => 151
Hashing 8 => 152
Hashing 9 => 153
Hashing 10 => 157
Hashing 11 => 158
Hashing 12 => 150
Hashing 13 => 154
Hashing 14 => 155
Hashing 15 => 156
Hashing 16 => 157
Hashing 17 => 158
Hashing 18 => 150
Hashing 19 => 151
Hashing 20 => 158
Hashing 21 => 150
Hashing 22 => 154
Hashing 23 => 155
Hashing 24 => 156
Hashing 25 => 157
Hashing 26 => 158
Hashing 27 => 150
Hashing 28 => 151
Hashing 29 => 152
Hashing 30 => 150
Hashing 31 => 154
Hashing 32 => 155
Hashing 33 => 156
Hashing 34 => 157
Hashing 35 => 158
Hashing 36 => 150
Hashing 37 => 151
Hashing 38 => 152
Hashing 39 => 153
Hashing 40 => 154
Hashing 41 => 155
Hashing 42 => 156
Hashing 43 => 157
Hashing 44 => 158
Hashing 45 => 150
Hashing 46 => 151
Hashing 47 => 152
Hashing 48 => 153
Hashing 49 => 154
Hashing 50 => 155
Hashing 51 => 156
Hashing 52 => 157
Hashing 53 => 158
Hashing 54 => 150
Hashing 55 => 151
Hashing 56 => 152
Hashing 57 => 153
Hashing 58 => 154
Hashing 59 => 155
Hashing 60 => 156
Hashing 61 => 157
Hashing 62 => 158
Hashing 63 => 150
Hashing 64 => 151
Hashing 65 => 152
Hashing 66 => 153
Hashing 67 => 154
Hashing 68 => 155
Hashing 69 => 156
Hashing 70 => 157
Hashing 71 => 158
Hashing 72 => 150
Hashing 73 => 151
Hashing 74 => 152
Hashing 75 => 153
Hashing 76 => 154
Hashing 77 => 155
Hashing 78 => 156
Hashing 79 => 157
Hashing 80 => 158
Hashing 81 => 150
Hashing 82 => 151
Hashing 83 => 152
Hashing 84 => 153
Hashing 85 => 154
Hashing 86 => 155
Hashing 87 => 156
Hashing 88 => 157
Hashing 89 => 158
Hashing 90 => 150
Hashing 91 => 151
Hashing 92 => 152
Hashing 93 => 153
Hashing 94 => 154
Hashing 95 => 155
Hashing 96 => 156
Hashing 97 => 157
Hashing 98 => 158
Hashing 99 => 150
Hashing 100 => 154
Hashing 101 => 155
Hashing 102 => 156
Hashing 103 => 157
Hashing 104 => 158
Hashing 105 => 150
Hashing 106 => 151
Hashing 107 => 152
Hashing 108 => 153
Hashing 109 => 154
Hashing 110 => 155
Hashing 111 => 156
Hashing 112 => 157
Hashing 113 => 158
Hashing 114 => 150
Hashing 115 => 151
Hashing 116 => 152
Hashing 117 => 153
Hashing 118 => 154
Hashing 119 => 155
Hashing 120 => 156
Hashing 121 => 157
Hashing 122 => 158
Hashing 123 => 150
Hashing 124 => 151
Hashing 125 => 152
Hashing 126 => 153
Hashing 127 => 154
Hashing 128 => 155
Hashing 129 => 156
Hashing 130 => 157
Hashing 131 => 158
Hashing 132 => 150
Hashing 133 => 151
Hashing 134 => 152
Hashing 135 => 153
Hashing 136 => 154
Hashing 137 => 155
Hashing 138 => 156
Hashing 139 => 157
Hashing 140 => 158
Hashing 141 => 150
Hashing 142 => 151
Hashing 143 => 152
Hashing 144 => 153
Hashing 145 => 154
Hashing 146 => 155
Hashing 147 => 156
Hashing 148 => 157
Hashing 149 => 158
Hashing 150 => 150
Hashing 151 => 151
Hashing 152 => 152
Hashing 153 => 153
Hashing 154 => 154
Hashing 155 => 155
Hashing 156 => 156
Hashing 157 => 157
Hashing 158 => 158
Hashing 159 => 159
Hashing 160 => 151
Hashing 161 => 152
Hashing 162 => 153
Hashing 163 => 154
Hashing 164 => 155
Hashing 165 => 156
Hashing 166 => 157
Hashing 167 => 158
Hashing 168 => 159
Hashing 169 => 151
Hashing 170 => 152
Hashing 171 => 153
Hashing 172 => 154
Hashing 173 => 155
Hashing 174 => 156
Hashing 175 => 157
Hashing 176 => 158
Hashing 177 => 159
Hashing 178 => 151
Hashing 179 => 152
Hashing 180 => 153
Hashing 181 => 154
Hashing 182 => 155
Hashing 183 => 156
Hashing 184 => 157
Hashing 185 => 158
Hashing 186 => 159
Hashing 187 => 151
Hashing 188 => 152
Hashing 189 => 153
Hashing 190 => 154
Hashing 191 => 155
Hashing 192 => 156
Hashing 193 => 157
Hashing 194 => 158
Hashing 195 => 159
Hashing 196 => 151
Hashing 197 => 152
Hashing 198 => 153
Hashing 199 => 154
Hashing 200 => 155
Hashing 201 => 156
Hashing 202 => 157
Hashing 203 => 158
Hashing 204 => 150
Hashing 205 => 151
Hashing 206 => 152
Hashing 207 => 153
Hashing 208 => 154
Hashing 209 => 155
Hashing 210 => 156
Hashing 211 => 157
Hashing 212 => 158
Hashing 213 => 150
Hashing 214 => 151
Hashing 215 => 152
Hashing 216 => 153
Hashing 217 => 154
Hashing 218 => 155
Hashing 219 => 156
Hashing 220 => 157
Hashing 221 => 158
Hashing 222 => 150
Hashing 223 => 151
Hashing 224 => 152
Hashing 225 => 153
Hashing 226 => 154
Hashing 227 => 155
Hashing 228 => 156
Hashing 229 => 157
Hashing 230 => 158
Hashing 231 => 150
Hashing 232 => 151
Hashing 233 => 152
Hashing 234 => 153
Hashing 235 => 154
Hashing 236 => 155
Hashing 237 => 156
Hashing 238 => 157
Hashing 239 => 158
Hashing 240 => 150
Hashing 241 => 151
Hashing 242 => 152
Hashing 243 => 153
Hashing 244 => 154
Hashing 245 => 155
Hashing 246 => 156
Hashing 247 => 157
Hashing 248 => 158
Hashing 249 => 159
Hashing 250 => 151
Hashing 251 => 152
Hashing 252 => 153
Hashing 253 => 154
Hashing 254 => 155
Hashing 255 => 156
我们已经将自己缩小到8个值......这很糟糕 ......我们的原始函数将S(∞)
映射到S(256)
。 那就是我们创建了一个映射$input
到$output
的Surjective Function。
既然我们有一个输出函数,我们不能保证任何输入子集的映射都不会发生冲突(事实上,实际上他们会这样做)。
这就是发生在这里的事情! 我们的功能很糟糕,但这不是为什么它能够工作(这就是为什么它的工作如此迅速和完全)。
MD5
发生同样的情况。 它将S(∞)
映射到S(2^128)
。 由于不能保证运行MD5(S(output))
将是内射的,这意味着它不会发生冲突。
TL / DR部分
因此,由于直接将输出反馈给md5
会产生冲突,因此每次迭代都会增加碰撞的机会。 然而,这是一个线性增长,这意味着虽然2^128
的结果集减少了,但它并没有显着减少到足以成为严重缺陷。
所以,
$output = md5($input); // 2^128 possibilities
$output = md5($output); // < 2^128 possibilities
$output = md5($output); // < 2^128 possibilities
$output = md5($output); // < 2^128 possibilities
$output = md5($output); // < 2^128 possibilities
你迭代的次数越多,减少得越多。
修正
幸运的是,对我们来说,解决这个问题的方法很简单:将更多内容反馈到进一步的迭代中:
$output = md5($input); // 2^128 possibilities
$output = md5($input . $output); // 2^128 possibilities
$output = md5($input . $output); // 2^128 possibilities
$output = md5($input . $output); // 2^128 possibilities
$output = md5($input . $output); // 2^128 possibilities
请注意, $input
每个单独值的进一步迭代不是2 ^ 128。 这意味着我们可能能够产生仍然在线下冲突的$input
值(并且因此将远远少于2^128
可能的输出来建立或共振)。 但$input
的一般情况仍然与单轮交易一样强劲。
等等,是吗? 我们用ourHash()
函数测试一下。 切换到$hash = ourHash($input . $hash);
,进行100次迭代:
Hashing 0 => 201
Hashing 1 => 212
Hashing 2 => 199
Hashing 3 => 201
Hashing 4 => 203
Hashing 5 => 205
Hashing 6 => 207
Hashing 7 => 209
Hashing 8 => 211
Hashing 9 => 204
Hashing 10 => 251
Hashing 11 => 147
Hashing 12 => 251
Hashing 13 => 148
Hashing 14 => 253
Hashing 15 => 0
Hashing 16 => 1
Hashing 17 => 2
Hashing 18 => 161
Hashing 19 => 163
Hashing 20 => 147
Hashing 21 => 251
Hashing 22 => 148
Hashing 23 => 253
Hashing 24 => 0
Hashing 25 => 1
Hashing 26 => 2
Hashing 27 => 161
Hashing 28 => 163
Hashing 29 => 8
Hashing 30 => 251
Hashing 31 => 148
Hashing 32 => 253
Hashing 33 => 0
Hashing 34 => 1
Hashing 35 => 2
Hashing 36 => 161
Hashing 37 => 163
Hashing 38 => 8
Hashing 39 => 4
Hashing 40 => 148
Hashing 41 => 253
Hashing 42 => 0
Hashing 43 => 1
Hashing 44 => 2
Hashing 45 => 161
Hashing 46 => 163
Hashing 47 => 8
Hashing 48 => 4
Hashing 49 => 9
Hashing 50 => 253
Hashing 51 => 0
Hashing 52 => 1
Hashing 53 => 2
Hashing 54 => 161
Hashing 55 => 163
Hashing 56 => 8
Hashing 57 => 4
Hashing 58 => 9
Hashing 59 => 11
Hashing 60 => 0
Hashing 61 => 1
Hashing 62 => 2
Hashing 63 => 161
Hashing 64 => 163
Hashing 65 => 8
Hashing 66 => 4
Hashing 67 => 9
Hashing 68 => 11
Hashing 69 => 4
Hashing 70 => 1
Hashing 71 => 2
Hashing 72 => 161
Hashing 73 => 163
Hashing 74 => 8
Hashing 75 => 4
Hashing 76 => 9
Hashing 77 => 11
Hashing 78 => 4
Hashing 79 => 3
Hashing 80 => 2
Hashing 81 => 161
Hashing 82 => 163
Hashing 83 => 8
Hashing 84 => 4
Hashing 85 => 9
Hashing 86 => 11
Hashing 87 => 4
Hashing 88 => 3
Hashing 89 => 17
Hashing 90 => 161
Hashing 91 => 163
Hashing 92 => 8
Hashing 93 => 4
Hashing 94 => 9
Hashing 95 => 11
Hashing 96 => 4
Hashing 97 => 3
Hashing 98 => 17
Hashing 99 => 13
Hashing 100 => 246
Hashing 101 => 248
Hashing 102 => 49
Hashing 103 => 44
Hashing 104 => 255
Hashing 105 => 198
Hashing 106 => 43
Hashing 107 => 51
Hashing 108 => 202
Hashing 109 => 2
Hashing 110 => 248
Hashing 111 => 49
Hashing 112 => 44
Hashing 113 => 255
Hashing 114 => 198
Hashing 115 => 43
Hashing 116 => 51
Hashing 117 => 202
Hashing 118 => 2
Hashing 119 => 51
Hashing 120 => 49
Hashing 121 => 44
Hashing 122 => 255
Hashing 123 => 198
Hashing 124 => 43
Hashing 125 => 51
Hashing 126 => 202
Hashing 127 => 2
Hashing 128 => 51
Hashing 129 => 53
Hashing 130 => 44
Hashing 131 => 255
Hashing 132 => 198
Hashing 133 => 43
Hashing 134 => 51
Hashing 135 => 202
Hashing 136 => 2
Hashing 137 => 51
Hashing 138 => 53
Hashing 139 => 55
Hashing 140 => 255
Hashing 141 => 198
Hashing 142 => 43
Hashing 143 => 51
Hashing 144 => 202
Hashing 145 => 2
Hashing 146 => 51
Hashing 147 => 53
Hashing 148 => 55
Hashing 149 => 58
Hashing 150 => 198
Hashing 151 => 43
Hashing 152 => 51
Hashing 153 => 202
Hashing 154 => 2
Hashing 155 => 51
Hashing 156 => 53
Hashing 157 => 55
Hashing 158 => 58
Hashing 159 => 0
Hashing 160 => 43
Hashing 161 => 51
Hashing 162 => 202
Hashing 163 => 2
Hashing 164 => 51
Hashing 165 => 53
Hashing 166 => 55
Hashing 167 => 58
Hashing 168 => 0
Hashing 169 => 209
Hashing 170 => 51
Hashing 171 => 202
Hashing 172 => 2
Hashing 173 => 51
Hashing 174 => 53
Hashing 175 => 55
Hashing 176 => 58
Hashing 177 => 0
Hashing 178 => 209
Hashing 179 => 216
Hashing 180 => 202
Hashing 181 => 2
Hashing 182 => 51
Hashing 183 => 53
Hashing 184 => 55
Hashing 185 => 58
Hashing 186 => 0
Hashing 187 => 209
Hashing 188 => 216
Hashing 189 => 219
Hashing 190 => 2
Hashing 191 => 51
Hashing 192 => 53
Hashing 193 => 55
Hashing 194 => 58
Hashing 195 => 0
Hashing 196 => 209
Hashing 197 => 216
Hashing 198 => 219
Hashing 199 => 220
Hashing 200 => 248
Hashing 201 => 49
Hashing 202 => 44
Hashing 203 => 255
Hashing 204 => 198
Hashing 205 => 43
Hashing 206 => 51
Hashing 207 => 202
Hashing 208 => 2
Hashing 209 => 51
Hashing 210 => 49
Hashing 211 => 44
Hashing 212 => 255
Hashing 213 => 198
Hashing 214 => 43
Hashing 215 => 51
Hashing 216 => 202
Hashing 217 => 2
Hashing 218 => 51
Hashing 219 => 53
Hashing 220 => 44
Hashing 221 => 255
Hashing 222 => 198
Hashing 223 => 43
Hashing 224 => 51
Hashing 225 => 202
Hashing 226 => 2
Hashing 227 => 51
Hashing 228 => 53
Hashing 229 => 55
Hashing 230 => 255
Hashing 231 => 198
Hashing 232 => 43
Hashing 233 => 51
Hashing 234 => 202
Hashing 235 => 2
Hashing 236 => 51
Hashing 237 => 53
Hashing 238 => 55
Hashing 239 => 58
Hashing 240 => 198
Hashing 241 => 43
Hashing 242 => 51
Hashing 243 => 202
Hashing 244 => 2
Hashing 245 => 51
Hashing 246 => 53
Hashing 247 => 55
Hashing 248 => 58
Hashing 249 => 0
Hashing 250 => 43
Hashing 251 => 51
Hashing 252 => 202
Hashing 253 => 2
Hashing 254 => 51
Hashing 255 => 53
这里仍然存在一个粗略的模式,但请注意,它不像我们的基础功能(已经非常弱)那样不是一种模式。
但是请注意, 0
和3
成为碰撞,即使它们不在单次运行中。 这是我之前说过的一个应用(对于所有输入的集合,碰撞阻力保持不变,但由于底层算法中的缺陷,特定的碰撞路径可能会打开)。
TL / DR部分
通过将输入反馈到每次迭代中,我们有效地打破了先前迭代中可能发生的任何冲突。
因此, md5($input . md5($input));
应该(理论上至少)与md5($input)
一样强。
这是重要的吗?
是。 这是PBKDF2替换RFC 2898中的PBKDF1的原因之一。考虑两个内部循环::
PBKDF1:
T_1 = Hash (P || S) ,
T_2 = Hash (T_1) ,
...
T_c = Hash (T_{c-1})
其中c
是迭代计数, P
是密码, S
是盐
PBKDF2:
U_1 = PRF (P, S || INT (i)) ,
U_2 = PRF (P, U_1) ,
...
U_c = PRF (P, U_{c-1})
PRF真的只是一个HMAC。 但是对于我们这里的目的,我们只要说PRF(P, S) = Hash(P || S)
(也就是说,两个输入的PRF大致相同,就像两个连接在一起的散列一样)。 这不是 ,但是对我们来说是这样。
所以PBKDF2保持了潜在Hash
函数的抗碰撞性能,其中PBKDF1没有。
将所有这些结合在一起:
我们知道迭代散列的安全方法。 事实上:
$hash = $input;
$i = 10000;
do {
$hash = hash($input . $hash);
} while ($i-- > 0);
通常是安全的。
现在,为了讨论为什么我们想要散列它,让我们来分析一下熵运动。
哈希处理无限集: S(∞)
并生成一个较小的,一致大小的集合S(n)
。 下一次迭代(假设输入传回S(n)
再次将S(∞)
映射到S(n)
:
S(∞) -> S(n)
S(∞) -> S(n)
S(∞) -> S(n)
S(∞) -> S(n)
S(∞) -> S(n)
S(∞) -> S(n)
请注意,最终输出的熵与第一个熵完全相同 。 迭代不会 “让它变得更加模糊”。 熵是相同的。 没有不可预测性的魔力来源(它是一个伪随机函数,而不是随机函数)。
然而,迭代有好处。 它会使散列过程人为地变慢。 这就是为什么迭代可以是一个好主意。 事实上,这是大多数现代密码哈希算法的基本原理(反复做一些事情使得它更慢)。
慢是好的,因为它正在抵御主要的安全威胁:暴力强制。 我们使用我们的哈希算法越慢,难度越大的攻击者就必须努力攻击我们窃取的密码哈希。 这是一件好事!
是的,重新哈希减少了搜索空间,但是不,这并不重要 - 有效的减少是微不足道的。
重新哈希增加了蛮力所需的时间,但这样做只有两次也不是最理想的。
你真正想要的是用PBKDF2来散列密码 - 这是一种经过验证的使用带有salt和迭代的安全散列的方法。 看看这个SO响应。
编辑:我差点忘了 - 不要使用MD5 !!!! 使用现代加密散列,如SHA-2系列(SHA-256,SHA-384和SHA-512)。
链接地址: http://www.djcxy.com/p/21521.html上一篇: Is "double hashing" a password less secure than just hashing it once?
下一篇: actor model: one actor requires information from another actor