我正在将旧的 ruby-on-rails 站点迁移到 node/express/react/redux,并且在验证用户现有密码方面遇到了困难。 该网站目前使用 AuthLogic(scrypt) 进行身份验证/密码哈希处理,一些较旧的帐户密码仍使用 sha512 AuthLogic 算法进行哈希处理。
我一生都无法弄清楚如何在 Node.js 中复制 authLogic 的 scrypt 算法。 我已经审查了 AuthLogic 的 ruby 源咒语和底层 scrypt 包,这给了我一些线索。
我正在使用最新版本的 npm scrypt 软件包(我已经尝试了其他一些软件包,没有明显的差异)。
存储的哈希如下所示:
400$8$1d$3fbb0d3688d9da6d$5dd919ace6bdf946d48946e9dd61f0afc5116986433633e24e58809c12b5ce9a
数据库还存储了唯一的盐参数:
fbMQa7EhFp5tdOhNsT
根据 scrypt gem 源,看起来 $ 分隔的部分是成本因素和盐:
n, r, p = args[0].split('$').map{ |x| x.to_i(16) }
来自 Scrypt gem scrypt.rb 源。
根据代码,看起来前三个 $ 分隔位是 scrypt 的“成本”因素,最后一个是盐。 我不知道为什么这个盐与数据库中存储的盐不同,或者我应该如何插入它们。这促使我尝试:
const n = parseInt("400", 16)
const r = parseInt("8", 16);
const p = parseInt("1d", 16)
const result = scrypt.hashSync("[my password]",{"N":n,"r":r,"p":p}, 32, 3fbb0d3688d9da6d);
其结果是与数据库存储不同的散列,但至少是正确的长度。
80e302f9f8942ec9d81fe217c03730b5b8256b22cd91ad2dd2a448ec588ec390
所以我尝试比较一下:
const comparision = scrypt.verifyKdfSync(
"5dd919ace6bdf946d48946e9dd61f0afc5116986433633e24e58809c12b5ce9a",
"[mypassword]");
但这失败了,告诉我数据不是加密哈希数据。 我尝试在散列中添加各种成本因子和盐(带或不带 $ 分隔符),但无济于事。 我尝试将哈希值转换为缓冲区对象,但也无济于事。使用上述选项尝试 kdfSync 也失败(计算派生密钥时出错)。在线工具也不会将存储的哈希识别为 scrypt 哈希。
帮助我红宝石魔术师(或任何其他有密码学能力的人),你是我唯一的希望。
我最近遇到了这个问题,并发现 AuthLogic + Scrypt 的组合本质上是对密码进行双重加盐。 AuthLogic 创建自己的盐,存储在
password_salt
中,在调用 Scrypt 之前将其附加到用户的密码中。
因此,要直接使用 Scrypt(在 Ruby 中)验证用户的密码,您需要执行以下操作:
SCrypt::Password.new(user.crypted_password) == "[my_password]"+password_salt
对于里德来说,这意味着他们应该尝试:
const n = parseInt("400", 16)
const r = parseInt("8", 16);
const p = parseInt("1d", 16)
const result = scrypt.hashSync("[my password]"+"fbMQa7EhFp5tdOhNsT",{"N":n,"r":r,"p":p}, 32, 3fbb0d3688d9da6d);