convert passy.js/sha1.js to CoffeeScript. passy.coffee now includes a copy of the sha1 code as well. updated tiny version.

This commit is contained in:
swaits committed 2011-04-05 17:39:09 -07:00
1 parent dcb476ba1c
commit 65c7f720ea
6 files changed
+812 -335

No files matched your search

+8 -7
View File
@@ -3,11 +3,12 @@
<head>
<script type='text/javascript'>
var u=function(){function t(c){var b=[];do{b.unshift(c&255);c>>=8}while(c);return b}function s(c){var b=[],a,d=c.length;for(a=0;a<d;a++)b=b.concat(t(c.charCodeAt(a)));return b}function p(c){c=c.slice();var b=c.length*8,a=1732584193,d=4023233417,g=2562383102,h=271733878,i=3285377520,e,j,f,k,o,l,r,m,n;for(c.push(128);(c.length+8)%64;)c.push(0);c=c.concat([(b&1.8374686479671624E19)>>>56,(b&71776119061217280)>>>48,(b&280375465082880)>>>40,(b&1095216660480)>>>32,(b&4278190080)>>>24,(b&16711680)>>>16,(b&
65280)>>>8,b&255]);for(b=0;b<c.length/64;b++){e=c.slice(b*64,b*64+64);j=[];f=void 0;k=e.length;for(f=0;f<k;f+=4)j.push(e[f]<<24|e[f+1]<<16|e[f+2]<<8|e[f+3]);m=j;e=a;j=d;f=g;k=h;o=i;for(n=0;n<80;n++){l=n&15;if(n>=16){r=m[l+13&15]^m[l+8&15]^m[l+2&15]^m[l];m[l]=r<<1|r>>>31}r=n<20?(e<<5|e>>>27)+(k^j&(f^k))+o+1518500249+m[l]&4294967295:n<40?(e<<5|e>>>27)+(j^f^k)+o+1859775393+m[l]&4294967295:n<60?(e<<5|e>>>27)+(j&f|j&k|f&k)+o+2400959708+m[l]&4294967295:(e<<5|e>>>27)+(j^f^k)+o+3395469782+m[l]&4294967295;
o=k;k=f;f=j<<30|j>>>2;j=e;e=r}a=a+e&4294967295;d=d+j&4294967295;g=g+f&4294967295;h=h+k&4294967295;i=i+o&4294967295}return[a>>>24&255,a>>>16&255,a>>>8&255,a&255,d>>>24&255,d>>>16&255,d>>>8&255,d&255,g>>>24&255,g>>>16&255,g>>>8&255,g&255,h>>>24&255,h>>>16&255,h>>>8&255,h&255,i>>>24&255,i>>>16&255,i>>>8&255,i&255]}var q=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];return{g:function(c,b){var a=s(c),d=s(b),g=Array(64),h=Array(64),i;if(a.length>64)a=p(a);for(;a.length<64;)a.push(0);
for(i=0;i<64;i++){g[i]=92^a[i];h[i]=54^a[i]}a=p(g.concat(p(h.concat(d))));d="";g=a.length;for(h=0;h<g;h++)d+=q[a[h]>>>4]+q[a[h]&15];return d}}}();
window.passy=function(t,s){var p=u.g(s,t).toLowerCase();return[function(q){var c=["A","B","C","D","E","F","G","H","a","b","c","d","e","f","g","h","2","3","4","5","6","7","8","9","#","$","%","*","+","=","@","?"],b={"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,a:10,b:11,c:12,d:13,e:14,f:15},a="",d,g;for(d=0;d<q.length/2;++d){g=b[q[d*2]]*16+b[q[d*2+1]];a+=c[g%c.length]}return a}(p.slice(0,24)),p.slice(0,10)]};
window.passy=function(v,w){var x,t,y,i,z,A,u,B,k,C,s;y=function(a){var c;for(c=[];a;)c.unshift(a&255),a>>=8;return c};s=function(a){var c,b,e,d;b=[];e=0;for(d=a.length;e<d;e++)c=a[e],b=b.concat(y(c.charCodeAt(0)));return b};B=function(a){return[(a&1.8374686479671624E19)>>>56,(a&71776119061217280)>>>48,(a&280375465082880)>>>40,(a&1095216660480)>>>32,(a&4278190080)>>>24,(a&16711680)>>>16,(a&65280)>>>8,a&255]};x=function(a){var c,b,e;e=[];c=0;for(b=a.length;0<=b?c<b:c>b;c+=4)e.push(a[c]<<24|a[c+1]<<
16|a[c+2]<<8|a[c+3]);return e};t=function(a){var c;return function(){var b,e,d;d=[];b=0;for(e=a.length;b<e;b++)c=a[b],d.push("0123456789abcdef"[c>>>4&15]+"0123456789abcdef"[c&15]);return d}().join("")};k=function(a){var c,b,e,d,f,j,o,p,g,h,q,n,r,l,i,m,k;r=function(a,b){return a<<b|a>>>32-b};n=a.slice(0);c=n.length*8;g=[1732584193,4023233417,2562383102,271733878,3285377520];a=g[0];j=g[1];o=g[2];p=g[3];g=g[4];for(n.push(128);(n.length+8)%64;)n.push(0);n=n.concat(B(c));q=0;for(k=n.length;0<=k?q<k:q>
k;q+=64){m=x(n.slice(q,q+64));h=[a,j,o,p,g];c=h[0];b=h[1];e=h[2];d=h[3];f=h[4];for(h=0;h<80;h++)l=h&15,h>=16&&(i=m[l+13&15]^m[l+8&15]^m[l+2&15]^m[l],m[l]=i<<1|i>>>31),i=h<20?r(c,5)+(d^b&(e^d))+f+1518500249+m[l]&4294967295:h<40?r(c,5)+(b^e^d)+f+1859775393+m[l]&4294967295:h<60?r(c,5)+(b&e|b&d|e&d)+f+2400959708+m[l]&4294967295:r(c,5)+(b^e^d)+f+3395469782+m[l]&4294967295,f=[i,c,r(b,30),e,d],c=f[0],b=f[1],e=f[2],d=f[3],f=f[4];a=a+c&4294967295;j=j+b&4294967295;o=o+e&4294967295;p=p+d&4294967295;g=g+f&4294967295}return[a>>>
24&255,a>>>16&255,a>>>8&255,a&255,j>>>24&255,j>>>16&255,j>>>8&255,j&255,o>>>24&255,o>>>16&255,o>>>8&255,o&255,p>>>24&255,p>>>16&255,p>>>8&255,p&255,g>>>24&255,g>>>16&255,g>>>8&255,g&255]};C=function(a){return t(k(s(a)))};u=function(a,c){var b,e,d,f,j;d=s(a);f=s(c);for(d.length>64&&(d=k(d));d.length<64;)d.push(0);j=function(){var a;a=[];for(b=0;b<64;b++)a.push(92^d[b]);return a}();e=function(){var a;a=[];for(b=0;b<64;b++)a.push(54^d[b]);return a}();return t(k(j.concat(k(e.concat(f)))))};z=function(a){return a.match(/[A-H]/)&&
a.match(/[a-h]/)&&a.match(/[2-9]/)&&a.match(/[#$%*+=@?]/)};A=function(a){var c,b;c=16;for(b=a.length;16<=b?c<=b:c>=b;16<=b?c+=1:c-=1)if(z(a.substr(0,c)))return c;return a.length};i=function(a,c){var b,e,d;e=function(a){return"ABCDEFGHabcdefgh23456789#$%*+=@?"[parseInt(a,16)%32]};b=u(a,c);b+=C(b);b=function(a){var b;return function(){var c,d;d=[];b=0;for(c=a.length;0<=c?b<c:b>c;b+=2)d.push(e(a.substr(b,2)));return d}().join("")}(b);d=A(b);return b.substr(0,d)};if(!(i("0123","a")==="Gad6DdC2e3cD6dF937c82h5%"&&
i("ABab12!@CDcd34#$","aB234SLKDJF(*#@jfsdk")==="d+B8#@hh5CB%=Fef"&&i("11111111111111111111","00000000000000000000")==="Fgh5bE?94A2chdhF"))return["Error!","Error!"];return[i(w,v),u(w,v).substr(0,10)]};
</script>
<script type='text/javascript'>
@@ -61,10 +62,10 @@ window.passy=function(t,s){var p=u.g(s,t).toLowerCase();return[function(q){var c
<input type='password' id='password' onkeyup='update_passy()'><br/>
<hr/>
Site Password:<br/>
<input type='text' id='result' readonly onfocus='delayed_select(this)'>
<input type='text' size=40 id='result' readonly onfocus='delayed_select(this)'>
<br/>
Site Password (old variation):<br/>
<input type='text' id='result_old' readonly onfocus='delayed_select(this)'>
<input type='text' size=40 id='result_old' readonly onfocus='delayed_select(this)'>
</form>
</body>
+273
View File
@@ -0,0 +1,273 @@
###
passy.coffee
Implementation of passy algorithm in CoffeeScript, by Stephen Waits.
The MIT License
Copyright (c) 2011 Stephen Waits <steve@waits.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
###
passy = (text, secret) ->
#
# SHA1 code
#
# convert a single character code to its byte representation
char_code_to_bytes = (char_code) ->
result = []
while char_code
result.unshift(char_code & 0xff)
char_code >>= 8
result
# convert a string into a byte array, including multibytes chars
str_to_bytes = (str) ->
result = []
for char_code in str
result = result.concat(char_code_to_bytes(char_code.charCodeAt(0)))
result
# convert a number to an array of 8 bytes representing a 64 bit big-endian integer
num_to_big_endian_64 = (num) ->
[
(num & 0xff00000000000000) >>> 56,
(num & 0x00ff000000000000) >>> 48,
(num & 0x0000ff0000000000) >>> 40,
(num & 0x000000ff00000000) >>> 32,
(num & 0x00000000ff000000) >>> 24,
(num & 0x0000000000ff0000) >>> 16,
(num & 0x000000000000ff00) >>> 8,
(num & 0x00000000000000ff)
]
# convert an array of bytes to an array of int32 (big-endian)
bytes_to_big_endian_32 = (array) ->
((array[i] << 24) | (array[i+1] << 16) | (array[i+2] << 8) | array[i+3]) for i in [0...array.length] by 4
# take an array of bytes and return the hex string
bytes_to_hex = (bytes) ->
hextab = "0123456789abcdef"
(hextab[(x >>> 4) & 0x0f] + hextab[x & 0x0f] for x in bytes).join("")
# compute SHA1 hash
#
# input is an array of bytes (big-endian order)
# returns an array of 20 bytes
sha1 = (byte_array) ->
# helper function (rotate left)
rol = (x,i) -> (x << i) | (x >>> (32-i))
# initialize variables
message = byte_array.slice(0) # copy array, since we will modify it
message_size_in_bits = message.length * 8 # store message size for later use
# initialize hash state variables
[h0, h1, h2, h3, h4] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]
# Preprocess message in preparation for hasing:
# append the bit '1' to the message
message.push(0x80)
# append (0 <= k < 512) bits '0', so that the resulting message length (in bits) is congruent to 448 = -64 (mod 512)
message.push(0) while ((message.length + 8) % 64)
# append length of message (before pre-processing), in bits, as 64-bit big-endian integer
message = message.concat(num_to_big_endian_64(message_size_in_bits))
# Process the message in successive 512-bit chunks:
# break message into 512-bit chunks
for i_chunk in [0...message.length] by 64
# convert bytes into int32
w = bytes_to_big_endian_32(message.slice(i_chunk, i_chunk+64))
# init state with current hash
[a, b, c, d, e] = [h0, h1, h2, h3, h4]
# hash rounds
for i in [0...80]
s = i & 0xf
if (i >= 16)
temp = w[(s + 13) & 0xf] ^ w[(s + 8) & 0xf] ^ w[(s + 2) & 0xf] ^ w[s]
w[s] = (temp << 1) | (temp >>> 31)
if (i < 20)
# rol(a,5) + _________f[i]________ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( d ^ (b & (c ^ d)) ) + e + 0x5a827999 + w[s]) & 0xffffffff
else if (i < 40)
# rol(a,5) + _____f[i]____ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( b ^ c ^ d ) + e + 0x6ed9eba1 + w[s]) & 0xffffffff
else if (i < 60)
# rol(a,5) + ___________f[i]________________ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( (b & c) | (b & d) | (c & d) ) + e + 0x8f1bbcdc + w[s]) & 0xffffffff
else
# rol(a,5) + _____f[i]____ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( b ^ c ^ d ) + e + 0xca62c1d6 + w[s]) & 0xffffffff
[a, b, c, d, e] = [temp, a, rol(b,30), c, d]
# Add this chunk's hash to result so far:
h0 = (h0 + a) & 0xffffffff
h1 = (h1 + b) & 0xffffffff
h2 = (h2 + c) & 0xffffffff
h3 = (h3 + d) & 0xffffffff
h4 = (h4 + e) & 0xffffffff
# Return the final hash value (big-endian):
[
(h0 >>> 24) & 0xff, (h0 >>> 16) & 0xff, (h0 >>> 8) & 0xff, h0 & 0xff,
(h1 >>> 24) & 0xff, (h1 >>> 16) & 0xff, (h1 >>> 8) & 0xff, h1 & 0xff,
(h2 >>> 24) & 0xff, (h2 >>> 16) & 0xff, (h2 >>> 8) & 0xff, h2 & 0xff,
(h3 >>> 24) & 0xff, (h3 >>> 16) & 0xff, (h3 >>> 8) & 0xff, h3 & 0xff,
(h4 >>> 24) & 0xff, (h4 >>> 16) & 0xff, (h4 >>> 8) & 0xff, h4 & 0xff
] # note: returning this as a byte array is quite expensive!
# compute SHA1
#
# input is a string
# returns a hex string
sha1_string = (str) ->
# convert hex string to a byte array, hash, and convert back to a hex string
bytes_to_hex(sha1(str_to_bytes(str)))
#
# HMAC-SHA1 code
#
# compute HMAC-SHA1
#
# key_str and message_str are both strings
# returns a hex string
hmac_sha1 = (key_str, message_str) ->
# convert key & message to byte arrays
key = str_to_bytes(key_str)
message = str_to_bytes(message_str)
# initialize key
key = sha1(key) if key.length > 64 # keys longer than 64 are truncated to sha1 result
key.push(0) while key.length < 64 # keys shorter than 64 are padded with zeroes
# setup pads
opad = (0x5c ^ key[i] for i in [0...64])
ipad = (0x36 ^ key[i] for i in [0...64])
# calculate HMAC
bytes_to_hex(sha1(opad.concat(sha1(ipad.concat(message)))))
# create a byte string of length "size" of "b"s
byte_string = (b, size) ->
(String.fromCharCode(b) for i in [0...size]).join("")
# test HMAC-SHA1 with known test vectors, which naturally tests SHA1
verify_hmac_sha1 = ->
# SHA1 test data from RFC
test_vectors = [
[ "Jefe", "what do ya want for nothing?", "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79" ],
[ byte_string(0x0b, 20), "Hi There", "b617318655057264e28bc0b6fb378c8ef146be00" ],
[ byte_string(0xaa, 20), byte_string(0xdd, 50), "125d7342b9ac11cd91a39af48aa17b4f63f175d3" ],
[ byte_string(0x0c, 20), "Test With Truncation", "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04" ],
[ byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key - Hash Key First", "aa4ae5e15272d00e95705637ce8a3b55ed402112" ],
[ byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" ]
]
# run tests
for t in test_vectors
# return false if a test fails
return false if hmac_sha1(t[0], t[1]) != t[2]
# all tests passed
true
#
# passy code
#
# returns true if string contains one of each [A-H], [a-h], [2-9], and [#$%*+=@?]
good_passy = (str) ->
str.match(/[A-H]/) &&
str.match(/[a-h]/) &&
str.match(/[2-9]/) &&
str.match(/[#$%*+=@?]/)
# given a long string, find the minimum length "good" passy (i.e. has one of each
# character type, and meets minimum length of 16 characters)
good_passy_length = (str) ->
for i in [16..str.length]
return i if good_passy(str.substr(0,i))
return str.length # uh-oh, that's a long passy!
# encode a hex string (typically a single octet) to a passy string
encode_passy = (secret, text) ->
# our symbol table for passy
symtab = "ABCDEFGHabcdefgh23456789#$%*+=@?"
# convert a hex string to a single passy character
# * modulo and lookup in symtab string
hex2passy = (x) -> symtab[parseInt(x,16) % symtab.length]
# encode a hex string into a passy string
# 1. split a string into two character strings (octets)
# 2. encode each two char string (octet) into a single passy char
# 3. join resulting array of passy chars into a single passy string
encode = (str) ->
(hex2passy(str.substr(i,2)) for i in [0...str.length] by 2).join("")
# this is the hmac_sha1 concatenated with the sha1(hmac_sha1)
double_hmac = hmac_sha1(secret,text)
double_hmac = double_hmac + sha1_string(double_hmac)
# convert the hex hmac-sha1 string to a passy string
encoded = encode(double_hmac)
# determine the length of the passy
len = good_passy_length(encoded)
# finally, return the passy string
encoded.substr(0,len)
# encode a hex string into the old version of a passy string
encode_passy_legacy = (secret, text) ->
hmac_sha1(secret,text).substr(0,10)
# begin main passy function
# return an error if passy fails on this javascript
return ["Error!","Error!"] unless (
encode_passy( "0123", "a") == "Gad6DdC2e3cD6dF937c82h5%" &&
encode_passy( "ABab12!@CDcd34#$", "aB234SLKDJF(*#@jfsdk",) == "d+B8#@hh5CB%=Fef" &&
encode_passy("11111111111111111111", "00000000000000000000",) == "Fgh5bE?94A2chdhF"
)
# return both new and old passy results (for now)
[encode_passy(secret,text),encode_passy_legacy(secret,text)]
# add to the DOM (for Google closure compiler)
window['passy'] = passy
+2 -6
View File
@@ -1,12 +1,8 @@
<html>
<head>
<script type='text/javascript' src='sha1.js'></script>
<script type='text/javascript' src='passy.js'></script>
<script type='text/javascript'>
// TODO: do something if this test actually fails
SHA1.test();
var password_timer=0;
function delayed_select(target)
{
@@ -55,10 +51,10 @@
<input type='password' id='password' onkeyup='update_passy()'><br/>
<hr/>
Site Password:<br/>
<input type='text' id='result' readonly onfocus='delayed_select(this)'>
<input type='text' size=40 id='result' readonly onfocus='delayed_select(this)'>
<br/>
Site Password (old version):<br/>
<input type='text' id='result_old' readonly onfocus='delayed_select(this)'>
<input type='text' size=40 id='result_old' readonly onfocus='delayed_select(this)'>
</form>
</body>
</html>
+191 -56
View File
@@ -1,38 +1,184 @@
/*
* passy.js - implementation of passy algorithm in javascript, by Stephen Waits
*
* The MIT License
*
* Copyright (c) 2010 Stephen Waits <steve@waits.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*jslint onevar: true, undef: true, nomen: true, regexp: true, newcap: true, immed: true */
passy.coffee
/*
* Given a "text" (i.e. "amazon.com") and a "secret" (i.e. "mypassword") return an
* array of four Passy'fied passwords.
*/
var passy;
Implementation of passy algorithm in CoffeeScript, by Stephen Waits.
The MIT License
Copyright (c) 2011 Stephen Waits <steve@waits.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/var passy;
passy = function(text, secret) {
var encode, hex2passy, symtab;
var byte_string, bytes_to_big_endian_32, bytes_to_hex, char_code_to_bytes, encode_passy, encode_passy_legacy, good_passy, good_passy_length, hmac_sha1, num_to_big_endian_64, sha1, sha1_string, str_to_bytes, verify_hmac_sha1;
char_code_to_bytes = function(char_code) {
var result;
result = [];
while (char_code) {
result.unshift(char_code & 0xff);
char_code >>= 8;
}
return result;
};
str_to_bytes = function(str) {
var char_code, result, _i, _len;
result = [];
for (_i = 0, _len = str.length; _i < _len; _i++) {
char_code = str[_i];
result = result.concat(char_code_to_bytes(char_code.charCodeAt(0)));
}
return result;
};
num_to_big_endian_64 = function(num) {
return [(num & 0xff00000000000000) >>> 56, (num & 0x00ff000000000000) >>> 48, (num & 0x0000ff0000000000) >>> 40, (num & 0x000000ff00000000) >>> 32, (num & 0x00000000ff000000) >>> 24, (num & 0x0000000000ff0000) >>> 16, (num & 0x000000000000ff00) >>> 8, num & 0x00000000000000ff];
};
bytes_to_big_endian_32 = function(array) {
var i, _ref, _results;
_results = [];
for (i = 0, _ref = array.length; (0 <= _ref ? i < _ref : i > _ref); i += 4) {
_results.push((array[i] << 24) | (array[i + 1] << 16) | (array[i + 2] << 8) | array[i + 3]);
}
return _results;
};
bytes_to_hex = function(bytes) {
var hextab, x;
hextab = "0123456789abcdef";
return ((function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = bytes.length; _i < _len; _i++) {
x = bytes[_i];
_results.push(hextab[(x >>> 4) & 0x0f] + hextab[x & 0x0f]);
}
return _results;
})()).join("");
};
sha1 = function(byte_array) {
var a, b, c, d, e, h0, h1, h2, h3, h4, i, i_chunk, message, message_size_in_bits, rol, s, temp, w, _ref, _ref2, _ref3, _ref4;
rol = function(x, i) {
return (x << i) | (x >>> (32 - i));
};
message = byte_array.slice(0);
message_size_in_bits = message.length * 8;
_ref = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], h0 = _ref[0], h1 = _ref[1], h2 = _ref[2], h3 = _ref[3], h4 = _ref[4];
message.push(0x80);
while ((message.length + 8) % 64) {
message.push(0);
}
message = message.concat(num_to_big_endian_64(message_size_in_bits));
for (i_chunk = 0, _ref2 = message.length; (0 <= _ref2 ? i_chunk < _ref2 : i_chunk > _ref2); i_chunk += 64) {
w = bytes_to_big_endian_32(message.slice(i_chunk, i_chunk + 64));
_ref3 = [h0, h1, h2, h3, h4], a = _ref3[0], b = _ref3[1], c = _ref3[2], d = _ref3[3], e = _ref3[4];
for (i = 0; i < 80; i++) {
s = i & 0xf;
if (i >= 16) {
temp = w[(s + 13) & 0xf] ^ w[(s + 8) & 0xf] ^ w[(s + 2) & 0xf] ^ w[s];
w[s] = (temp << 1) | (temp >>> 31);
}
if (i < 20) {
temp = (rol(a, 5) + (d ^ (b & (c ^ d))) + e + 0x5a827999 + w[s]) & 0xffffffff;
} else if (i < 40) {
temp = (rol(a, 5) + (b ^ c ^ d) + e + 0x6ed9eba1 + w[s]) & 0xffffffff;
} else if (i < 60) {
temp = (rol(a, 5) + ((b & c) | (b & d) | (c & d)) + e + 0x8f1bbcdc + w[s]) & 0xffffffff;
} else {
temp = (rol(a, 5) + (b ^ c ^ d) + e + 0xca62c1d6 + w[s]) & 0xffffffff;
}
_ref4 = [temp, a, rol(b, 30), c, d], a = _ref4[0], b = _ref4[1], c = _ref4[2], d = _ref4[3], e = _ref4[4];
}
h0 = (h0 + a) & 0xffffffff;
h1 = (h1 + b) & 0xffffffff;
h2 = (h2 + c) & 0xffffffff;
h3 = (h3 + d) & 0xffffffff;
h4 = (h4 + e) & 0xffffffff;
}
return [(h0 >>> 24) & 0xff, (h0 >>> 16) & 0xff, (h0 >>> 8) & 0xff, h0 & 0xff, (h1 >>> 24) & 0xff, (h1 >>> 16) & 0xff, (h1 >>> 8) & 0xff, h1 & 0xff, (h2 >>> 24) & 0xff, (h2 >>> 16) & 0xff, (h2 >>> 8) & 0xff, h2 & 0xff, (h3 >>> 24) & 0xff, (h3 >>> 16) & 0xff, (h3 >>> 8) & 0xff, h3 & 0xff, (h4 >>> 24) & 0xff, (h4 >>> 16) & 0xff, (h4 >>> 8) & 0xff, h4 & 0xff];
};
sha1_string = function(str) {
return bytes_to_hex(sha1(str_to_bytes(str)));
};
hmac_sha1 = function(key_str, message_str) {
var i, ipad, key, message, opad;
key = str_to_bytes(key_str);
message = str_to_bytes(message_str);
if (key.length > 64) {
key = sha1(key);
}
while (key.length < 64) {
key.push(0);
}
opad = (function() {
var _results;
_results = [];
for (i = 0; i < 64; i++) {
_results.push(0x5c ^ key[i]);
}
return _results;
})();
ipad = (function() {
var _results;
_results = [];
for (i = 0; i < 64; i++) {
_results.push(0x36 ^ key[i]);
}
return _results;
})();
return bytes_to_hex(sha1(opad.concat(sha1(ipad.concat(message)))));
};
byte_string = function(b, size) {
var i;
return ((function() {
var _results;
_results = [];
for (i = 0; (0 <= size ? i < size : i > size); (0 <= size ? i += 1 : i -= 1)) {
_results.push(String.fromCharCode(b));
}
return _results;
})()).join("");
};
verify_hmac_sha1 = function() {
var t, test_vectors, _i, _len;
test_vectors = [["Jefe", "what do ya want for nothing?", "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"], [byte_string(0x0b, 20), "Hi There", "b617318655057264e28bc0b6fb378c8ef146be00"], [byte_string(0xaa, 20), byte_string(0xdd, 50), "125d7342b9ac11cd91a39af48aa17b4f63f175d3"], [byte_string(0x0c, 20), "Test With Truncation", "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"], [byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key - Hash Key First", "aa4ae5e15272d00e95705637ce8a3b55ed402112"], [byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"]];
for (_i = 0, _len = test_vectors.length; _i < _len; _i++) {
t = test_vectors[_i];
if (hmac_sha1(t[0], t[1]) !== t[2]) {
return false;
}
}
return true;
};
good_passy = function(str) {
return str.match(/[A-H]/) && str.match(/[a-h]/) && str.match(/[2-9]/) && str.match(/[#$%*+=@?]/);
};
good_passy_length = function(str) {
var i, _ref;
for (i = 16, _ref = str.length; (16 <= _ref ? i <= _ref : i >= _ref); (16 <= _ref ? i += 1 : i -= 1)) {
if (good_passy(str.substr(0, i))) {
return i;
}
}
return str.length;
};
encode_passy = function(secret, text) {
var double_hmac, encode, encoded, hex2passy, len, symtab;
symtab = "ABCDEFGHabcdefgh23456789#$%*+=@?";
hex2passy = function(x) {
return symtab[parseInt(x, 16) % symtab.length];
@@ -48,29 +194,18 @@ passy = function(text, secret) {
return _results;
})()).join("");
};
return [encode(SHA1.hmac(secret, text).substr(0, 24)), SHA1.hmac(secret, text).substr(0, 10)];
double_hmac = hmac_sha1(secret, text);
double_hmac = double_hmac + sha1_string(double_hmac);
encoded = encode(double_hmac);
len = good_passy_length(encoded);
return encoded.substr(0, len);
};
/* This is the source CoffeeScript code:
passy = (text,secret) ->
# our symbol table for passy
symtab = "ABCDEFGHabcdefgh23456789#$%*+=@?"
# convert a hex string to a single passy character
# * modulo and lookup in symtab string
hex2passy = (x) -> symtab[parseInt(x,16) % symtab.length]
# encode a hex string into a passy string
# 1. split a string into two character strings (octets)
# 2. encode each two char string (octet) into a single passy char
# 3. join resulting array of passy chars into a single passy string
encode = (str) ->
(hex2passy(str.substr(i,2)) for i in [0...str.length] by 2).join("")
# return the first 12 characters of the passy string and 10 characters of hmac
[encode(SHA1.hmac(secret,text).substr(0,24)), SHA1.hmac(secret,text).substr(0,10)]
*/
encode_passy_legacy = function(secret, text) {
return hmac_sha1(secret, text).substr(0, 10);
};
if (!(encode_passy("0123", "a") === "Gad6DdC2e3cD6dF937c82h5%" && encode_passy("ABab12!@CDcd34#$", "aB234SLKDJF(*#@jfsdk") === "d+B8#@hh5CB%=Fef" && encode_passy("11111111111111111111", "00000000000000000000") === "Fgh5bE?94A2chdhF")) {
return ["Error!", "Error!"];
}
return [encode_passy(secret, text), encode_passy_legacy(secret, text)];
};
window['passy'] = passy;
+199
View File
@@ -0,0 +1,199 @@
###
sha1.coffee
Implementation of SHA-1 hash and HMAC algorithms in CoffeeScript, by Stephen
Waits.
The MIT License
Copyright (c) 2011 Stephen Waits <steve@waits.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
###
class SHA1
# convert a single character code to its byte representation
char_code_to_bytes = (char) ->
result = []
while char
result.unshift(char & 0xff)
char >>= 8
result
# convert a string into a byte array, including multibytes chars
str_to_bytes = (str) ->
result = []
for char in str
result = result.concat(char_code_to_bytes(char.charCodeAt(0)))
result
# convert a number to an array of 8 bytes representing a 64 bit big-endian integer
num_to_big_endian_64 = (num) ->
[
(num & 0xff00000000000000) >>> 56,
(num & 0x00ff000000000000) >>> 48,
(num & 0x0000ff0000000000) >>> 40,
(num & 0x000000ff00000000) >>> 32,
(num & 0x00000000ff000000) >>> 24,
(num & 0x0000000000ff0000) >>> 16,
(num & 0x000000000000ff00) >>> 8,
(num & 0x00000000000000ff)
]
# convert an array of bytes to an array of int32 (big-endian)
bytes_to_big_endian_32 = (array) ->
((array[i] << 24) | (array[i+1] << 16) | (array[i+2] << 8) | array[i+3]) for i in [0...array.length] by 4
# take an array of bytes and return the hex string
bytes_to_hex = (bytes) ->
hextab = "0123456789abcdef"
(hextab[(x >>> 4) & 0x0f] + hextab[x & 0x0f] for x in bytes).join("")
# compute SHA1 hash
#
# input is an array of bytes (big-endian order)
# returns an array of 20 bytes
sha1 = (byte_array) ->
# helper function (rotate left)
rol = (x,i) -> (x << i) | (x >>> (32-i))
# initialize variables
message = byte_array.slice(0) # copy array, since we will modify it
message_size_in_bits = message.length * 8 # store message size for later use
# initialize hash state variables
[h0, h1, h2, h3, h4] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]
# Preprocess message in preparation for hasing:
# append the bit '1' to the message
message.push(0x80)
# append (0 <= k < 512) bits '0', so that the resulting message length (in bits) is congruent to 448 = -64 (mod 512)
message.push(0) while ((message.length + 8) % 64)
# append length of message (before pre-processing), in bits, as 64-bit big-endian integer
message = message.concat(num_to_big_endian_64(message_size_in_bits))
# Process the message in successive 512-bit chunks:
# break message into 512-bit chunks
for i_chunk in [0...message.length] by 64
# convert bytes into int32
w = bytes_to_big_endian_32(message.slice(i_chunk, i_chunk+64))
# init state with current hash
[a, b, c, d, e] = [h0, h1, h2, h3, h4]
# hash rounds
for i in [0...80]
s = i & 0xf
if (i >= 16)
temp = w[(s + 13) & 0xf] ^ w[(s + 8) & 0xf] ^ w[(s + 2) & 0xf] ^ w[s]
w[s] = (temp << 1) | (temp >>> 31)
if (i < 20)
# rol(a,5) + _________f[i]________ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( d ^ (b & (c ^ d)) ) + e + 0x5a827999 + w[s]) & 0xffffffff
else if (i < 40)
# rol(a,5) + _____f[i]____ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( b ^ c ^ d ) + e + 0x6ed9eba1 + w[s]) & 0xffffffff
else if (i < 60)
# rol(a,5) + ___________f[i]________________ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( (b & c) | (b & d) | (c & d) ) + e + 0x8f1bbcdc + w[s]) & 0xffffffff
else
# rol(a,5) + _____f[i]____ + e + ___k[i]___ + w[s]
temp = (rol(a,5) + ( b ^ c ^ d ) + e + 0xca62c1d6 + w[s]) & 0xffffffff
[a, b, c, d, e] = [temp, a, rol(b,30), c, d]
# Add this chunk's hash to result so far:
h0 = (h0 + a) & 0xffffffff
h1 = (h1 + b) & 0xffffffff
h2 = (h2 + c) & 0xffffffff
h3 = (h3 + d) & 0xffffffff
h4 = (h4 + e) & 0xffffffff
# Return the final hash value (big-endian):
[
(h0 >>> 24) & 0xff, (h0 >>> 16) & 0xff, (h0 >>> 8) & 0xff, h0 & 0xff,
(h1 >>> 24) & 0xff, (h1 >>> 16) & 0xff, (h1 >>> 8) & 0xff, h1 & 0xff,
(h2 >>> 24) & 0xff, (h2 >>> 16) & 0xff, (h2 >>> 8) & 0xff, h2 & 0xff,
(h3 >>> 24) & 0xff, (h3 >>> 16) & 0xff, (h3 >>> 8) & 0xff, h3 & 0xff,
(h4 >>> 24) & 0xff, (h4 >>> 16) & 0xff, (h4 >>> 8) & 0xff, h4 & 0xff
] # note: returning this as a byte array is quite expensive!
# test HMAC-SHA1 with known test vectors, which naturally tests SHA1
verify_hmac_sha1 = ->
# SHA1 test data from RFC
test_vectors = [
[ "Jefe", "what do ya want for nothing?", "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79" ],
[ byte_string(0x0b, 20), "Hi There", "b617318655057264e28bc0b6fb378c8ef146be00" ],
[ byte_string(0xaa, 20), byte_string(0xdd, 50), "125d7342b9ac11cd91a39af48aa17b4f63f175d3" ],
[ byte_string(0x0c, 20), "Test With Truncation", "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04" ],
[ byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key - Hash Key First", "aa4ae5e15272d00e95705637ce8a3b55ed402112" ],
[ byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" ]
]
# run tests
for t in test_vectors
# return false if a test fails
return false if hmac_sha1(t[0], t[1]) != t[2]
# all tests passed
true
# compute SHA1
#
# input is a string
# returns a hex string
sha1_string = (str) ->
# convert hex string to a byte array, hash, and convert back to a hex string
bytes_to_hex(sha1(str_to_bytes(str)))
# create a byte string of length "size" of "byte"s
byte_string = (byte, size) ->
(String.fromCharCode(byte) for i in [0...size]).join("")
# compute HMAC-SHA1
#
# key_str and message_str are both strings
# returns a hex string
hmac_sha1 = (key_str, message_str) ->
# convert key & message to byte arrays
key = str_to_bytes(key_str)
message = str_to_bytes(message_str)
# initialize key
key = sha1(key) if key.length > 64 # keys longer than 64 are truncated to sha1 result
key.push(0) while key.length < 64 # keys shorter than 64 are padded with zeroes
# setup pads
opad = (0x5c ^ key[i] for i in [0...64])
ipad = (0x36 ^ key[i] for i in [0...64])
# calculate HMAC
bytes_to_hex(sha1(opad.concat(sha1(ipad.concat(message)))))
# exports
@hash:sha1_string
@hmac:hmac_sha1
@test:verify_hmac_sha1
+139 -266
View File
@@ -1,301 +1,174 @@
/*
* sha1.js - implementation of SHA-1 hash and HMAC algorithms in javascript, by Stephen Waits
*
* The MIT License
*
* Copyright (c) 2010 Stephen Waits <steve@waits.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*jslint onevar: true, undef: true, nomen: true, regexp: true, newcap: true, immed: true */
sha1.coffee
var SHA1 = (function() // SHA1 "namespace"
{
// table for doing number to hex string conversion
var hextab = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];
Implementation of SHA-1 hash and HMAC algorithms in CoffeeScript, by Stephen
Waits.
// convert one character to an array of bytes
function char_code_to_bytes(code)
{
var result = [];
do
{
result.unshift(code & 0xff);
code >>= 8;
} while (code);
return result;
}
The MIT License
// convert a string to an array of bytes
// note: multi-byte characters are included
function str_to_bytes(str)
{
var result = [], i, len = str.length;
for (i=0; i<len; i++)
{
result = result.concat( char_code_to_bytes(str.charCodeAt(i)) );
Copyright (c) 2011 Stephen Waits <steve@waits.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/var SHA1;
SHA1 = (function() {
var byte_string, bytes_to_big_endian_32, bytes_to_hex, char_code_to_bytes, hmac_sha1, num_to_big_endian_64, sha1, sha1_string, str_to_bytes, verify_hmac_sha1;
function SHA1() {}
char_code_to_bytes = function(char) {
var result;
result = [];
while (char) {
result.unshift(char & 0xff);
char >>= 8;
}
return result;
}
// take a number and return an array of 8 bytes representing a big-endian int64
function num_to_big_endian_64(num)
{
return [
(num & 0xff00000000000000) >>> 56,
(num & 0x00ff000000000000) >>> 48,
(num & 0x0000ff0000000000) >>> 40,
(num & 0x000000ff00000000) >>> 32,
(num & 0x00000000ff000000) >>> 24,
(num & 0x0000000000ff0000) >>> 16,
(num & 0x000000000000ff00) >>> 8,
(num & 0x00000000000000ff)
];
}
// convert an array of bytes to an array of int32 (big-endian)
function bytes_to_big_endian_32(array)
{
var result = [], i, len = array.length;
for (i=0; i<len; i+=4)
{
result.push((array[i] << 24) | (array[i+1] << 16) | (array[i+2] << 8) | array[i+3]);
};
str_to_bytes = function(str) {
var char, result, _i, _len;
result = [];
for (_i = 0, _len = str.length; _i < _len; _i++) {
char = str[_i];
result = result.concat(char_code_to_bytes(char.charCodeAt(0)));
}
return result;
};
num_to_big_endian_64 = function(num) {
return [(num & 0xff00000000000000) >>> 56, (num & 0x00ff000000000000) >>> 48, (num & 0x0000ff0000000000) >>> 40, (num & 0x000000ff00000000) >>> 32, (num & 0x00000000ff000000) >>> 24, (num & 0x0000000000ff0000) >>> 16, (num & 0x000000000000ff00) >>> 8, num & 0x00000000000000ff];
};
bytes_to_big_endian_32 = function(array) {
var i, _ref, _results;
_results = [];
for (i = 0, _ref = array.length; (0 <= _ref ? i < _ref : i > _ref); i += 4) {
_results.push((array[i] << 24) | (array[i + 1] << 16) | (array[i + 2] << 8) | array[i + 3]);
}
// take an array of bytes and return the hex string
function bytes_to_hex(x)
{
var
result = "",
len = x.length,
i;
for (i=0; i<len; i++)
{
result += (hextab[x[i] >>> 4]) + (hextab[x[i] & 0xf]);
return _results;
};
bytes_to_hex = function(bytes) {
var hextab, x;
hextab = "0123456789abcdef";
return ((function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = bytes.length; _i < _len; _i++) {
x = bytes[_i];
_results.push(hextab[(x >>> 4) & 0x0f] + hextab[x & 0x0f]);
}
return result;
}
// compute SHA1 hash
//
// input is an array of bytes (big-endian order)
// returns an array of 20 bytes
function sha1(byte_array)
{
var
// copy array
message = byte_array.slice(),
// store message size for later use
message_size_in_bits = message.length * 8,
// Initialize variables:
h0 = 0x67452301,
h1 = 0xefcdab89,
h2 = 0x98badcfe,
h3 = 0x10325476,
h4 = 0xc3d2e1f0,
// variables
a, b, c, d, e, s, temp, w, i, i_chunk;
// Pre-processing:
// append the bit '1' to the message
return _results;
})()).join("");
};
sha1 = function(byte_array) {
var a, b, c, d, e, h0, h1, h2, h3, h4, i, i_chunk, message, message_size_in_bits, rol, s, temp, w, _ref, _ref2, _ref3, _ref4;
rol = function(x, i) {
return (x << i) | (x >>> (32 - i));
};
message = byte_array.slice(0);
message_size_in_bits = message.length * 8;
_ref = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], h0 = _ref[0], h1 = _ref[1], h2 = _ref[2], h3 = _ref[3], h4 = _ref[4];
message.push(0x80);
// append (0 <= k < 512) bits '0', so that the resulting message length (in bits) is congruent to 448 = -64 (mod 512)
while ((message.length + 8) % 64)
{
while ((message.length + 8) % 64) {
message.push(0);
}
// append length of message (before pre-processing), in bits, as 64-bit big-endian integer
message = message.concat(num_to_big_endian_64(message_size_in_bits));
// Process the message in successive 512-bit chunks:
// break message into 512-bit chunks
for (i_chunk=0; i_chunk<(message.length/64); i_chunk++)
{
// break chunk into sixteen 32-bit big-endian words w[i], 0 <= i <= 15
w = bytes_to_big_endian_32(message.slice(i_chunk*64,(i_chunk*64)+64));
// Initialize hash value for this chunk:
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
// Main loop:
for (i=0; i<80; i++)
{
for (i_chunk = 0, _ref2 = message.length; (0 <= _ref2 ? i_chunk < _ref2 : i_chunk > _ref2); i_chunk += 64) {
w = bytes_to_big_endian_32(message.slice(i_chunk, i_chunk + 64));
_ref3 = [h0, h1, h2, h3, h4], a = _ref3[0], b = _ref3[1], c = _ref3[2], d = _ref3[3], e = _ref3[4];
for (i = 0; i < 80; i++) {
s = i & 0xf;
if (i >= 16)
{
if (i >= 16) {
temp = w[(s + 13) & 0xf] ^ w[(s + 8) & 0xf] ^ w[(s + 2) & 0xf] ^ w[s];
w[s] = (temp << 1) | (temp >>> 31); // rol(temp,1)
w[s] = (temp << 1) | (temp >>> 31);
}
if (i < 20)
{
// _______rol(a,5)_________ + _________f[i]________ + e + ___k[i]___ + w[s]
temp = (((a << 5) | (a >>> 27)) + ( d ^ (b & (c ^ d)) ) + e + 0x5a827999 + w[s]) & 0xffffffff;
if (i < 20) {
temp = (rol(a, 5) + (d ^ (b & (c ^ d))) + e + 0x5a827999 + w[s]) & 0xffffffff;
} else if (i < 40) {
temp = (rol(a, 5) + (b ^ c ^ d) + e + 0x6ed9eba1 + w[s]) & 0xffffffff;
} else if (i < 60) {
temp = (rol(a, 5) + ((b & c) | (b & d) | (c & d)) + e + 0x8f1bbcdc + w[s]) & 0xffffffff;
} else {
temp = (rol(a, 5) + (b ^ c ^ d) + e + 0xca62c1d6 + w[s]) & 0xffffffff;
}
else if (i < 40)
{
// _______rol(a,5)_________ + _____f[i]____ + e + ___k[i]___ + w[s]
temp = (((a << 5) | (a >>> 27)) + ( b ^ c ^ d ) + e + 0x6ed9eba1 + w[s]) & 0xffffffff;
_ref4 = [temp, a, rol(b, 30), c, d], a = _ref4[0], b = _ref4[1], c = _ref4[2], d = _ref4[3], e = _ref4[4];
}
else if (i < 60)
{
// _______rol(a,5)_________ + ___________f[i]________________ + e + ___k[i]___ + w[s]
temp = (((a << 5) | (a >>> 27)) + ( (b & c) | (b & d) | (c & d) ) + e + 0x8f1bbcdc + w[s]) & 0xffffffff;
}
else
{
// ________rol(a,5)_________ + _____f[i]____ + e + ___k[i]___ + w[s]
temp = (((a << 5) | (a >>> 27)) + ( b ^ c ^ d ) + e + 0xca62c1d6 + w[s]) & 0xffffffff;
}
e = d;
d = c;
c = (b << 30) | (b >>> 2); // c = rol(b,30)
b = a;
a = temp;
}
// Add this chunk's hash to result so far:
h0 = (h0 + a) & 0xffffffff;
h1 = (h1 + b) & 0xffffffff;
h2 = (h2 + c) & 0xffffffff;
h3 = (h3 + d) & 0xffffffff;
h4 = (h4 + e) & 0xffffffff;
}
// Produce the final hash value (big-endian):
return [
(h0 >>> 24) & 0xff, (h0 >>> 16) & 0xff, (h0 >>> 8) & 0xff, h0 & 0xff,
(h1 >>> 24) & 0xff, (h1 >>> 16) & 0xff, (h1 >>> 8) & 0xff, h1 & 0xff,
(h2 >>> 24) & 0xff, (h2 >>> 16) & 0xff, (h2 >>> 8) & 0xff, h2 & 0xff,
(h3 >>> 24) & 0xff, (h3 >>> 16) & 0xff, (h3 >>> 8) & 0xff, h3 & 0xff,
(h4 >>> 24) & 0xff, (h4 >>> 16) & 0xff, (h4 >>> 8) & 0xff, h4 & 0xff
]; // note: returning this as a byte array is quite expensive!
return [(h0 >>> 24) & 0xff, (h0 >>> 16) & 0xff, (h0 >>> 8) & 0xff, h0 & 0xff, (h1 >>> 24) & 0xff, (h1 >>> 16) & 0xff, (h1 >>> 8) & 0xff, h1 & 0xff, (h2 >>> 24) & 0xff, (h2 >>> 16) & 0xff, (h2 >>> 8) & 0xff, h2 & 0xff, (h3 >>> 24) & 0xff, (h3 >>> 16) & 0xff, (h3 >>> 8) & 0xff, h3 & 0xff, (h4 >>> 24) & 0xff, (h4 >>> 16) & 0xff, (h4 >>> 8) & 0xff, h4 & 0xff];
};
verify_hmac_sha1 = function() {
var t, test_vectors, _i, _len;
test_vectors = [["Jefe", "what do ya want for nothing?", "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"], [byte_string(0x0b, 20), "Hi There", "b617318655057264e28bc0b6fb378c8ef146be00"], [byte_string(0xaa, 20), byte_string(0xdd, 50), "125d7342b9ac11cd91a39af48aa17b4f63f175d3"], [byte_string(0x0c, 20), "Test With Truncation", "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"], [byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key - Hash Key First", "aa4ae5e15272d00e95705637ce8a3b55ed402112"], [byte_string(0xaa, 80), "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"]];
for (_i = 0, _len = test_vectors.length; _i < _len; _i++) {
t = test_vectors[_i];
if (hmac_sha1(t[0], t[1]) !== t[2]) {
return false;
}
// compute SHA1
//
// input is a string
// returns a hex string
function sha1_string(str)
{
// get text into byte array, hash, convert to hex string
}
return true;
};
sha1_string = function(str) {
return bytes_to_hex(sha1(str_to_bytes(str)));
};
byte_string = function(byte, size) {
var i;
return ((function() {
var _results;
_results = [];
for (i = 0; (0 <= size ? i < size : i > size); (0 <= size ? i += 1 : i -= 1)) {
_results.push(String.fromCharCode(byte));
}
// compute HMAC-SHA1
//
// key_str and message_str are both strings
// returns a hex string
function hmac_sha1(key_str, message_str)
{
var
// convert key & message to byte arrays
key = str_to_bytes(key_str),
message = str_to_bytes(message_str),
// our pads
opad = new Array(64),
ipad = new Array(64),
// misc
i;
// setup key
if (key.length > 64)
{
key = sha1(key); // keys longer than blocksize are shortened
return _results;
})()).join("");
};
hmac_sha1 = function(key_str, message_str) {
var i, ipad, key, message, opad;
key = str_to_bytes(key_str);
message = str_to_bytes(message_str);
if (key.length > 64) {
key = sha1(key);
}
while (key.length < 64)
{
while (key.length < 64) {
key.push(0);
}
// setup pads
for (i=0; i<64; i++)
{
opad[i] = 0x5c ^ key[i];
ipad[i] = 0x36 ^ key[i];
opad = (function() {
var _results;
_results = [];
for (i = 0; i < 64; i++) {
_results.push(0x5c ^ key[i]);
}
// calculate HMAC
return _results;
})();
ipad = (function() {
var _results;
_results = [];
for (i = 0; i < 64; i++) {
_results.push(0x36 ^ key[i]);
}
return _results;
})();
return bytes_to_hex(sha1(opad.concat(sha1(ipad.concat(message)))));
}
//
// verification code
//
// create a byte string of size number of x's
function byte_string(x,size)
{
var a = "", s = String.fromCharCode(x);
for (var i=0; i<size; i++)
{
a += s;
};
return a;
}
// test HMAC-SHA1 with known test vectors
function verify()
{
// testing HMAC-SHA1 also naturally tests SHA1
var tests = [
[ 'Jefe','what do ya want for nothing?', 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79' ],
[ byte_string(0xb,20),'Hi There','b617318655057264e28bc0b6fb378c8ef146be00' ],
[ byte_string(0xaa,20),byte_string(0xdd,50), '125d7342b9ac11cd91a39af48aa17b4f63f175d3' ],
[ byte_string(0xc,20),'Test With Truncation','4c1a03424b55e07fe7f27be1d58bb9324a9a5a04' ],
[ byte_string(0xaa,80),'Test Using Larger Than Block-Size Key - Hash Key First','aa4ae5e15272d00e95705637ce8a3b55ed402112' ],
[ byte_string(0xaa,80),'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data','e8e99d0f45237d786d6bbaa7965c7808bbff1a91' ]
];
for (var i = 0; i < tests.length; i++) {
if (hmac_sha1(tests[i][0],tests[i][1]) != tests[i][2]) { return false; }
};
return true;
}
//
// exported symbols
//
return {
hash:sha1_string,
hmac:hmac_sha1,
test:verify
};
}()); // SHA1 "namespace"
SHA1.hash = sha1_string;
SHA1.hmac = hmac_sha1;
SHA1.test = verify_hmac_sha1;
return SHA1;
})();