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:
1 parent
dcb476ba1c
commit
65c7f720ea
6 files changed
+812
-335
No files matched your search
+8
-7
@@ -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
@@ -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
@@ -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>
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
})();
|
||||
Reference in new issue
Block a user