【问题标题】:Missing salt: Why is the salt not complete after using hashpw (bcrypt)?缺少盐:为什么使用 hashpw (bcrypt) 后盐不完整?
【发布时间】:2021-11-30 12:28:43
【问题描述】:

在制作保存密码时,我们可以使用盐进行散列。这是通过bcrypt 包完成的,但散列密码不包含完整的盐文本。见这里:

library("bcrypt")
my_password <- "password1"
my_salt <- "$2a$10$abcdefghijklmnopqrstuv"
hashpw(my_password, my_salt)
[1] "$2a$10$abcdefghijklmnopqrstuu2njjerFUdKeNqVoGia/slSqhJQ.vuAy"

所以我使用的盐是"$2a$10$abcdefghijklmnopqrstuv",但散列密码中的文本只包含直到字母u 的盐。但是here 据说:“查看以前的哈希/盐结果,注意哈希是如何附加哈希的盐”。

【问题讨论】:

  • bcrypt 使用 16 字节盐(在 Radix-64 中为 22 个字符)。过长的盐将被相应地截断。
  • @Topaco 我正在使用我认为最短的盐。在我的盐包含字母表的前 22 个字母的问题中,请参见此处:hashpw(my_password, paste0("$2a$10$", paste0(letters[1:22], collapse= ""), collapse= ""))。但是如果我们使用 21 个字母而不是 hashpw(my_password, paste0("$2a$10$", paste0(letters[1:21], collapse= ""), collapse= "")),我们会得到错误 Invalid salt
  • bcrypt salt 是 Radix-64 编码的 22 个字符长。 21 个字符的盐太短,因此出现错误消息。尝试使用gensalt() 生成盐。也许我误解了你。
  • @Topaco 在您的第一条评论中,您说超过22 个字符的盐将被截断。我上面说的是我的盐正好有 22 个字符。看看我使用gensalt(log_rounds= 10) 得到了什么:“$2a$10$0bboS2soT8klOBwvVMw1fe”。在这里,就像我的问题一样,$2y$10 不是盐的一部分,而是有关算法的信息(参见图片here)。如果您从我的问题中的盐中删除这些信息,您会看到我使用字母表的前 22 个字母作为盐。

标签: r hash cryptography bcrypt salt


【解决方案1】:

由于某种原因,盐必须以".""O""e""u" 结尾,在bcrypt 中。你可以看到这里是这样的:

# Generate a bunch of salts
library("bcrypt")
lots_salt <- NULL
for(i in 1:99999) {
  lots_salt[i] <- gensalt(10)  
}
# See unique last character
salt_end <- unique(substring(lots_salt, nchar(lots_salt[1]), nchar(lots_salt[1])))
salt_end
[1] "." "O" "e" "u"

现在我们使用问题中的盐,但使用有效的最后一个字符 ".""O""e""u",我们确实取回了我们在生成的哈希中使用的盐:

sapply(salt_end, function(salt_end_i){
  substring(hashpw(my_password, paste0(my_salt, salt_end_i)), 8, 8+21)
})

另一方面,如果我们使用除".""O""e""u" 之外的其他最后字符,我们会在生成的哈希中得到与输入盐不同的盐。例如,请参见此处:

sapply(letters, function(salt_end_i){
  substring(hashpw(my_password, paste0(my_salt, salt_end_i)), 8, 8+21)
})

因此,生成的哈希盐对于问题中使用的盐来说是不完整的,因为它没有使用 ".""O""e""u" 作为最后一个字符。为什么只有".""O""e""u" 仍然有效,因为最后一个字符仍然存在。

【讨论】:

  • 使用 16 字节的盐,附加 2 个填充字节。在盐的 128 位中,126 位可以分为 21 个块,每个块 6 位。最后两位只能形成块 000000、010000、100000 和 110000,它们映射到 bcrypt Base64 变体中的字符.Oeu。由于填充,所有后续块都由零位组成,并且被 bcrypt Base64 变体忽略。这就是为什么使用gensalt() 生成的所有盐最后都包含这4 个字符之一的原因。结尾序列为uv 的盐不是常规的 bcrypt Base64 编码,因此无效。
  • 严格来说,salt 不是 base-64 字母表的 22 个字符,salt 是 base64 编码的 16 个字节。你的观察显示了差异。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
  • 2018-03-23
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
相关资源
最近更新 更多