我在 Node 中的 PBKDF2 有什么问题?

What is wrong with my PBKDF2 in Node here?

似乎无法弄清楚我在这里做错了什么,我无法两次获得相同的哈希值,也无法验证密码,因此规范 2 和 4 失败了。有没有人在这里看到任何明显的问题导致我在两次生成相同的哈希时遇到问题?我正在使用 node 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;
  });
});

});

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

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

对于 createverify 的调试显示 pbkdf2 的输入和输出,对 salthash 等二进制值使用十六进制并将其添加到问题中。这可能足以让您看到错误。

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

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

万一有人遇到这个:

// 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');
  }
}