diff --git a/bcrypt.js b/bcrypt.js index 62da525..98e10ec 100644 --- a/bcrypt.js +++ b/bcrypt.js @@ -166,6 +166,10 @@ function compareSync(data, hash) { throw new Error('data must be a string or Buffer and hash must be a string'); } + if (hash.indexOf('\0') !== -1) { + throw new Error('hash must not contain null bytes'); + } + return bindings.compare_sync(data, hash); } @@ -214,6 +218,13 @@ function compare(data, hash, cb) { }); } + if (hash.indexOf('\0') !== -1) { + error = new Error('hash must not contain null bytes'); + return process.nextTick(function () { + cb(error); + }); + } + return bindings.compare(data, hash, cb); } diff --git a/test/async.test.js b/test/async.test.js index fb59367..3470db4 100644 --- a/test/async.test.js +++ b/test/async.test.js @@ -207,3 +207,22 @@ test('hash_compare_one_param', done => { done(); }); }) + +test('compare_rejects_nul_byte_in_hash', done => { + expect.assertions(2); + const hash = bcrypt.hashSync("password", bcrypt.genSaltSync(10)); + bcrypt.compare("password", hash + "\x00extra", function (err, res) { + expect(err).toBeInstanceOf(Error); + expect(err.message).toBe('hash must not contain null bytes'); + done(); + }); +}) + +test('compare_normal_hash_still_works', done => { + expect.assertions(1); + const hash = bcrypt.hashSync("password", bcrypt.genSaltSync(10)); + bcrypt.compare("password", hash, function (err, res) { + expect(res).toBe(true); + done(); + }); +}) diff --git a/test/promise.test.js b/test/promise.test.js index 0103418..b89985f 100644 --- a/test/promise.test.js +++ b/test/promise.test.js @@ -138,6 +138,16 @@ test('hash_compare_one_param', () => { return expect(bcrypt.compare('password')).rejects.toThrow('data and hash arguments required') }) +test('compare_rejects_nul_byte_in_hash', () => { + const hash = bcrypt.hashSync("password", bcrypt.genSaltSync(10)); + return expect(bcrypt.compare("password", hash + "\x00extra")).rejects.toThrow('hash must not contain null bytes'); +}) + +test('compare_nul_byte_normal_hash_still_works', () => { + const hash = bcrypt.hashSync("password", bcrypt.genSaltSync(10)); + return expect(bcrypt.compare("password", hash)).resolves.toEqual(true); +}) + test('change_promise_impl_reject', () => { promises.use({ diff --git a/test/sync.test.js b/test/sync.test.js index 2e6809a..4a96b39 100644 --- a/test/sync.test.js +++ b/test/sync.test.js @@ -123,3 +123,15 @@ test('getRounds', () => { expect(9).toStrictEqual(bcrypt.getRounds(hash)) expect(() => bcrypt.getRounds('')).toThrow("invalid hash provided"); }); + +test('compareSync_rejects_nul_byte_in_hash', () => { + const hash = bcrypt.hashSync("password", bcrypt.genSaltSync(10)); + expect(bcrypt.compareSync("password", hash)).toBe(true); + expect(() => bcrypt.compareSync("password", hash + "\x00extra")).toThrow("hash must not contain null bytes"); +}); + +test('compareSync_rejects_nul_byte_mid_hash', () => { + const hash = bcrypt.hashSync("password", bcrypt.genSaltSync(10)); + const tampered = hash.slice(0, 30) + "\x00" + hash.slice(31); + expect(() => bcrypt.compareSync("password", tampered)).toThrow("hash must not contain null bytes"); +});