| // Load modules |
| |
| var Crypto = require('crypto'); |
| var Boom = require('boom'); |
| |
| |
| // Declare internals |
| |
| var internals = {}; |
| |
| |
| // Generate a cryptographically strong pseudo-random data |
| |
| exports.randomString = function (size) { |
| |
| var buffer = exports.randomBits((size + 1) * 6); |
| if (buffer instanceof Error) { |
| return buffer; |
| } |
| |
| var string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, ''); |
| return string.slice(0, size); |
| }; |
| |
| |
| exports.randomBits = function (bits) { |
| |
| if (!bits || |
| bits < 0) { |
| |
| return Boom.internal('Invalid random bits count'); |
| } |
| |
| var 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; |
| } |
| |
| var mismatch = (a.length === b.length ? 0 : 1); |
| if (mismatch) { |
| b = a; |
| } |
| |
| for (var i = 0, il = a.length; i < il; ++i) { |
| var ac = a.charCodeAt(i); |
| var bc = b.charCodeAt(i); |
| mismatch |= (ac ^ bc); |
| } |
| |
| return (mismatch === 0); |
| }; |
| |
| |