node-identity-server
Version:
A package that allows you to verify & create identity server 2/3/4 hashes in nodeJS
210 lines (160 loc) • 8.59 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _crypto = require('crypto');
var _crypto2 = _interopRequireDefault(_crypto);
var _util = require('util');
var _util2 = _interopRequireDefault(_util);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var pbkdf2Async = _util2.default.promisify(_crypto2.default.pbkdf2);
var HashPasswordv3 = function () {
function HashPasswordv3() {
_classCallCheck(this, HashPasswordv3);
}
_createClass(HashPasswordv3, [{
key: 'verifyPassword',
value: function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(password, hashedPassword) {
var decodedBuffer, iteration, key, saltLength, salt, subkeyLength, expectedSubkey, acutalSubkey;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
decodedBuffer = null;
if (hashedPassword) {
decodedBuffer = Buffer.from(hashedPassword, 'base64');
}
iteration = 10000;
key = decodedBuffer[0];
saltLength = this.readNetworkByteOrder(decodedBuffer, 9);
if (!(saltLength < 128 / 8)) {
_context.next = 7;
break;
}
return _context.abrupt('return', false);
case 7:
_context.next = 9;
return _crypto2.default.randomBytes(16);
case 9:
salt = _context.sent;
// take the salt from the stored hash in the database.
// we effectively overwrite the bytes here from our random buffer.
decodedBuffer.copy(salt, 0, 13, 13 + saltLength);
subkeyLength = decodedBuffer.length - 13 - saltLength;
if (!(subkeyLength < 128 / 8)) {
_context.next = 14;
break;
}
return _context.abrupt('return', false);
case 14:
expectedSubkey = new Buffer(32);
decodedBuffer.copy(expectedSubkey, 0, 13 + saltLength, 13 + saltLength + expectedSubkey.length);
_context.next = 18;
return pbkdf2Async(password, salt, 10000, 32, 'sha256');
case 18:
acutalSubkey = _context.sent;
return _context.abrupt('return', this.areBuffersEqual(acutalSubkey, expectedSubkey));
case 20:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
function verifyPassword(_x, _x2) {
return _ref.apply(this, arguments);
}
return verifyPassword;
}()
}, {
key: 'hashPassword',
value: function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(password) {
var salt, subkey, outputBytes;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
_context2.next = 3;
return _crypto2.default.randomBytes(16);
case 3:
salt = _context2.sent;
_context2.next = 6;
return pbkdf2Async(password, salt, 10000, 32, 'sha256');
case 6:
subkey = _context2.sent;
outputBytes = new Buffer(13 + salt.length + subkey.length);
// Write in the format marker
outputBytes[0] = 0x01;
// Write out the byte order
this.writeNetworkByteOrder(outputBytes, 1, 1);
this.writeNetworkByteOrder(outputBytes, 5, 10000);
this.writeNetworkByteOrder(outputBytes, 9, salt.length);
salt.copy(outputBytes, 13, 0, 16);
subkey.copy(outputBytes, 13 + salt.length, 0, subkey.length);
return _context2.abrupt('return', outputBytes.toString('base64'));
case 17:
_context2.prev = 17;
_context2.t0 = _context2['catch'](0);
new Error(_context2.t0);
case 20:
case 'end':
return _context2.stop();
}
}
}, _callee2, this, [[0, 17]]);
}));
function hashPassword(_x3) {
return _ref2.apply(this, arguments);
}
return hashPassword;
}()
/**
* Writes the appropriate bytes into available slots
* @param buffer
* @param offset
* @param value
*/
}, {
key: 'writeNetworkByteOrder',
value: function writeNetworkByteOrder(buffer, offset, value) {
buffer[offset + 0] = value >> 0;
buffer[offset + 1] = value >> 8;
buffer[offset + 2] = value >> 16;
buffer[offset + 3] = value >> 24;
}
/**
* Reads the bytes back out using an offset.
* @param buffer
* @param offset
* @returns {number}
*/
}, {
key: 'readNetworkByteOrder',
value: function readNetworkByteOrder(buffer, offset) {
return buffer[offset + 0] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3];
}
}, {
key: 'areBuffersEqual',
value: function areBuffersEqual(bufA, bufB) {
var len = bufA.length;
if (len !== bufB.length) {
return false;
}
for (var i = 0; i < len; i++) {
if (bufA.readUInt8(i) !== bufB.readUInt8(i)) {
return false;
}
}
return true;
}
}]);
return HashPasswordv3;
}();
exports.default = HashPasswordv3;
//# sourceMappingURL=HashPasswordv3.js.map