Browse files

added async forms to funcions

  • Loading branch information...
1 parent e4fdd04 commit 49e5ed54e7407ca9e33d51f0204a0ad1561f6bed @kbjr committed Jun 21, 2011
Showing with 140 additions and 29 deletions.
  1. +121 −19 lib/sechash.js
  2. +1 −1 package.json
  3. +18 −9 readme.textile
View
140 lib/sechash.js
@@ -1,3 +1,13 @@
+/**
+ * sechash
+ *
+ * Secure password hashing using salt and keystretching
+ *
+ * @author James Brumond
+ * @version 0.1.1
+ * @copyright Copyright 2011 James Brumond
+ * @license Dual licensed under MIT and GPL
+ */
module.exports = (function() {
var self = { };
@@ -11,6 +21,20 @@ module.exports = (function() {
hashsum.update(str);
return hashsum.digest('hex');
};
+
+ // Defaults optional arguments for strongHash(Sync)
+ var getOptions = function(algorithm, salt, iterations) {
+ if (salt == null) {
+ salt = hash(algorithm, String(Math.random())).substring(0, 6);
+ }
+ if (iterations == null) {
+ iterations = 3000;
+ }
+ return {
+ salt: salt,
+ iterations: iterations
+ };
+ };
// ----------------------------------------------------------------------------
// Public functions
@@ -37,21 +61,59 @@ module.exports = (function() {
* @param number the number of hash iterations
* @return string
*/
- self.strongHash = function(algorithm, str, salt, iterations) {
- // Default the optional arguments
- if (salt == null) {
- salt = hash(algorithm, String(Math.random())).substring(0, 3);
+ self.strongHashSync = function(algorithm, str, salt, iterations) {
+ var opts = getOptions(algorithm, salt, iterations);
+ // Do the hashing
+ for (var i = 0; i < opts.iterations; i++) {
+ str = hash(algorithm, str + opts.salt);
}
- if (iterations == null) {
- iterations = Math.round(Math.random() * 9000) + 1000;
+ // Build the final result
+ return opts.salt + ':' + algorithm + ':' + opts.iterations + ':' + str;
+ };
+
+ /**
+ * Hash a string with salt and key stretching
+ *
+ * @access public
+ * @param string the hashing algorithm
+ * @param string the string to hash
+ * @param string the salt value
+ * @param number the number of hash iterations
+ * @param function the callback
+ * @return void
+ */
+ self.strongHash = function(algorithm, str, salt, iterations, after) {
+ // Handle shorthand execution
+ if (typeof salt === 'function') {
+ after = salt;
+ salt = null;
+ }
+ if (typeof iterations === 'function') {
+ after = iterations;
+ iterations = null;
+ }
+ // Check for a callback
+ if (typeof after !== 'function') {
+ throw new TypeError('No valid callback given');
}
+ // Generate any missing params
+ var opts = getOptions(algorithm, salt, iterations);
// Do the hashing
- var result = str;
- for (var i = 0; i < iterations; i++) {
- result = hash(algorithm, result + salt);
+ var count = opts.iterations;
+ function runHashingLoop() {
+ for (var i = 0; (i < 500 && count > 0); i++, count--) {
+ str = hash(algorithm, str + opts.salt);
+ }
+ // Continue after a short while if there is more left
+ if (count > 0) {
+ setTimeout(runHashingLoop, 3);
+ }
+ // Otherwise, finish up
+ else {
+ after(null, opts.salt + ':' + algorithm + ':' + opts.iterations + ':' + str);
+ }
}
- // Build the final result
- return salt + ':' + algorithm + ':' + iterations + ':' + result;
+ runHashingLoop();
};
/**
@@ -62,38 +124,78 @@ module.exports = (function() {
* @param string the hash to test against
* @return boolean
*/
- self.testHash = function(str, testHash) {
+ self.testHashSync = function(str, testHash) {
var data = testHash.split(':');
// Check for a 4 segment hash
if (data.length !== 4) {
throw new Error('Invalid hash string given');
}
// Test the hash
data[2] = Number(data[2]);
- return (self.strongHash(str, data[0], data[1], data[2]) === testHash);
+ return (self.strongHashSync(data[1], str, data[0], data[2]) === testHash);
+ };
+
+ /**
+ * Test if a string matches a given hash
+ *
+ * @access public
+ * @param string the string to test
+ * @param string the hash to test against
+ * @param function the callback
+ * @return void
+ */
+ self.testHash = function(str, testHash, after) {
+ var data = testHash.split(':');
+ // Check for a 4 segment hash
+ if (data.length !== 4) {
+ after(new Error('Invalid hash string given'), null);
+ }
+ // Test the hash
+ data[2] = Number(data[2]);
+ self.strongHash(data[1], str, data[0], data[2], function(err, hashStr) {
+ if (err) {
+ after(err, null);
+ } else {
+ after(null, (hashStr === testHash));
+ }
+ });
};
// ----------------------------------------------------------------------------
-// A simple automated test function
+// Simple automated test functions
- self._test = function() {
+ self._testSync = function() {
var startTime = now();
var startingString = 'Hello World';
console.log('Original String: "' + startingString + '"');
- var hash = self.strongHash(startingString);
+ var hash = self.strongHashSync('md5', startingString);
console.log('Hashed String: "' + hash + '"');
- var result = self.testHash(startingString, hash);
- console.log('Hash Test Successful: ' + result);
-
console.log('Time to Run: ' + (now() - startTime) + 'ms');
function now() {
return (new Date()).getTime();
}
};
+ self._testAsync = function() {
+ var startTime = now();
+
+ var startingString = 'Hello World';
+ console.log('Original String: "' + startingString + '"');
+
+ self.strongHash('md5', startingString, function(err, hash) {
+ console.log('Hashed String: "' + hash + '"');
+
+ console.log('Time to Run: ' + (now() - startTime) + 'ms');
+ });
+
+ function now() {
+ return (new Date()).getTime();
+ }
+ };
+
return self;
}());
View
2 package.json
@@ -2,7 +2,7 @@
"author": "James Brumond <kbjr14@gmail.com> (http://jbrumond.me)",
"name": "sechash",
"description": "Secure password hashing with salt and key stretching",
- "version": "0.1.0",
+ "version": "0.1.1",
"repository": {
"type": "git",
"url": "git://github.com/kbjr/node-sechash.git"
View
27 readme.textile
@@ -3,7 +3,7 @@ h1. sechash
h4. Secure password hashing with salt and key stretching
Author: James Brumond
-Version: 0.1.0
+Version: 0.1.1
Copyright 2011 James Brumond
Dual licensed under MIT and GPL
@@ -29,23 +29,32 @@ h3. Using the strong stuff
// This will hash the string quite a bit more strongly. It adds
// a salt parameter and an iterations parameter to make the hash
// harder to break.
-var hash1 = sechash.strongHash('md5', 'Your String', 'Salt', 2500);
+var hash1 = sechash.strongHashSync('md5', 'Your String', 'Salt', 2500);
// If no salt value is given, it will randomly generate salt for
-// you; similarly, if no iteration count is given, it will randomly
-// select a number between 1000 and 10000.
-var hash2 = sechash.strongHash('md5', 'Your String');</code></pre>
+// you; similarly, if no iteration count is given, it will default
+// to 2000.
+var hash2 = sechash.strongHashSync('md5', 'Your String');
+
+// Because this function can take so long to run, it has an asynchronous
+// option as well, which is very similar...
+sechash.strongHash('md5', 'Your String', function(err, hash3) {
+ console.log(hash3);
+});</code></pre>
h3. Testing a hash
<pre><code>var sechash = require('sechash');
// First we generate a hash...
-var hash = sechash.strongHash('md5', 'Your String', 'Salt', 2500);
+var hash = sechash.strongHashSync('md5', 'Your String', 'Salt', 2500);
// To test if a string matches a hash, we you the testHash method
-sechash.testHash('Your String', hash); // true
-sechash.testHash('Another String', hash); // false
+sechash.testHashSync('Your String', hash); // true
+sechash.testHashSync('Another String', hash); // false
-</code></pre>
+// Again, this function also has an async form...
+sechash.testHash('Your String', hash, function(err, match) {
+ console.log(match); // true
+});</code></pre>

0 comments on commit 49e5ed5

Please sign in to comment.