Reputation: 576
Can't seem to figure out what I am doing wrong here, I can't get the same hash twice nor validate a password so specs 2 and 4 are failing. Does anyone see any obvious issues here that is causing me to have problems with generating the same hash twice? I'm using node v8.9.1 (and Typescript 2.6.1 which shouldn't matter I hope). I've tried using only Buffers and base64 strings (below) but nothing has worked.
Implementation:
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');
}
}
Specs:
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;
});
});
});
Upvotes: 0
Views: 1314
Reputation: 576
I've pinpointed my bug. I falsely assumed that since pbkdf2 accepts either a Buffer or a string that it would work with a Buffer, however I was storing the salt in base64 to later verify it with pdkdf2 would result in a different salt being used.
In case someone comes across this:
// 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');
}
}
Upvotes: 0
Reputation: 112865
You are not supposed to be able to generate the same PBKDF2 hash twice, that is the point of the random seed.
WRT verifying you are Base64 encoding the salt and hash in create
but not Base64 decoding them in verify
.
For debugging display the inputs and outputs of pbkdf2
for both create
and verify
, use hex for binary values such as salt
and hash
and add that to the question. This may be enough for you to see the error.
When debugging make things as simple as possible, using call backs adds a level of debugging complexity.
Upvotes: 1