Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Justin Thomas
committed
Feb 2, 2012
0 parents
commit 86934d3
Showing
6 changed files
with
317 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
var express = require('express'); | ||
var hashcash = require('./lib/hashcash'); | ||
var app = express.createServer(); | ||
app.use(express.static('lib')); | ||
app.get('/protected',hashcash.middleware(),function(req,res) { | ||
res.send('Hello, World!'); | ||
}); | ||
|
||
app.get('/unprotected',function(req,res) { | ||
res.send('You should use protection.'); | ||
}); | ||
|
||
app.listen(1337); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
/** | ||
* | ||
* Secure Hash Algorithm (SHA1) | ||
* http://www.webtoolkit.info/ | ||
* | ||
**/ | ||
|
||
function SHA1 (msg) { | ||
|
||
function rotate_left(n,s) { | ||
var t4 = ( n<<s ) | (n>>>(32-s)); | ||
return t4; | ||
}; | ||
|
||
function lsb_hex(val) { | ||
var str=""; | ||
var i; | ||
var vh; | ||
var vl; | ||
|
||
for( i=0; i<=6; i+=2 ) { | ||
vh = (val>>>(i*4+4))&0x0f; | ||
vl = (val>>>(i*4))&0x0f; | ||
str += vh.toString(16) + vl.toString(16); | ||
} | ||
return str; | ||
}; | ||
|
||
function cvt_hex(val) { | ||
var str=""; | ||
var i; | ||
var v; | ||
|
||
for( i=7; i>=0; i-- ) { | ||
v = (val>>>(i*4))&0x0f; | ||
str += v.toString(16); | ||
} | ||
return str; | ||
}; | ||
|
||
|
||
function Utf8Encode(string) { | ||
string = string.replace(/\r\n/g,"\n"); | ||
var utftext = ""; | ||
|
||
for (var n = 0; n < string.length; n++) { | ||
|
||
var c = string.charCodeAt(n); | ||
|
||
if (c < 128) { | ||
utftext += String.fromCharCode(c); | ||
} | ||
else if((c > 127) && (c < 2048)) { | ||
utftext += String.fromCharCode((c >> 6) | 192); | ||
utftext += String.fromCharCode((c & 63) | 128); | ||
} | ||
else { | ||
utftext += String.fromCharCode((c >> 12) | 224); | ||
utftext += String.fromCharCode(((c >> 6) & 63) | 128); | ||
utftext += String.fromCharCode((c & 63) | 128); | ||
} | ||
|
||
} | ||
|
||
return utftext; | ||
}; | ||
|
||
var blockstart; | ||
var i, j; | ||
var W = new Array(80); | ||
var H0 = 0x67452301; | ||
var H1 = 0xEFCDAB89; | ||
var H2 = 0x98BADCFE; | ||
var H3 = 0x10325476; | ||
var H4 = 0xC3D2E1F0; | ||
var A, B, C, D, E; | ||
var temp; | ||
|
||
msg = Utf8Encode(msg); | ||
|
||
var msg_len = msg.length; | ||
|
||
var word_array = new Array(); | ||
for( i=0; i<msg_len-3; i+=4 ) { | ||
j = msg.charCodeAt(i)<<24 | msg.charCodeAt(i+1)<<16 | | ||
msg.charCodeAt(i+2)<<8 | msg.charCodeAt(i+3); | ||
word_array.push( j ); | ||
} | ||
|
||
switch( msg_len % 4 ) { | ||
case 0: | ||
i = 0x080000000; | ||
break; | ||
case 1: | ||
i = msg.charCodeAt(msg_len-1)<<24 | 0x0800000; | ||
break; | ||
|
||
case 2: | ||
i = msg.charCodeAt(msg_len-2)<<24 | msg.charCodeAt(msg_len-1)<<16 | 0x08000; | ||
break; | ||
|
||
case 3: | ||
i = msg.charCodeAt(msg_len-3)<<24 | msg.charCodeAt(msg_len-2)<<16 | msg.charCodeAt(msg_len-1)<<8 | 0x80; | ||
break; | ||
} | ||
|
||
word_array.push( i ); | ||
|
||
while( (word_array.length % 16) != 14 ) word_array.push( 0 ); | ||
|
||
word_array.push( msg_len>>>29 ); | ||
word_array.push( (msg_len<<3)&0x0ffffffff ); | ||
|
||
|
||
for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) { | ||
|
||
for( i=0; i<16; i++ ) W[i] = word_array[blockstart+i]; | ||
for( i=16; i<=79; i++ ) W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); | ||
|
||
A = H0; | ||
B = H1; | ||
C = H2; | ||
D = H3; | ||
E = H4; | ||
|
||
for( i= 0; i<=19; i++ ) { | ||
temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff; | ||
E = D; | ||
D = C; | ||
C = rotate_left(B,30); | ||
B = A; | ||
A = temp; | ||
} | ||
|
||
for( i=20; i<=39; i++ ) { | ||
temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff; | ||
E = D; | ||
D = C; | ||
C = rotate_left(B,30); | ||
B = A; | ||
A = temp; | ||
} | ||
|
||
for( i=40; i<=59; i++ ) { | ||
temp = (rotate_left(A,5) + ((B&C) | (B&D) | (C&D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff; | ||
E = D; | ||
D = C; | ||
C = rotate_left(B,30); | ||
B = A; | ||
A = temp; | ||
} | ||
|
||
for( i=60; i<=79; i++ ) { | ||
temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff; | ||
E = D; | ||
D = C; | ||
C = rotate_left(B,30); | ||
B = A; | ||
A = temp; | ||
} | ||
|
||
H0 = (H0 + A) & 0x0ffffffff; | ||
H1 = (H1 + B) & 0x0ffffffff; | ||
H2 = (H2 + C) & 0x0ffffffff; | ||
H3 = (H3 + D) & 0x0ffffffff; | ||
H4 = (H4 + E) & 0x0ffffffff; | ||
|
||
} | ||
|
||
var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4); | ||
|
||
return temp.toLowerCase(); | ||
|
||
} | ||
|
||
function hashcash(options) { | ||
var og_success = options.success; | ||
|
||
var success = function(response,statusText,xhr) { | ||
var challenge = xhr.getResponseHeader('hashcash-challenge'); | ||
var potential_answer = -1; | ||
var answered = false; | ||
var start = new Date().getTime(); | ||
|
||
while(!answered) { | ||
++potential_answer; | ||
var answer = SHA1(challenge+potential_answer); | ||
answered = answer.slice(0,3) === '000'; | ||
} | ||
|
||
console.log('answer took (' + (new Date().getTime()-start)+'ms): '+answer); | ||
options.headers = options.headers || {}; | ||
options.headers['hashcash-challenge'] = challenge; | ||
options.headers['hashcash-answer'] = potential_answer; | ||
options.success = og_success; | ||
$.ajax(options); | ||
|
||
} | ||
|
||
options.success = success; | ||
$.ajax(options); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
var crypto = require('crypto'); | ||
var os = require('os'); | ||
var hostname = os.hostname(); | ||
|
||
var requests = 0; | ||
var pending = {}; | ||
var HashCash = function() { | ||
|
||
return function(req,res,next) { | ||
|
||
// check header for challenge answer | ||
var answer = req.headers['hashcash-answer']; | ||
var challenge = req.headers['hashcash-challenge']; | ||
var still_pending = pending[challenge]; | ||
if(!answer || !challenge || !still_pending) { | ||
var shasum = crypto.createHash('sha1'); | ||
var rand = Math.random(); | ||
var txt = hostname+new Date().getTime()+req.url+requests; | ||
shasum.update(txt); | ||
var digest = shasum.digest('hex'); | ||
shasum = crypto.createHash('sha1'); | ||
shasum.update(digest); | ||
shasum.update(''+rand); | ||
challenge = shasum.digest('hex'); | ||
pending[challenge] = req; | ||
|
||
res.header('hashcash-challenge',challenge); | ||
res.send('Answer challenge to complete request.'); | ||
setTimeout(function() { | ||
delete pending[challenge]; | ||
},4000); | ||
|
||
} else { | ||
var shasum = crypto.createHash('sha1'); | ||
shasum.update(challenge); | ||
shasum.update(answer); | ||
var digest = shasum.digest('hex'); | ||
var solved = digest.slice(0,3) === "000"; | ||
if(solved) { | ||
next(); | ||
} else { | ||
res.header('hashcash-challenge',challenge); | ||
res.send('Wrong answer to challenge.'); | ||
} | ||
} | ||
|
||
requests++; | ||
|
||
}; | ||
}; | ||
|
||
exports.middleware = HashCash; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<!DOCTYPE html> | ||
|
||
<html> | ||
|
||
<head> | ||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"> | ||
</script> | ||
<script src="/hashcash-client.js"> | ||
</script> | ||
<script> | ||
$(document).ready(function() { | ||
hashcash({ | ||
url: '/protected', | ||
success:function(responseText) { | ||
console.log(responseText); | ||
} | ||
); | ||
}); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
Yo. | ||
</body> | ||
</html> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "hashcash", | ||
"version": "0.1.0", | ||
"description": "HashCash protocol for Node", | ||
"author": ["Justin Thomas <justin.thomas1@gmail.com>"], | ||
"scripts": { | ||
"test": "node test/test.js" | ||
}, | ||
"main":"./lib/hashcash", | ||
"dependencies": { | ||
"underscore":"1.2.x", | ||
"express": ">=2.5.2" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url" : "https://github.com/base698/hashcash" | ||
}, | ||
"devDependencies": { | ||
}, | ||
"engine": "node 0.6.x" | ||
} | ||
|