netcore-passwords
Advanced tools
Comparing version 1.1.0 to 2.0.0
{ | ||
"name": "netcore-passwords", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": ".NET Core compatible password hashing and verification", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -28,22 +28,46 @@ # .NET Core passwords on Node.JS | ||
### Hash passwords | ||
### Hashing passwords (Default - Version 3) | ||
#### Default (V3) | ||
``` | ||
const p = require('netcore-passwords'); | ||
/* | ||
* Callback-style | ||
*/ | ||
passwords.hash("qwerty", (err, hash) => { | ||
console.log(hash); | ||
}) | ||
// Generate hash | ||
const hash = p.hash('clearTextPassword'); | ||
console.log(hash); | ||
/* | ||
* Promise | ||
*/ | ||
passwords.hash("qwerty").then((hash) => { | ||
console.log(hash); | ||
}) | ||
/* | ||
* Async / Await | ||
*/ | ||
console.log(await passwords.hash("qwerty")); | ||
``` | ||
#### Using a specific version | ||
### Hashing passwords (Version 2) | ||
``` | ||
const p = require('netcore-passwords'); | ||
/* | ||
* Callback-style | ||
*/ | ||
passwords.hash("qwerty", { version: 2 }, (err, hash) => { | ||
console.log(hash); | ||
}) | ||
// Generate hash | ||
const hash = p.hash('clearTextPassword', { version: 2 }); | ||
console.log(hash); | ||
/* | ||
* Promise | ||
*/ | ||
passwords.hash("qwerty", { version: 2 }).then((hash) => { | ||
console.log(hash); | ||
}) | ||
/* | ||
* Async / Await | ||
*/ | ||
console.log(await passwords.hash("qwerty", { version: 2 })); | ||
``` | ||
@@ -54,12 +78,19 @@ | ||
``` | ||
const p = require('netcore-passwords'); | ||
/* | ||
* Callback-style | ||
*/ | ||
passwords.verify("qwerty", "AQAAAAEAACcQAAAAEFsyb88d2/nTrV2QJ3CG6y8ac3QwYBdnb6SR3LT/rG/SZemrHAoh/MrQmxFrqMey5A==", | ||
(err, valid) => { console.log(valid); }); | ||
const hash = ''; // Fetch this has from your users database; | ||
/* | ||
* Promise | ||
*/ | ||
passwords.verify("qwerty", "AQAAAAEAACcQAAAAEFsyb88d2/nTrV2QJ3CG6y8ac3QwYBdnb6SR3LT/rG/SZemrHAoh/MrQmxFrqMey5A==") | ||
.then((valid) => { console.log(valid); }); | ||
// Verify | ||
if (p.verify('clearTextPassword', hash)) { | ||
console.log("PASSWORD MATCH"); | ||
} else { | ||
console.log("PASSWORD DOESN'T MATCH"); | ||
} | ||
/* | ||
* Async / Await | ||
*/ | ||
console.log(await passwords.verify("qwerty", "AQAAAAEAACcQAAAAEFsyb88d2/nTrV2QJ3CG6y8ac3QwYBdnb6SR3LT/rG/SZemrHAoh/MrQmxFrqMey5A==")); | ||
``` | ||
@@ -66,0 +97,0 @@ |
@@ -11,57 +11,57 @@ const crypto = require("crypto"); | ||
function hashV2 (password) { | ||
function hashV2 (passwordBytes) { | ||
// Generate salt | ||
let salt = Buffer.alloc(SALT_SIZE); | ||
crypto.randomFillSync(salt); | ||
return new Promise((resolve, reject) => { | ||
// Generate key | ||
let derivedKey = crypto.pbkdf2Sync( | ||
new Buffer(password), salt, ITERATIONS_V2, KEY_SIZE, ALGORITHM_V2); | ||
// Generate salt | ||
let salt = Buffer.alloc(SALT_SIZE); | ||
crypto.randomFillSync(salt); | ||
// Generate final buffer | ||
let result = Buffer.alloc(HEADER_SIZE_V2 + SALT_SIZE + KEY_SIZE); | ||
result.writeInt8(0); // v2 format | ||
salt.copy(result, HEADER_SIZE_V2); // Salt | ||
derivedKey.copy(result, HEADER_SIZE_V2 + SALT_SIZE); // Derived key | ||
// Generate key | ||
crypto.pbkdf2(passwordBytes, salt, ITERATIONS_V2, KEY_SIZE, ALGORITHM_V2, (err, derivedKey) => { | ||
return result.toString("base64"); | ||
if (err) { | ||
return reject(err); | ||
} | ||
// Generate final buffer | ||
let result = Buffer.alloc(HEADER_SIZE_V2 + SALT_SIZE + KEY_SIZE); | ||
result.writeInt8(0); // v2 format | ||
salt.copy(result, HEADER_SIZE_V2); // Salt | ||
derivedKey.copy(result, HEADER_SIZE_V2 + SALT_SIZE); // Derived key | ||
resolve(result.toString("base64")); | ||
}); | ||
}); | ||
} | ||
function hashV3 (password) { | ||
function hashV3 (passwordBytes) { | ||
// Generate salt | ||
let salt = Buffer.alloc(SALT_SIZE); | ||
crypto.randomFillSync(salt); | ||
return new Promise((resolve, reject) => { | ||
// Generate key | ||
let derivedKey = crypto.pbkdf2Sync( | ||
new Buffer(password), salt, ITERATIONS_V3, KEY_SIZE, ALGORITHM_V3); | ||
// Generate salt | ||
let salt = Buffer.alloc(SALT_SIZE); | ||
crypto.randomFillSync(salt); | ||
// Generate final buffer | ||
let result = Buffer.alloc(HEADER_SIZE_V3 + SALT_SIZE + KEY_SIZE); | ||
result.writeInt8(1); // v3 format | ||
result.writeUInt32BE(1, 1); // HMAC SHA256 | ||
result.writeUInt32BE(ITERATIONS_V3, 5); // Iterations | ||
result.writeUInt32BE(SALT_SIZE, 9); // Salt size | ||
salt.copy(result, HEADER_SIZE_V3); // Salt | ||
derivedKey.copy(result, HEADER_SIZE_V3 + SALT_SIZE); // Derived key | ||
// Generate key | ||
crypto.pbkdf2(passwordBytes, salt, ITERATIONS_V3, KEY_SIZE, ALGORITHM_V3, (err, derivedKey) => { | ||
return result.toString("base64"); | ||
if (err) { | ||
return reject(err); | ||
} | ||
} | ||
// Generate final buffer | ||
let result = Buffer.alloc(HEADER_SIZE_V3 + SALT_SIZE + KEY_SIZE); | ||
result.writeInt8(1); // v3 format | ||
result.writeUInt32BE(1, 1); // HMAC SHA256 | ||
result.writeUInt32BE(ITERATIONS_V3, 5); // Iterations | ||
result.writeUInt32BE(SALT_SIZE, 9); // Salt size | ||
salt.copy(result, HEADER_SIZE_V3); // Salt | ||
derivedKey.copy(result, HEADER_SIZE_V3 + SALT_SIZE); // Derived key | ||
function hash (password, options) { | ||
resolve(result.toString("base64")); | ||
}); | ||
options = options || {}; | ||
const version = options.version || 3; | ||
switch (version) { | ||
case 2: | ||
return hashV2(password); | ||
case 3: | ||
return hashV3(password); | ||
default: | ||
throw new Error("Version not supported"); | ||
} | ||
}); | ||
} | ||
@@ -71,19 +71,26 @@ | ||
// Extract salt | ||
const salt = Buffer.alloc(SALT_SIZE); | ||
if (hashedPasswordBytes.copy(salt, 0, HEADER_SIZE_V2) != SALT_SIZE) { | ||
return false; | ||
} | ||
return new Promise((resolve, reject) => { | ||
// Extract key | ||
const key = Buffer.alloc(KEY_SIZE); | ||
if (hashedPasswordBytes.copy(key, 0, HEADER_SIZE_V2 + SALT_SIZE, HEADER_SIZE_V2 + SALT_SIZE + KEY_SIZE) != KEY_SIZE) { | ||
return false; | ||
} | ||
// Extract salt | ||
const salt = Buffer.alloc(SALT_SIZE); | ||
if (hashedPasswordBytes.copy(salt, 0, HEADER_SIZE_V2) != SALT_SIZE) { | ||
return resolve(false); | ||
} | ||
// Create derived key | ||
var derivedKey = crypto.pbkdf2Sync( | ||
passwordBytes, salt, ITERATIONS_V2, KEY_SIZE, ALGORITHM_V2); | ||
// Extract key | ||
const key = Buffer.alloc(KEY_SIZE); | ||
if (hashedPasswordBytes.copy(key, 0, HEADER_SIZE_V2 + SALT_SIZE, HEADER_SIZE_V2 + SALT_SIZE + KEY_SIZE) != KEY_SIZE) { | ||
return resolve(false); | ||
} | ||
return derivedKey.equals(key); | ||
// Generate key and verify | ||
crypto.pbkdf2(passwordBytes, salt, ITERATIONS_V2, KEY_SIZE, ALGORITHM_V2, (err, derivedKey) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
resolve(derivedKey.equals(key)); | ||
}); | ||
}); | ||
} | ||
@@ -93,33 +100,71 @@ | ||
// Extract salt size | ||
const saltSize = hashedPasswordBytes.readUInt32BE(9); | ||
if (saltSize < SALT_SIZE) { | ||
return false; | ||
} | ||
return new Promise((resolve, reject) => { | ||
const iterations = hashedPasswordBytes.readUInt32BE(5); | ||
const salt = Buffer.alloc(saltSize); | ||
const key = Buffer.alloc(KEY_SIZE); | ||
// Extract salt size | ||
const saltSize = hashedPasswordBytes.readUInt32BE(9); | ||
if (saltSize < SALT_SIZE) { | ||
return resolve(false); | ||
} | ||
// Extract salt | ||
if (hashedPasswordBytes.copy(salt, 0, HEADER_SIZE_V3, HEADER_SIZE_V3 + saltSize) != saltSize) { | ||
return false; | ||
const iterations = hashedPasswordBytes.readUInt32BE(5); | ||
const salt = Buffer.alloc(saltSize); | ||
const key = Buffer.alloc(KEY_SIZE); | ||
// Extract salt | ||
if (hashedPasswordBytes.copy(salt, 0, HEADER_SIZE_V3, HEADER_SIZE_V3 + saltSize) != saltSize) { | ||
return resolve(false); | ||
} | ||
// Extract key | ||
if (hashedPasswordBytes.copy(key, 0, HEADER_SIZE_V3 + saltSize, HEADER_SIZE_V3 + saltSize + KEY_SIZE) != KEY_SIZE) { | ||
return resolve(false); | ||
} | ||
// Generate key and verify | ||
crypto.pbkdf2(passwordBytes, salt, iterations, KEY_SIZE, ALGORITHM_V3, (err, derivedKey) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
resolve(derivedKey.equals(key)); | ||
}); | ||
}); | ||
} | ||
function hash (password, options, callback) { | ||
/* | ||
* Accept callback passed as second parameter and no options | ||
*/ | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = undefined; | ||
} | ||
// Extract key | ||
if (hashedPasswordBytes.copy(key, 0, HEADER_SIZE_V3 + saltSize, HEADER_SIZE_V3 + saltSize + KEY_SIZE) != KEY_SIZE) { | ||
return false; | ||
options = options || {}; | ||
let promise = null; | ||
switch (options.version || 3) { | ||
case 2: | ||
promise = hashV2(new Buffer(password), callback); | ||
break; | ||
case 3: | ||
promise = hashV3(new Buffer(password), callback); | ||
break; | ||
default: | ||
promise = Promise.reject(new Error("Version not supported")); | ||
} | ||
// Create derived key | ||
var derivedKey = crypto.pbkdf2Sync( | ||
passwordBytes, salt, iterations, KEY_SIZE, ALGORITHM_V3); | ||
return derivedKey.equals(key); | ||
return callback ? promise | ||
.then((r) => { callback(undefined, r) }) | ||
.catch((e) => { callback(e) }) : | ||
promise; | ||
} | ||
function verify (password, hashedPassword) { | ||
function verify (password, hashedPassword, callback) { | ||
if (!password || !hashedPassword) { | ||
return false; | ||
return callback ? callback(null, false) : Promise.resolve(false); | ||
} | ||
@@ -133,10 +178,20 @@ | ||
let promise = null; | ||
switch (version) { | ||
case 2: | ||
return verifyV2(passwordBytes, hashedPasswordBytes); | ||
promise = verifyV2(passwordBytes, hashedPasswordBytes); | ||
break; | ||
case 3: | ||
return verifyV3(passwordBytes, hashedPasswordBytes); | ||
promise = verifyV3(passwordBytes, hashedPasswordBytes); | ||
break; | ||
default: | ||
return false; | ||
promise = Promise.resolve(false); | ||
break; | ||
} | ||
return callback ? promise | ||
.then((r) => { callback(undefined, r) }) | ||
.catch((e) => { callback(e) }) : | ||
promise; | ||
} | ||
@@ -143,0 +198,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10603
7
153
105