我正在努力将哈希摘要生成功能添加到我们的代码库中。我想使用字符串作为哈希盐,以便可以将预先知道的密钥/密码短语添加到需要哈希的任何内容之前。我误解了这个概念吗?
5 回答
盐是添加到密码函数输入中的随机元素,目的是在每次调用时以不同的方式影响处理和输出。与“密钥”相反,盐并不意味着保密。
一个世纪前,用于加密或认证的密码方法是“秘密”的。然后,随着计算机的出现,人们意识到将方法完全保密是很困难的,因为这意味着要对软件本身保密。定期写入磁盘或体现为某些专用硬件的内容难以保密。因此,研究人员将“方法”分为两个不同的概念:算法(公开的并成为软件和硬件)和密钥(算法的参数,仅在处理期间存在于易失性 RAM 中)。密钥集中秘密,是纯数据。当密钥存储在人的大脑中时,它通常被称为“密码”
然后密钥本身随后被拆分。事实证明,为了获得适当的密码安全性,我们需要两件事:机密参数和可变参数。基本上,为不同的用途重复使用相同的密钥往往会造成麻烦。它经常泄露信息。在某些情况下(尤其是流密码,也用于散列密码),它会泄漏太多并导致成功的攻击。因此,经常需要可变性,每次加密方法运行时都会发生变化。现在好的部分是大多数时候,可变性和秘密不需要合并。也就是说,我们可以将机密与变量分开。所以密钥被分成:
- 密钥,通常称为“密钥”;
- 变量元素,通常随机选择,根据算法类型称为“盐”或“IV”(作为“初始值”)。
只有密钥需要保密。变量元素需要所有相关方都知道,但它可以是公开的。这是一种祝福,因为共享密钥很困难;用于分发这种秘密的系统会发现容纳每次算法运行时都会发生变化的可变部分的成本很高。
在存储散列密码的上下文中,上面的解释变成了以下内容:
- “重用密钥”意味着两个用户碰巧选择了相同的密码。如果密码只是简单地散列,那么两个用户将获得相同的散列值,这将显示出来。这里是泄漏。
- 同样,如果没有哈希,攻击者可以使用预先计算的表进行快速查找;他还可以同时攻击数千个密码。这仍然使用相同的泄漏,只是以某种方式证明了为什么这种泄漏是不好的。
- 加盐意味着在散列函数输入中添加一些可变数据。那个可变数据就是盐。盐的重点是两个不同的用户应该尽可能多地使用不同的盐。但是密码验证者需要能够从密码中重新计算相同的哈希值,因此他们必须能够访问盐。
由于盐必须可供验证者访问,但不需要保密,因此习惯上将盐值与哈希值一起存储。例如,在 Linux 系统上,我可以使用以下命令:
openssl passwd -1 -salt "zap" "blah"
这将计算一个散列密码,使用散列函数 MD5,适合在/etc/password
or/etc/shadow
文件中使用,用于密码"blah"
和盐"zap"
(这里,我明确选择盐,但在实际条件下应该随机选择)。那么输出是:
$1$zap$t3KZajBWMA7dVxwut6y921
其中美元符号用作分隔符。首字母"1"
标识散列方法 (MD5)。盐就在那里,以明文表示。最后一部分是哈希函数输出。
关于如何将盐和密码作为输入发送到散列函数(至少在 glibc 源代码中,可能在其他地方)有一个规范(某处)。
编辑:在“登录名和密码”用户身份验证系统中,“登录名”可以充当可通过的盐(两个不同的用户将有不同的登录名),但这并不能捕捉给定用户更改密码的情况(是否新密码与旧密码相同会泄露)。
你完全理解这个概念。只要确保预先添加的盐每次都是可重复的。
如果我对您的理解正确,那么听起来您是对的。该过程的伪代码如下所示:
string saltedValue = plainTextValue + saltString;
// or string saltedalue = saltString + plainTextValue;
Hash(saltedValue);
Salt 只是为试图获取您的信息的人们增加了另一个级别的复杂性。
如果每个加密短语的盐都不同,那就更好了,因为每个盐都需要自己的彩虹表。
值得一提的是,即使每个密码使用的盐值应该不同,但绝对不能从密码本身计算盐值!这种事情的实际结果是使您的安全性完全失效。