【问题标题】:What is wrong with my PBKDF2 in Node here?我在 Node 中的 PBKDF2 有什么问题?
【发布时间】:2018-05-11 01:57:01
【问题描述】:

似乎无法弄清楚我在这里做错了什么,我无法两次获得相同的哈希值,也无法验证密码,因此规范 2 和 4 都失败了。有没有人在这里看到任何明显的问题导致我两次生成相同的哈希时遇到问题?我正在使用节点 v8.9.1(和 Typescript 2.6.1,我希望这无关紧要)。我试过只使用缓冲区和 base64 字符串(如下),但没有任何效果。

实施:

import { pbkdf2Sync, randomBytes } from 'crypto';

export class Auth {
  private iters = 1e1; // TODO: increase later
  private keylen = 64;
  private digest = 'sha512';

  create(password: string) {
    const salt = randomBytes(128);

    const hash = pbkdf2Sync(password, salt, this.iters, this.keylen, this.digest);

    console.log(hash.toString('hex'));

    return [salt.toString('base64'), hash.toString('base64'), this.iters].join('::');
  }

  verify(stored: string, password: string) {
    const [salt, hash, iters] = stored.split('::');

    const verify = pbkdf2Sync(password, salt, parseInt(iters, 10), this.keylen, this.digest);

    console.log(verify.toString('hex'));

    return hash === verify.toString('base64');
  }
}

规格:

  describe('Auth', () => {
  const auth = new Auth();
  const password = 'test';

  it('should hash a password', () => {
    const hash = auth.create(password);

    expect(hash).to.be.string;
  });

  it('should verify valid password', () => {
    const hash = auth.create(password);
    const valid = auth.verify(hash, password);

    expect(valid).to.be.true;
  });

  it('should reject invalid password', () => {
    const hash = auth.create(password);
    const invalid = auth.verify(hash, 'wrong input');

    expect(invalid).to.be.false;
  });
});

});

【问题讨论】:

    标签: javascript node.js typescript cryptography pbkdf2


    【解决方案1】:

    我已经查明了我的错误。我错误地认为,由于 pbkdf2 接受 Buffer 或可以与 Buffer 一起使用的字符串,但是我将 salt 存储在 base64 中以便稍后使用 pdkdf2 验证它会导致使用不同的 salt。

    如果有人遇到这种情况:

    // tslint:disable:no-shadowed-variable
    import { pbkdf2Sync, randomBytes } from 'crypto';
    
    export class Auth {
      private iters = 1e1; // TODO: increase later
      private keylen = 64;
      private digest = 'sha512';
    
      create(password: string) {
        const salt = randomBytes(128).toString('base64'); // <- salt 
        // salt was not base64 before being used by pbkdf2
    
        const hash = pbkdf2Sync(password, salt, this.iters, this.keylen, this.digest).toString('base64');
    
        return [salt, hash, this.iters].join('::');
      }
    
      verify(stored: string, password: string) {
        const [salt, hash, iters] = stored.split('::');
        const verify = pbkdf2Sync(password, salt, parseInt(iters, 10), this.keylen, this.digest);
    
        return hash === verify.toString('base64');
      }
    }
    

    【讨论】:

    • 你怎么能使用加密模块?,转了一圈寻找解决方案,但仍然面临没有模块找到加密的错误。
    • crypto 在最近的 nodejs 版本标准库中,你使用的是什么版本的 node?检查是否包含加密
    • 我正在使用 8.11.1,按照它所说的包含它的文档,还检查了我的本地系统中是否存在这样的模块,似乎它存在,还设法运行了一个小个体.js 程序使用 crypo 模块,但由于某种原因不能在 Angular .ts 中使用
    • crypto 是一个 NodeJS 模块(服务器端)。你不能在浏览器中使用加密(Angular)
    • return hash === verify.toString('base64'); 不是容易受到定时攻击吗?
    【解决方案2】:

    你不应该能够两次生成相同的 PBKDF2 哈希,这就是随机种子的点。

    WRT 验证您在 create 中对盐和哈希进行 Base64 编码,但在 verify 中未对它们进行 Base64 解码。

    要调试显示pbkdf2 的输入和输出create 和verify,请使用十六进制表示二进制值,例如salt 和hash,并将其添加到问题中。这可能足以让您看到错误。

    当调试使事情尽可能简单时,使用回调会增加一定程度的调试复杂性。

    【讨论】:

    • 谢谢你,我明白你所说的两次相同的哈希是什么意思。
    • 我已经用同步版本更新了我的帖子,但唉,尝试verify时我仍然得到不同的哈希值
    • 感谢您为我指明正确的方向,请在下方查看我自己的答案
    猜你喜欢
    • 1970-01-01
    • 2015-02-07
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-06
    • 2012-09-10
    • 2013-06-29
    相关资源
    最近更新 更多