Что не так с моим PBKDF2 в узле здесь?

Кажется, я не могу понять, что я делаю здесь неправильно, я не могу получить один и тот же хэш дважды, ни подтвердить пароль, поэтому спецификации 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;
  });
});

});

2 ответа

Решение

Я точно определил свою ошибку. Я ошибочно предположил, что, поскольку pbkdf2 принимает либо Buffer, либо строку, что он будет работать с Buffer, тем не менее, я хранил соль в 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');
  }
}

Вы не должны иметь возможность генерировать один и тот же хэш PBKDF2 дважды, то есть точку случайного начального числа.

WRT проверяет, что вы Base64 кодируете соль и хеш в create но не Base64, декодирующий их в verify,

Для отладки отобразите входы и выходы pbkdf2 для обоих create а также verifyиспользуйте hex для двоичных значений, таких как salt а также hash и добавьте это к вопросу. Это может быть достаточно для вас, чтобы увидеть ошибку.

Когда отладка упрощает работу, использование обратных вызовов добавляет уровень сложности отладки.

Другие вопросы по тегам