Skip to content

Commit

Permalink
Throw errors. Closes #24. Closes #27
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Sep 24, 2017
1 parent 434bddb commit c44c0e9
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 112 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
language: node_js

node_js:
- "4"
- "6"
- "8"
- "node"

Expand Down
37 changes: 2 additions & 35 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ const internals = {};
exports.randomString = function (size) {

const buffer = exports.randomBits((size + 1) * 6);
if (buffer instanceof Error) {
return buffer;
}

const string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
return string.slice(0, size);
};
Expand All @@ -30,10 +26,6 @@ exports.randomString = function (size) {
exports.randomDigits = function (size) {

const buffer = exports.randomBits(size * 8);
if (buffer instanceof Error) {
return buffer;
}

const digits = [];
for (let i = 0; i < buffer.length; ++i) {
digits.push(Math.floor(buffer[i] / 25.6));
Expand All @@ -50,39 +42,14 @@ exports.randomBits = function (bits) {
if (!bits ||
bits < 0) {

return Boom.internal('Invalid random bits count');
throw Boom.internal('Invalid random bits count');
}

const bytes = Math.ceil(bits / 8);
try {
return Crypto.randomBytes(bytes);
}
catch (err) {
return Boom.internal('Failed generating random bits: ' + err.message);
}
};


// Compare two strings using fixed time algorithm (to prevent time-based analysis of MAC digest match)

exports.fixedTimeComparison = function (a, b) {

if (typeof a !== 'string' ||
typeof b !== 'string') {

return false;
}

let mismatch = (a.length === b.length ? 0 : 1);
if (mismatch) {
b = a;
}

for (let i = 0; i < a.length; ++i) {
const ac = a.charCodeAt(i);
const bc = b.charCodeAt(i);
mismatch |= (ac ^ bc);
throw Boom.internal('Failed generating random bits: ' + err.message);
}

return (mismatch === 0);
};
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "cryptiles",
"description": "General purpose crypto utilities",
"version": "3.1.2",
"version": "4.0.0",
"repository": "git://github.com/hapijs/cryptiles",
"main": "lib/index.js",
"keywords": [
Expand All @@ -10,14 +10,14 @@
"utilites"
],
"engines": {
"node": ">=4.0.0"
"node": ">=8.0.0"
},
"dependencies": {
"boom": "5.x.x"
},
"devDependencies": {
"code": "4.x.x",
"lab": "13.x.x"
"code": "5.x.x",
"lab": "14.x.x"
},
"scripts": {
"test": "lab -a code -t 100 -L",
Expand Down
79 changes: 8 additions & 71 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,103 +22,40 @@ const expect = Code.expect;

describe('randomString()', () => {

it('should generate the right length string', (done) => {
it('should generate the right length string', async () => {

for (let i = 1; i <= 1000; ++i) {
expect(Cryptiles.randomString(i).length).to.equal(i);
}

done();
});

it('returns an error on invalid bits size', (done) => {
it('returns an error on invalid bits size', async () => {

expect(Cryptiles.randomString(99999999999999999999).message).to.match(/Failed generating random bits/);
done();
expect(() => Cryptiles.randomString(99999999999999999999)).to.throw(/Failed generating random bits/);
});
});

describe('randomDigits()', () => {

it('should generate the right length string', (done) => {
it('should generate the right length string', async () => {

for (let i = 1; i <= 1000; ++i) {
const string = Cryptiles.randomDigits(i);
expect(string.length).to.equal(i);
expect(string).to.match(/^\d+$/);
}

done();
});

it('returns an error on invalid bits size', (done) => {
it('returns an error on invalid bits size', async () => {

expect(Cryptiles.randomDigits(99999999999999999999).message).to.match(/Failed generating random bits/);
done();
expect(() => Cryptiles.randomDigits(99999999999999999999)).to.throw(/Failed generating random bits/);
});
});

describe('randomBits()', () => {

it('returns an error on invalid input', (done) => {

expect(Cryptiles.randomBits(0).message).to.equal('Invalid random bits count');
done();
});
});

describe('fixedTimeComparison()', () => {

const a = Cryptiles.randomString(50000);
const b = Cryptiles.randomString(150000);

it('should take the same amount of time comparing different string sizes', (done) => {

let now = Date.now();
Cryptiles.fixedTimeComparison(b, a);
const t1 = Date.now() - now;

now = Date.now();
Cryptiles.fixedTimeComparison(b, b);
const t2 = Date.now() - now;

expect(t2 - t1).to.be.within(-20, 20);
done();
});

it('should return true for equal strings', (done) => {

expect(Cryptiles.fixedTimeComparison(a, a)).to.equal(true);
done();
});

it('should return false for different strings (size, a < b)', (done) => {

expect(Cryptiles.fixedTimeComparison(a, a + 'x')).to.equal(false);
done();
});

it('should return false for different strings (size, a > b)', (done) => {

expect(Cryptiles.fixedTimeComparison(a + 'x', a)).to.equal(false);
done();
});

it('should return false for different strings (size, a = b)', (done) => {

expect(Cryptiles.fixedTimeComparison(a + 'x', a + 'y')).to.equal(false);
done();
});

it('should return false when not a string', (done) => {

expect(Cryptiles.fixedTimeComparison('x', null)).to.equal(false);
done();
});

it('should return false when not a string (left)', (done) => {
it('returns an error on invalid input', async () => {

expect(Cryptiles.fixedTimeComparison(null, 'x')).to.equal(false);
done();
expect(() => Cryptiles.randomBits(0)).to.throw('Invalid random bits count');
});
});

0 comments on commit c44c0e9

Please sign in to comment.