Created
May 5, 2011 20:49
-
-
Save dennishall/957897 to your computer and use it in GitHub Desktop.
connect-auth example
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
// app.js | |
var connect = require('connect'); // needed? | |
var auth = require('connect-auth'); | |
var fs = require('fs'); | |
var express = require('express'); | |
var app = express.createServer( | |
connect.cookieDecoder(), | |
connect.session(), | |
connect.bodyDecoder(), | |
auth(require('./src/FormAuthStrategy')()), | |
express.staticProvider(__dirname + '/public') | |
); | |
// can now use res.render('whatever.haml') instead of res.send(haml.render('whatever.whatever')); | |
app.register('.haml', require('hamljs')); | |
app.get('/', function(req, res, params) { | |
req.authenticate(['sha256'], function(error, authenticated) { | |
res.writeHead(200, { 'Content-Type': 'text/plain' }); | |
res.end('Hello World'); | |
}); | |
}); | |
app.listen(3000); | |
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
//FormStrategy.js | |
var fs = require("fs"), | |
forms = require("forms"), | |
connect = require('connect'), | |
url = require('url'), | |
jsSHA = require('./jsSHA'), | |
haml = require('hamljs'), // For a higher quality implementation you may want to look at [visionmedia]'s [Jade](http://jade-lang.com) template engine, | |
mailer = require('mailer'), | |
// our own libs | |
DatabaseManager = require('./DatabaseManager-mongo').DatabaseManager, | |
db = new DatabaseManager('localhost', 27017); | |
// TODO: fix bug where real redirect_url gets clobbered by "/auth/form_callback" | |
module.exports = function(options) { | |
options = options || {}; | |
var me = {}; | |
var loginFormTimeLimit = (options.loginFormTimeLimit || 300) * 1000; //default is 300 seconds (5 minutes). | |
// not yet used/implemented | |
//var loginFormAttempts = options.loginFormAttempts || 3; //default is to allow a max of 3 unsuccessful login attempts. | |
me.name = options.name || "sha256"; | |
// templates | |
var templates = { | |
login : fs.readFileSync('views/auth/log_in.html.haml'), | |
logout : fs.readFileSync('views/auth/log_out.html.haml'), | |
register : fs.readFileSync('views/auth/register.html.haml'), | |
//confirmationEmail : fs.readFileSync('views/auth/registration-challenge.eml.txt'), // the mailer appears to take care of this, and uses mustache instead of haml | |
emailConfirmationSent : fs.readFileSync('views/auth/email_confirmation_sent.html.haml'), | |
emailConfirmationAttempt : fs.readFileSync('views/auth/email_confirmation_attempt.html.haml'), | |
forgotPassword : fs.readFileSync('views/auth/forgot_password.html.haml') | |
}; | |
// TODO: | |
// forms needs a way of customizing default rendering | |
// forms needs a way of plugging in a custom field renderer | |
// forms needs a way to customize the field label | |
// forms needs a way to group elements into a fieldset, with a legend (or heading (h2,h3,etc.)) | |
// forms needs a way to add input-level and input-group-level hints, tooltips, and or instructional/explanatory text | |
var registrationForm = forms.create({ | |
username: forms.fields.string({required: true}), | |
email: forms.fields.email({required: true, label: 'Email Address'}), | |
//website: forms.fields.url(), | |
password: forms.fields.password({required: true}), | |
password_confirm: forms.fields.password({ | |
required: true, | |
validators: [forms.validators.matchField('password')] | |
}), | |
// dummy example extra user fields ... | |
/* | |
options: forms.fields.string({ | |
choices: { | |
one: 'option one', | |
two: 'option two', | |
three: 'option three' | |
}, | |
widget: forms.widgets.select(), | |
validators: [function(form, field, callback){ | |
if(field.data === 'two') callback('two?! are you crazy?!'); | |
else callback(); | |
}] | |
}), | |
more_options: forms.fields.array({ | |
choices: {one: 'item 1', two: 'item 2', three: 'item 3'}, | |
widget: forms.widgets.multipleCheckbox() | |
}), | |
even_more: forms.fields.string({ | |
choices: {one: 'item 1', two: 'item 2', three: 'item 3'}, | |
widget: forms.widgets.multipleRadio() | |
}), | |
and_more: forms.fields.array({ | |
choices: {one: 'item 1', two: 'item 2', three: 'item 3'}, | |
widget: forms.widgets.multipleSelect() | |
}), | |
notes: forms.fields.string({ | |
widget: forms.widgets.textarea({rows: 6}) | |
}), | |
spam_me: forms.fields.boolean() | |
*/ | |
agree_to_terms: forms.fields.boolean() | |
}); | |
function failed_validation( request, response, uri ) { | |
var parsedUrl = url.parse(request.url, true); | |
var redirectUrl = "/auth/form_callback"; | |
if( uri ) { | |
redirectUrl += "?redirect_url=" + uri; | |
} | |
else if( parsedUrl.query && parsedUrl.query.redirect_url ) { | |
redirectUrl += "?redirect_url=" + parsedUrl.query.redirect_url; | |
} | |
// why not redirect server-side? | |
response.writeHead(303, { 'Location': redirectUrl }); | |
response.end(''); | |
} | |
function validate_credentials( request, response, callback ) { | |
var parsedUrl = url.parse(request.url, true); | |
if( request.body && request.body.username && request.body.password && request.body.salt) { | |
// are we within an acceptable timeframe for processing this form? | |
var saltSplits = request.body.salt.split('|'); | |
if( saltSplits.length == 2 && saltSplits[1]*1 > (new Date()).getTime() - loginFormTimeLimit ){ | |
// is there a user with that username? | |
db.findOne('users', {username: request.body.username}, function(dbresult){ | |
// does that user's password hash to the same thing? | |
var salt = request.body.salt; | |
var passwordHash = (new jsSHA(request.body.password, 'ASCII')).getHMAC(salt, 'ASCII', 'SHA-256', 'HEX'); | |
var storedPasswordHash = (new jsSHA(dbresult.password, 'ASCII')).getHMAC(salt, 'ASCII', 'SHA-256', 'HEX'); | |
if(passwordHash == storedPasswordHash){ | |
this.success( {username : request.body.username}, callback ); | |
} else { | |
this.fail( callback ); | |
} | |
}); | |
} | |
} | |
else { | |
failed_validation( request, response ); | |
} | |
} | |
// make this method available to the app (make it a public method) | |
me.authenticate = validate_credentials; | |
me.setupRoutes = function(server) { | |
server.use('/', connect.router(function routes(app){ | |
app.post('/log_in', function(request, response){ | |
request.authenticate( [me.name], function(error, authenticated) { | |
var redirectUrl= "/"; | |
var parsedUrl = url.parse(request.url, true); | |
if( parsedUrl.query && parsedUrl.query.redirect_url ) { | |
redirectUrl = parsedUrl.query.redirect_url; | |
} | |
// this seems like a couple extra http request/responses compared to server-side redirection | |
response.writeHead(303, { 'Location': redirectUrl }); | |
response.end(''); | |
}) | |
}); | |
app.get('/log_in', function(request, response){ | |
response.writeHead(200, {'Content-Type': 'text/html'}) | |
var parsedUrl = url.parse(request.url, true); | |
var redirectUrl = ""; | |
if( parsedUrl.query && parsedUrl.query.redirect_url ) { | |
redirectUrl = "?redirect_url="+ parsedUrl.query.redirect_url; | |
} | |
// todo: store the salt in the db. | |
// todo: USE the salt (do HMAC, not SHA) | |
var salt = Math.random() + "|" + (new Date().getTime()); | |
db.save('salts', salt); | |
response.end(haml.render(templates.login,{ | |
locals: { | |
'title': 'Log In', | |
'redirectUrl': redirectUrl, | |
'salt': salt | |
} | |
})); | |
}); | |
app.get('/user/register', function(){ | |
}); | |
/* | |
app.get('/user/register', function(request, response){ | |
response.end(haml.render(templates.register, { | |
locals: { | |
'title': 'Register' | |
} | |
})); | |
}); | |
app.post('/user/register', function(){ | |
var username = this.param('username'); | |
// validation goes here | |
// end validation | |
var now = new Date(); | |
var confirmationKey = ("" + Math.random()).substring(2) + "|" + (now.getTime()); | |
db.save('pendingRegistrationConfirmations',{ | |
"username": username, | |
"password": this.param('password'), | |
"firstname": this.param('firstname'), | |
"lastname": this.param('lastname'), | |
"key": confirmationKey, | |
"registrationDate": now | |
}); | |
mailer.send( | |
{ | |
host : "smtp.sendgrid.net", // smtp server hostname | |
port : "25", // smtp server port | |
domain : "smtp.sendgrid.net", // domain used by client to identify itself to server | |
to : this.param('email') || username, | |
from : "do-not-reply@" + conf.domainName, | |
subject : conf.domainName + " Registration Confirmation", | |
template : "registration-challenge.eml.txt", // path to template name | |
data : { | |
"firstname": firstname, | |
"confirmationUrl": "http://www." + conf.domainName + "/user/confirm_registration/" + confirmationKey | |
}, | |
authentication : "login", // auth login is supported; anything else is no auth | |
username : conf.mailer.username, // Base64 encoded username | |
password : conf.mailer.password // Base64 encoded password | |
}, | |
function(err, result){ | |
if(err){ | |
console.log(err); | |
} | |
} | |
); | |
// let the user know | |
res.send(haml.render( | |
"<h1>Confirmation Code Sent</h1>"+ | |
"<p>Please check your email and click the confirmation link to confirm your email.</p>" | |
)); | |
}); | |
*/ | |
app.get('/user/confirm_registration/*', function(confirmationKey, res){ | |
db.findOne('pendingRegistrationConfirmations', {key:confirmationKey}, function(err, result){ | |
if(err){ | |
// there was an error... | |
res.send(haml.render("<h1>Invalid Confirmation Code</h1>")); | |
} else { | |
var now = new Date(); | |
var expirationDate = new Date(result.date.getTime() + conf.pendingRegistrationConfirmationsExpiry); | |
if(now < expirationDate){ | |
// email is confirmed... | |
// save user to user db table | |
db.save('users', result); | |
// inform the user of successful confirmation | |
res.send(haml.render("<h1>Email Confirmed</h1>")); | |
} else { | |
res.send(haml.render("<h1>Confirmation Code Expired</h1>")); | |
} | |
} | |
}); | |
}); | |
})); | |
}; | |
return me; | |
}; |
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
/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS | |
* PUB 180-2 as well as the corresponding HMAC implementation as defined in | |
* FIPS PUB 198a | |
* | |
* Version 1.3 Copyright Brian Turek 2008-2010 | |
* Distributed under the BSD License | |
* See http://jssha.sourceforge.net/ for more information | |
* | |
* Several functions taken from Paul Johnson | |
* | |
* NOTE - changed window.jsSHA to module.exports for serverside use. | |
*/ | |
(function(){var charSize=8,b64pad="",hexCase=0,str2binb=function(a){var b=[],mask=(1<<charSize)-1,length=a.length*charSize,i;for(i=0;i<length;i+=charSize){b[i>>5]|=(a.charCodeAt(i/charSize)&mask)<<(32-charSize-(i%32))}return b},hex2binb=function(a){var b=[],length=a.length,i,num;for(i=0;i<length;i+=2){num=parseInt(a.substr(i,2),16);if(!isNaN(num)){b[i>>3]|=num<<(24-(4*(i%8)))}else{return"INVALID HEX STRING"}}return b},binb2hex=function(a){var b=(hexCase)?"0123456789ABCDEF":"0123456789abcdef",str="",length=a.length*4,i,srcByte;for(i=0;i<length;i+=1){srcByte=a[i>>2]>>((3-(i%4))*8);str+=b.charAt((srcByte>>4)&0xF)+b.charAt(srcByte&0xF)}return str},binb2b64=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"+"0123456789+/",str="",length=a.length*4,i,j,triplet;for(i=0;i<length;i+=3){triplet=(((a[i>>2]>>8*(3-i%4))&0xFF)<<16)|(((a[i+1>>2]>>8*(3-(i+1)%4))&0xFF)<<8)|((a[i+2>>2]>>8*(3-(i+2)%4))&0xFF);for(j=0;j<4;j+=1){if(i*8+j*6<=a.length*32){str+=b.charAt((triplet>>6*(3-j))&0x3F)}else{str+=b64pad}}}return str},rotr=function(x,n){return(x>>>n)|(x<<(32-n))},shr=function(x,n){return x>>>n},ch=function(x,y,z){return(x&y)^(~x&z)},maj=function(x,y,z){return(x&y)^(x&z)^(y&z)},sigma0=function(x){return rotr(x,2)^rotr(x,13)^rotr(x,22)},sigma1=function(x){return rotr(x,6)^rotr(x,11)^rotr(x,25)},gamma0=function(x){return rotr(x,7)^rotr(x,18)^shr(x,3)},gamma1=function(x){return rotr(x,17)^rotr(x,19)^shr(x,10)},safeAdd_2=function(x,y){var a=(x&0xFFFF)+(y&0xFFFF),msw=(x>>>16)+(y>>>16)+(a>>>16);return((msw&0xFFFF)<<16)|(a&0xFFFF)},safeAdd_4=function(a,b,c,d){var e=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF),msw=(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16);return((msw&0xFFFF)<<16)|(e&0xFFFF)},safeAdd_5=function(a,b,c,d,e){var f=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF),msw=(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16)+(f>>>16);return((msw&0xFFFF)<<16)|(f&0xFFFF)},coreSHA2=function(j,k,l){var a,b,c,d,e,f,g,h,T1,T2,H,lengthPosition,i,t,K,W=[],appendedMessageLength;if(l==="SHA-224"||l==="SHA-256"){lengthPosition=(((k+65)>>9)<<4)+15;K=[0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0x0FC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x06CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2];if(l==="SHA-224"){H=[0xc1059ed8,0x367cd507,0x3070dd17,0xf70e5939,0xffc00b31,0x68581511,0x64f98fa7,0xbefa4fa4]}else{H=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19]}}j[k>>5]|=0x80<<(24-k%32);j[lengthPosition]=k;appendedMessageLength=j.length;for(i=0;i<appendedMessageLength;i+=16){a=H[0];b=H[1];c=H[2];d=H[3];e=H[4];f=H[5];g=H[6];h=H[7];for(t=0;t<64;t+=1){if(t<16){W[t]=j[t+i]}else{W[t]=safeAdd_4(gamma1(W[t-2]),W[t-7],gamma0(W[t-15]),W[t-16])}T1=safeAdd_5(h,sigma1(e),ch(e,f,g),K[t],W[t]);T2=safeAdd_2(sigma0(a),maj(a,b,c));h=g;g=f;f=e;e=safeAdd_2(d,T1);d=c;c=b;b=a;a=safeAdd_2(T1,T2)}H[0]=safeAdd_2(a,H[0]);H[1]=safeAdd_2(b,H[1]);H[2]=safeAdd_2(c,H[2]);H[3]=safeAdd_2(d,H[3]);H[4]=safeAdd_2(e,H[4]);H[5]=safeAdd_2(f,H[5]);H[6]=safeAdd_2(g,H[6]);H[7]=safeAdd_2(h,H[7])}switch(l){case"SHA-224":return[H[0],H[1],H[2],H[3],H[4],H[5],H[6]];case"SHA-256":return H;default:return[]}},jsSHA=function(a,b){this.sha224=null;this.sha256=null;this.strBinLen=null;this.strToHash=null;if("HEX"===b){if(0!==(a.length%2)){return"TEXT MUST BE IN BYTE INCREMENTS"}this.strBinLen=a.length*4;this.strToHash=hex2binb(a)}else if(("ASCII"===b)||('undefined'===typeof(b))){this.strBinLen=a.length*charSize;this.strToHash=str2binb(a)}else{return"UNKNOWN TEXT INPUT TYPE"}};jsSHA.prototype={getHash:function(a,b){var c=null,message=this.strToHash.slice();switch(b){case"HEX":c=binb2hex;break;case"B64":c=binb2b64;break;default:return"FORMAT NOT RECOGNIZED"}switch(a){case"SHA-224":if(null===this.sha224){this.sha224=coreSHA2(message,this.strBinLen,a)}return c(this.sha224);case"SHA-256":if(null===this.sha256){this.sha256=coreSHA2(message,this.strBinLen,a)}return c(this.sha256);default:return"HASH NOT RECOGNIZED"}},getHMAC:function(a,b,c,d){var e,keyToUse,i,retVal,keyBinLen,hashBitSize,keyWithIPad=[],keyWithOPad=[];switch(d){case"HEX":e=binb2hex;break;case"B64":e=binb2b64;break;default:return"FORMAT NOT RECOGNIZED"}switch(c){case"SHA-224":hashBitSize=224;break;case"SHA-256":hashBitSize=256;break;default:return"HASH NOT RECOGNIZED"}if("HEX"===b){if(0!==(a.length%2)){return"KEY MUST BE IN BYTE INCREMENTS"}keyToUse=hex2binb(a);keyBinLen=a.length*4}else if("ASCII"===b){keyToUse=str2binb(a);keyBinLen=a.length*charSize}else{return"UNKNOWN KEY INPUT TYPE"}if(64<(keyBinLen/8)){keyToUse=coreSHA2(keyToUse,keyBinLen,c);keyToUse[15]&=0xFFFFFF00}else if(64>(keyBinLen/8)){keyToUse[15]&=0xFFFFFF00}for(i=0;i<=15;i+=1){keyWithIPad[i]=keyToUse[i]^0x36363636;keyWithOPad[i]=keyToUse[i]^0x5C5C5C5C}retVal=coreSHA2(keyWithIPad.concat(this.strToHash),512+this.strBinLen,c);retVal=coreSHA2(keyWithOPad.concat(retVal),512+hashBitSize,c);return(e(retVal))}};module.exports=jsSHA;}()); |
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
%form{ id:"login_form", action:"/auth/form_callback"+redirectUrl, method:"post" } | |
%label{ for:"username" } | |
Username | |
%input{ type:"text", name:"username", id:"username" } | |
%br | |
%label{ for:"password" } | |
Password | |
%input{ type:"password", name:"password", id:"password" } | |
%input{ type:"hidden", name:"salt", id:"salt", value:salt } | |
%input{ type:"submit", value:'Log In' } | |
:javascript | |
(function(){ | |
var get = function(id){return document.getElementById(id);}; | |
get('login_form').onsubmit = function(){ | |
var passwordInput = get("password"); | |
passwordInput.value=(new jsSHA(passwordInput.value)).getHash("SHA-256", "HEX"); | |
}; | |
})(); | |
%noscript | |
For your protection, JavaScript is required to log into this site. |
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
/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS | |
* PUB 180-2 as well as the corresponding HMAC implementation as defined in | |
* FIPS PUB 198a | |
* | |
* Version 1.3 Copyright Brian Turek 2008-2010 | |
* Distributed under the BSD License | |
* See http://jssha.sourceforge.net/ for more information | |
* | |
* Several functions taken from Paul Johnson | |
* | |
* NOTE - This is the client-side sha256 library | |
* | |
*/ | |
(function(){var charSize=8,b64pad="",hexCase=0,str2binb=function(a){var b=[],mask=(1<<charSize)-1,length=a.length*charSize,i;for(i=0;i<length;i+=charSize){b[i>>5]|=(a.charCodeAt(i/charSize)&mask)<<(32-charSize-(i%32))}return b},hex2binb=function(a){var b=[],length=a.length,i,num;for(i=0;i<length;i+=2){num=parseInt(a.substr(i,2),16);if(!isNaN(num)){b[i>>3]|=num<<(24-(4*(i%8)))}else{return"INVALID HEX STRING"}}return b},binb2hex=function(a){var b=(hexCase)?"0123456789ABCDEF":"0123456789abcdef",str="",length=a.length*4,i,srcByte;for(i=0;i<length;i+=1){srcByte=a[i>>2]>>((3-(i%4))*8);str+=b.charAt((srcByte>>4)&0xF)+b.charAt(srcByte&0xF)}return str},binb2b64=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"+"0123456789+/",str="",length=a.length*4,i,j,triplet;for(i=0;i<length;i+=3){triplet=(((a[i>>2]>>8*(3-i%4))&0xFF)<<16)|(((a[i+1>>2]>>8*(3-(i+1)%4))&0xFF)<<8)|((a[i+2>>2]>>8*(3-(i+2)%4))&0xFF);for(j=0;j<4;j+=1){if(i*8+j*6<=a.length*32){str+=b.charAt((triplet>>6*(3-j))&0x3F)}else{str+=b64pad}}}return str},rotr=function(x,n){return(x>>>n)|(x<<(32-n))},shr=function(x,n){return x>>>n},ch=function(x,y,z){return(x&y)^(~x&z)},maj=function(x,y,z){return(x&y)^(x&z)^(y&z)},sigma0=function(x){return rotr(x,2)^rotr(x,13)^rotr(x,22)},sigma1=function(x){return rotr(x,6)^rotr(x,11)^rotr(x,25)},gamma0=function(x){return rotr(x,7)^rotr(x,18)^shr(x,3)},gamma1=function(x){return rotr(x,17)^rotr(x,19)^shr(x,10)},safeAdd_2=function(x,y){var a=(x&0xFFFF)+(y&0xFFFF),msw=(x>>>16)+(y>>>16)+(a>>>16);return((msw&0xFFFF)<<16)|(a&0xFFFF)},safeAdd_4=function(a,b,c,d){var e=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF),msw=(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16);return((msw&0xFFFF)<<16)|(e&0xFFFF)},safeAdd_5=function(a,b,c,d,e){var f=(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF),msw=(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16)+(f>>>16);return((msw&0xFFFF)<<16)|(f&0xFFFF)},coreSHA2=function(j,k,l){var a,b,c,d,e,f,g,h,T1,T2,H,lengthPosition,i,t,K,W=[],appendedMessageLength;if(l==="SHA-224"||l==="SHA-256"){lengthPosition=(((k+65)>>9)<<4)+15;K=[0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0x0FC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x06CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2];if(l==="SHA-224"){H=[0xc1059ed8,0x367cd507,0x3070dd17,0xf70e5939,0xffc00b31,0x68581511,0x64f98fa7,0xbefa4fa4]}else{H=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19]}}j[k>>5]|=0x80<<(24-k%32);j[lengthPosition]=k;appendedMessageLength=j.length;for(i=0;i<appendedMessageLength;i+=16){a=H[0];b=H[1];c=H[2];d=H[3];e=H[4];f=H[5];g=H[6];h=H[7];for(t=0;t<64;t+=1){if(t<16){W[t]=j[t+i]}else{W[t]=safeAdd_4(gamma1(W[t-2]),W[t-7],gamma0(W[t-15]),W[t-16])}T1=safeAdd_5(h,sigma1(e),ch(e,f,g),K[t],W[t]);T2=safeAdd_2(sigma0(a),maj(a,b,c));h=g;g=f;f=e;e=safeAdd_2(d,T1);d=c;c=b;b=a;a=safeAdd_2(T1,T2)}H[0]=safeAdd_2(a,H[0]);H[1]=safeAdd_2(b,H[1]);H[2]=safeAdd_2(c,H[2]);H[3]=safeAdd_2(d,H[3]);H[4]=safeAdd_2(e,H[4]);H[5]=safeAdd_2(f,H[5]);H[6]=safeAdd_2(g,H[6]);H[7]=safeAdd_2(h,H[7])}switch(l){case"SHA-224":return[H[0],H[1],H[2],H[3],H[4],H[5],H[6]];case"SHA-256":return H;default:return[]}},jsSHA=function(a,b){this.sha224=null;this.sha256=null;this.strBinLen=null;this.strToHash=null;if("HEX"===b){if(0!==(a.length%2)){return"TEXT MUST BE IN BYTE INCREMENTS"}this.strBinLen=a.length*4;this.strToHash=hex2binb(a)}else if(("ASCII"===b)||('undefined'===typeof(b))){this.strBinLen=a.length*charSize;this.strToHash=str2binb(a)}else{return"UNKNOWN TEXT INPUT TYPE"}};jsSHA.prototype={getHash:function(a,b){var c=null,message=this.strToHash.slice();switch(b){case"HEX":c=binb2hex;break;case"B64":c=binb2b64;break;default:return"FORMAT NOT RECOGNIZED"}switch(a){case"SHA-224":if(null===this.sha224){this.sha224=coreSHA2(message,this.strBinLen,a)}return c(this.sha224);case"SHA-256":if(null===this.sha256){this.sha256=coreSHA2(message,this.strBinLen,a)}return c(this.sha256);default:return"HASH NOT RECOGNIZED"}},getHMAC:function(a,b,c,d){var e,keyToUse,i,retVal,keyBinLen,hashBitSize,keyWithIPad=[],keyWithOPad=[];switch(d){case"HEX":e=binb2hex;break;case"B64":e=binb2b64;break;default:return"FORMAT NOT RECOGNIZED"}switch(c){case"SHA-224":hashBitSize=224;break;case"SHA-256":hashBitSize=256;break;default:return"HASH NOT RECOGNIZED"}if("HEX"===b){if(0!==(a.length%2)){return"KEY MUST BE IN BYTE INCREMENTS"}keyToUse=hex2binb(a);keyBinLen=a.length*4}else if("ASCII"===b){keyToUse=str2binb(a);keyBinLen=a.length*charSize}else{return"UNKNOWN KEY INPUT TYPE"}if(64<(keyBinLen/8)){keyToUse=coreSHA2(keyToUse,keyBinLen,c);keyToUse[15]&=0xFFFFFF00}else if(64>(keyBinLen/8)){keyToUse[15]&=0xFFFFFF00}for(i=0;i<=15;i+=1){keyWithIPad[i]=keyToUse[i]^0x36363636;keyWithOPad[i]=keyToUse[i]^0x5C5C5C5C}retVal=coreSHA2(keyWithIPad.concat(this.strToHash),512+this.strBinLen,c);retVal=coreSHA2(keyWithOPad.concat(retVal),512+hashBitSize,c);return(e(retVal))}};window.jsSHA=jsSHA}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment