From 33acf62431a91405fec29f8a0318b528f5e411a9 Mon Sep 17 00:00:00 2001 From: Yi-Cyuan Chen Date: Wed, 24 Jan 2024 11:31:08 +0800 Subject: [PATCH] ### Added - TypeScript interfaces. #6, #9 - HMAC feature. - support for web worker. #14 ### Fixed - deprecated `new Buffer`, replace with `Buffer.from`. #10 - dependencies and security issues. - refactor: simplify formatMessage internal logic. - Generates incorrect hash in some cases. ### Changed - remove `eval` and use `require` directly. #8 - throw error by Error oject. - throw error if update after finalize - use unsigned right shift. --- CHANGELOG.md | 18 ++++ LICENSE.txt | 2 +- README.md | 28 ++++- build/sha1.min.js | 6 +- index.d.ts | 148 +++++++++++++++++++++++++ package-lock.json | 27 +++-- package.json | 7 +- src/sha1.js | 251 +++++++++++++++++++++++++++++++++---------- tests/hmac-test.js | 202 ++++++++++++++++++++++++++++++++++ tests/node-test.js | 155 ++++++++++++++++++++++---- tests/requirejs.html | 24 +++++ tests/test.js | 94 ++++++++++------ tests/worker-test.js | 24 +++++ tests/worker.html | 25 +++++ tests/worker.js | 12 +++ 15 files changed, 901 insertions(+), 122 deletions(-) create mode 100644 index.d.ts create mode 100644 tests/hmac-test.js create mode 100644 tests/requirejs.html create mode 100644 tests/worker-test.js create mode 100644 tests/worker.html create mode 100644 tests/worker.js diff --git a/CHANGELOG.md b/CHANGELOG.md index cf84d45..26f1e89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Change Log +## v0.7.0 / 2024-01-24 +### Added +- TypeScript interfaces. #6, #9 +- HMAC feature. +- support for web worker. #14 + +### Fixed +- deprecated `new Buffer`, replace with `Buffer.from`. #10 +- dependencies and security issues. +- refactor: simplify formatMessage internal logic. +- Generates incorrect hash in some cases. + +### Changed +- remove `eval` and use `require` directly. #8 +- throw error by Error oject. +- throw error if update after finalize +- use unsigned right shift. + ## v0.6.0 / 2017-12-21 ### Fixed - incorrect result when first bit is 1 of bytes. diff --git a/LICENSE.txt b/LICENSE.txt index 74ac20d..462bc00 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright 2014-2017 Chen, Yi-Cyuan +Copyright 2014-2024 Chen, Yi-Cyuan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 836e8b3..1ae2552 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ A simple SHA1 hash function for JavaScript supports UTF-8 encoding. ## Demo [SHA1 Online](http://emn178.github.io/online-tools/sha1.html) +[SHA1 File Checksum Online](https://emn178.github.io/online-tools/sha1_checksum.html) ## Download [Compress](https://raw.github.com/emn178/js-sha1/master/build/sha1.min.js) @@ -20,6 +21,9 @@ For node.js, you can use this command to install: npm install js-sha1 +## Notice +NIST formally deprecated use of SHA-1 in 2011 and disallowed its use for digital signatures in 2013, and declared that it should be phased out by 2030. However, SHA-1 is still secure for HMAC. [wiki](https://en.wikipedia.org/wiki/SHA-1) + ## Usage You could use like this: ```JavaScript @@ -27,11 +31,28 @@ sha1('Message to hash'); var hash = sha1.create(); hash.update('Message to hash'); hash.hex(); + +// HMAC +sha1.hmac('key', 'Message to hash'); + +var hash = sha1.hmac.create('key'); +hash.update('Message to hash'); +hash.hex(); ``` + +### Node.js If you use node.js, you should require the module first: ```JavaScript -sha1 = require('js-sha1'); +var sha1 = require('js-sha1'); ``` + +### TypeScript +If you use TypeScript, you can import like this: +```TypeScript +import { sha1 } from 'js-sha1'; +``` + +## RequireJS It supports AMD: ```JavaScript require(['your/path/sha1.js'], function(sha1) { @@ -58,6 +79,11 @@ sha1.hex(''); // da39a3ee5e6b4b0d3255bfef95601890afd80709 sha1.array(''); // [218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9] sha1.digest(''); // [218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9] sha1.arrayBuffer(''); // ArrayBuffer + +// HMAC +sha1.hmac.hex('key', 'Message to hash'); +sha1.hmac.array('key', 'Message to hash'); +// ... ``` ## License diff --git a/build/sha1.min.js b/build/sha1.min.js index e20453d..85ac42d 100644 --- a/build/sha1.min.js +++ b/build/sha1.min.js @@ -1,9 +1,9 @@ /* * [js-sha1]{@link https://github.com/emn178/js-sha1} * - * @version 0.6.0 + * @version 0.7.0 * @author Chen, Yi-Cyuan [emn178@gmail.com] - * @copyright Chen, Yi-Cyuan 2014-2017 + * @copyright Chen, Yi-Cyuan 2014-2024 * @license MIT */ -!function(){"use strict";function t(t){t?(f[0]=f[16]=f[1]=f[2]=f[3]=f[4]=f[5]=f[6]=f[7]=f[8]=f[9]=f[10]=f[11]=f[12]=f[13]=f[14]=f[15]=0,this.blocks=f):this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],this.h0=1732584193,this.h1=4023233417,this.h2=2562383102,this.h3=271733878,this.h4=3285377520,this.block=this.start=this.bytes=this.hBytes=0,this.finalized=this.hashed=!1,this.first=!0}var h="object"==typeof window?window:{},s=!h.JS_SHA1_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;s&&(h=global);var i=!h.JS_SHA1_NO_COMMON_JS&&"object"==typeof module&&module.exports,e="function"==typeof define&&define.amd,r="0123456789abcdef".split(""),o=[-2147483648,8388608,32768,128],n=[24,16,8,0],a=["hex","array","digest","arrayBuffer"],f=[],u=function(h){return function(s){return new t(!0).update(s)[h]()}},c=function(){var h=u("hex");s&&(h=p(h)),h.create=function(){return new t},h.update=function(t){return h.create().update(t)};for(var i=0;i>2]|=t[r]<>2]|=i<>2]|=(192|i>>6)<>2]|=(128|63&i)<=57344?(a[e>>2]|=(224|i>>12)<>2]|=(128|i>>6&63)<>2]|=(128|63&i)<>2]|=(240|i>>18)<>2]|=(128|i>>12&63)<>2]|=(128|i>>6&63)<>2]|=(128|63&i)<=64?(this.block=a[16],this.start=e-64,this.hash(),this.hashed=!0):this.start=e}return this.bytes>4294967295&&(this.hBytes+=this.bytes/4294967296<<0,this.bytes=this.bytes%4294967296),this}},t.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,h=this.lastByteIndex;t[16]=this.block,t[h>>2]|=o[3&h],this.block=t[16],h>=56&&(this.hashed||this.hash(),t[0]=this.block,t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[14]=this.hBytes<<3|this.bytes>>>29,t[15]=this.bytes<<3,this.hash()}},t.prototype.hash=function(){var t,h,s=this.h0,i=this.h1,e=this.h2,r=this.h3,o=this.h4,n=this.blocks;for(t=16;t<80;++t)h=n[t-3]^n[t-8]^n[t-14]^n[t-16],n[t]=h<<1|h>>>31;for(t=0;t<20;t+=5)s=(h=(i=(h=(e=(h=(r=(h=(o=(h=s<<5|s>>>27)+(i&e|~i&r)+o+1518500249+n[t]<<0)<<5|o>>>27)+(s&(i=i<<30|i>>>2)|~s&e)+r+1518500249+n[t+1]<<0)<<5|r>>>27)+(o&(s=s<<30|s>>>2)|~o&i)+e+1518500249+n[t+2]<<0)<<5|e>>>27)+(r&(o=o<<30|o>>>2)|~r&s)+i+1518500249+n[t+3]<<0)<<5|i>>>27)+(e&(r=r<<30|r>>>2)|~e&o)+s+1518500249+n[t+4]<<0,e=e<<30|e>>>2;for(;t<40;t+=5)s=(h=(i=(h=(e=(h=(r=(h=(o=(h=s<<5|s>>>27)+(i^e^r)+o+1859775393+n[t]<<0)<<5|o>>>27)+(s^(i=i<<30|i>>>2)^e)+r+1859775393+n[t+1]<<0)<<5|r>>>27)+(o^(s=s<<30|s>>>2)^i)+e+1859775393+n[t+2]<<0)<<5|e>>>27)+(r^(o=o<<30|o>>>2)^s)+i+1859775393+n[t+3]<<0)<<5|i>>>27)+(e^(r=r<<30|r>>>2)^o)+s+1859775393+n[t+4]<<0,e=e<<30|e>>>2;for(;t<60;t+=5)s=(h=(i=(h=(e=(h=(r=(h=(o=(h=s<<5|s>>>27)+(i&e|i&r|e&r)+o-1894007588+n[t]<<0)<<5|o>>>27)+(s&(i=i<<30|i>>>2)|s&e|i&e)+r-1894007588+n[t+1]<<0)<<5|r>>>27)+(o&(s=s<<30|s>>>2)|o&i|s&i)+e-1894007588+n[t+2]<<0)<<5|e>>>27)+(r&(o=o<<30|o>>>2)|r&s|o&s)+i-1894007588+n[t+3]<<0)<<5|i>>>27)+(e&(r=r<<30|r>>>2)|e&o|r&o)+s-1894007588+n[t+4]<<0,e=e<<30|e>>>2;for(;t<80;t+=5)s=(h=(i=(h=(e=(h=(r=(h=(o=(h=s<<5|s>>>27)+(i^e^r)+o-899497514+n[t]<<0)<<5|o>>>27)+(s^(i=i<<30|i>>>2)^e)+r-899497514+n[t+1]<<0)<<5|r>>>27)+(o^(s=s<<30|s>>>2)^i)+e-899497514+n[t+2]<<0)<<5|e>>>27)+(r^(o=o<<30|o>>>2)^s)+i-899497514+n[t+3]<<0)<<5|i>>>27)+(e^(r=r<<30|r>>>2)^o)+s-899497514+n[t+4]<<0,e=e<<30|e>>>2;this.h0=this.h0+s<<0,this.h1=this.h1+i<<0,this.h2=this.h2+e<<0,this.h3=this.h3+r<<0,this.h4=this.h4+o<<0},t.prototype.hex=function(){this.finalize();var t=this.h0,h=this.h1,s=this.h2,i=this.h3,e=this.h4;return r[t>>28&15]+r[t>>24&15]+r[t>>20&15]+r[t>>16&15]+r[t>>12&15]+r[t>>8&15]+r[t>>4&15]+r[15&t]+r[h>>28&15]+r[h>>24&15]+r[h>>20&15]+r[h>>16&15]+r[h>>12&15]+r[h>>8&15]+r[h>>4&15]+r[15&h]+r[s>>28&15]+r[s>>24&15]+r[s>>20&15]+r[s>>16&15]+r[s>>12&15]+r[s>>8&15]+r[s>>4&15]+r[15&s]+r[i>>28&15]+r[i>>24&15]+r[i>>20&15]+r[i>>16&15]+r[i>>12&15]+r[i>>8&15]+r[i>>4&15]+r[15&i]+r[e>>28&15]+r[e>>24&15]+r[e>>20&15]+r[e>>16&15]+r[e>>12&15]+r[e>>8&15]+r[e>>4&15]+r[15&e]},t.prototype.toString=t.prototype.hex,t.prototype.digest=function(){this.finalize();var t=this.h0,h=this.h1,s=this.h2,i=this.h3,e=this.h4;return[t>>24&255,t>>16&255,t>>8&255,255&t,h>>24&255,h>>16&255,h>>8&255,255&h,s>>24&255,s>>16&255,s>>8&255,255&s,i>>24&255,i>>16&255,i>>8&255,255&i,e>>24&255,e>>16&255,e>>8&255,255&e]},t.prototype.array=t.prototype.digest,t.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(20),h=new DataView(t);return h.setUint32(0,this.h0),h.setUint32(4,this.h1),h.setUint32(8,this.h2),h.setUint32(12,this.h3),h.setUint32(16,this.h4),t};var y=c();i?module.exports=y:(h.sha1=y,e&&define(function(){return y}))}(); \ No newline at end of file +!function(){"use strict";function t(t){t?(l[0]=l[16]=l[1]=l[2]=l[3]=l[4]=l[5]=l[6]=l[7]=l[8]=l[9]=l[10]=l[11]=l[12]=l[13]=l[14]=l[15]=0,this.blocks=l):this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],this.h0=1732584193,this.h1=4023233417,this.h2=2562383102,this.h3=271733878,this.h4=3285377520,this.block=this.start=this.bytes=this.hBytes=0,this.finalized=this.hashed=!1,this.first=!0}function r(r,e){var i,h=v(r);if(r=h[0],h[1]){var s,n=[],o=r.length,a=0;for(i=0;i>>6,n[a++]=128|63&s):s<55296||s>=57344?(n[a++]=224|s>>>12,n[a++]=128|s>>>6&63,n[a++]=128|63&s):(s=65536+((1023&s)<<10|1023&r.charCodeAt(++i)),n[a++]=240|s>>>18,n[a++]=128|s>>>12&63,n[a++]=128|s>>>6&63,n[a++]=128|63&s);r=n}r.length>64&&(r=new t(!0).update(r).array());var f=[],u=[];for(i=0;i<64;++i){var c=r[i]||0;f[i]=92^c,u[i]=54^c}t.call(this,e),this.update(u),this.oKeyPad=f,this.inner=!0,this.sharedMemory=e}var e="input is invalid type",i="object"==typeof window,h=i?window:{};h.JS_SHA1_NO_WINDOW&&(i=!1);var s=!i&&"object"==typeof self,n=!h.JS_SHA1_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;n?h=global:s&&(h=self);var o=!h.JS_SHA1_NO_COMMON_JS&&"object"==typeof module&&module.exports,a="function"==typeof define&&define.amd,f=!h.JS_SHA1_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,u="0123456789abcdef".split(""),c=[-2147483648,8388608,32768,128],y=[24,16,8,0],p=["hex","array","digest","arrayBuffer"],l=[],d=Array.isArray;!h.JS_SHA1_NO_NODE_JS&&d||(d=function(t){return"[object Array]"===Object.prototype.toString.call(t)});var b=ArrayBuffer.isView;!f||!h.JS_SHA1_NO_ARRAY_BUFFER_IS_VIEW&&b||(b=function(t){return"object"==typeof t&&t.buffer&&t.buffer.constructor===ArrayBuffer});var v=function(t){var r=typeof t;if("string"===r)return[t,!0];if("object"!==r||null===t)throw new Error(e);if(f&&t.constructor===ArrayBuffer)return[new Uint8Array(t),!1];if(!d(t)&&!b(t))throw new Error(e);return[t,!1]},_=function(r){return function(e){return new t(!0).update(e)[r]()}},A=function(t){var r,i=require("crypto"),s=require("buffer").Buffer;r=s.from&&!h.JS_SHA1_NO_BUFFER_FROM?s.from:function(t){return new s(t)};return function(h){if("string"==typeof h)return i.createHash("sha1").update(h,"utf8").digest("hex");if(null===h||void 0===h)throw new Error(e);return h.constructor===ArrayBuffer&&(h=new Uint8Array(h)),d(h)||b(h)||h.constructor===s?i.createHash("sha1").update(r(h)).digest("hex"):t(h)}},w=function(t){return function(e,i){return new r(e,!0).update(i)[t]()}};t.prototype.update=function(t){if(this.finalized)throw new Error("finalize already called");var r=v(t);t=r[0];for(var e,i,h=r[1],s=0,n=t.length||0,o=this.blocks;s>>2]|=e<>>2]|=(192|e>>>6)<>>2]|=(128|63&e)<=57344?(o[i>>>2]|=(224|e>>>12)<>>2]|=(128|e>>>6&63)<>>2]|=(128|63&e)<>>2]|=(240|e>>>18)<>>2]|=(128|e>>>12&63)<>>2]|=(128|e>>>6&63)<>>2]|=(128|63&e)<>>2]|=t[s]<=64?(this.block=o[16],this.start=i-64,this.hash(),this.hashed=!0):this.start=i}return this.bytes>4294967295&&(this.hBytes+=this.bytes/4294967296<<0,this.bytes=this.bytes%4294967296),this},t.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,r=this.lastByteIndex;t[16]=this.block,t[r>>>2]|=c[3&r],this.block=t[16],r>=56&&(this.hashed||this.hash(),t[0]=this.block,t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[14]=this.hBytes<<3|this.bytes>>>29,t[15]=this.bytes<<3,this.hash()}},t.prototype.hash=function(){var t,r,e=this.h0,i=this.h1,h=this.h2,s=this.h3,n=this.h4,o=this.blocks;for(t=16;t<80;++t)r=o[t-3]^o[t-8]^o[t-14]^o[t-16],o[t]=r<<1|r>>>31;for(t=0;t<20;t+=5)e=(r=(i=(r=(h=(r=(s=(r=(n=(r=e<<5|e>>>27)+(i&h|~i&s)+n+1518500249+o[t]<<0)<<5|n>>>27)+(e&(i=i<<30|i>>>2)|~e&h)+s+1518500249+o[t+1]<<0)<<5|s>>>27)+(n&(e=e<<30|e>>>2)|~n&i)+h+1518500249+o[t+2]<<0)<<5|h>>>27)+(s&(n=n<<30|n>>>2)|~s&e)+i+1518500249+o[t+3]<<0)<<5|i>>>27)+(h&(s=s<<30|s>>>2)|~h&n)+e+1518500249+o[t+4]<<0,h=h<<30|h>>>2;for(;t<40;t+=5)e=(r=(i=(r=(h=(r=(s=(r=(n=(r=e<<5|e>>>27)+(i^h^s)+n+1859775393+o[t]<<0)<<5|n>>>27)+(e^(i=i<<30|i>>>2)^h)+s+1859775393+o[t+1]<<0)<<5|s>>>27)+(n^(e=e<<30|e>>>2)^i)+h+1859775393+o[t+2]<<0)<<5|h>>>27)+(s^(n=n<<30|n>>>2)^e)+i+1859775393+o[t+3]<<0)<<5|i>>>27)+(h^(s=s<<30|s>>>2)^n)+e+1859775393+o[t+4]<<0,h=h<<30|h>>>2;for(;t<60;t+=5)e=(r=(i=(r=(h=(r=(s=(r=(n=(r=e<<5|e>>>27)+(i&h|i&s|h&s)+n-1894007588+o[t]<<0)<<5|n>>>27)+(e&(i=i<<30|i>>>2)|e&h|i&h)+s-1894007588+o[t+1]<<0)<<5|s>>>27)+(n&(e=e<<30|e>>>2)|n&i|e&i)+h-1894007588+o[t+2]<<0)<<5|h>>>27)+(s&(n=n<<30|n>>>2)|s&e|n&e)+i-1894007588+o[t+3]<<0)<<5|i>>>27)+(h&(s=s<<30|s>>>2)|h&n|s&n)+e-1894007588+o[t+4]<<0,h=h<<30|h>>>2;for(;t<80;t+=5)e=(r=(i=(r=(h=(r=(s=(r=(n=(r=e<<5|e>>>27)+(i^h^s)+n-899497514+o[t]<<0)<<5|n>>>27)+(e^(i=i<<30|i>>>2)^h)+s-899497514+o[t+1]<<0)<<5|s>>>27)+(n^(e=e<<30|e>>>2)^i)+h-899497514+o[t+2]<<0)<<5|h>>>27)+(s^(n=n<<30|n>>>2)^e)+i-899497514+o[t+3]<<0)<<5|i>>>27)+(h^(s=s<<30|s>>>2)^n)+e-899497514+o[t+4]<<0,h=h<<30|h>>>2;this.h0=this.h0+e<<0,this.h1=this.h1+i<<0,this.h2=this.h2+h<<0,this.h3=this.h3+s<<0,this.h4=this.h4+n<<0},t.prototype.hex=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,i=this.h3,h=this.h4;return u[t>>>28&15]+u[t>>>24&15]+u[t>>>20&15]+u[t>>>16&15]+u[t>>>12&15]+u[t>>>8&15]+u[t>>>4&15]+u[15&t]+u[r>>>28&15]+u[r>>>24&15]+u[r>>>20&15]+u[r>>>16&15]+u[r>>>12&15]+u[r>>>8&15]+u[r>>>4&15]+u[15&r]+u[e>>>28&15]+u[e>>>24&15]+u[e>>>20&15]+u[e>>>16&15]+u[e>>>12&15]+u[e>>>8&15]+u[e>>>4&15]+u[15&e]+u[i>>>28&15]+u[i>>>24&15]+u[i>>>20&15]+u[i>>>16&15]+u[i>>>12&15]+u[i>>>8&15]+u[i>>>4&15]+u[15&i]+u[h>>>28&15]+u[h>>>24&15]+u[h>>>20&15]+u[h>>>16&15]+u[h>>>12&15]+u[h>>>8&15]+u[h>>>4&15]+u[15&h]},t.prototype.toString=t.prototype.hex,t.prototype.digest=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,i=this.h3,h=this.h4;return[t>>>24&255,t>>>16&255,t>>>8&255,255&t,r>>>24&255,r>>>16&255,r>>>8&255,255&r,e>>>24&255,e>>>16&255,e>>>8&255,255&e,i>>>24&255,i>>>16&255,i>>>8&255,255&i,h>>>24&255,h>>>16&255,h>>>8&255,255&h]},t.prototype.array=t.prototype.digest,t.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(20),r=new DataView(t);return r.setUint32(0,this.h0),r.setUint32(4,this.h1),r.setUint32(8,this.h2),r.setUint32(12,this.h3),r.setUint32(16,this.h4),t},(r.prototype=new t).finalize=function(){if(t.prototype.finalize.call(this),this.inner){this.inner=!1;var r=this.array();t.call(this,this.sharedMemory),this.update(this.oKeyPad),this.update(r),t.prototype.finalize.call(this)}};var S=function(){var r=_("hex");n&&(r=A(r)),r.create=function(){return new t},r.update=function(t){return r.create().update(t)};for(var e=0;e> 2] |= message[index] << SHIFT[i++ & 3]; - } - } else { + if(isString) { for (i = this.start; index < length && i < 64; ++index) { code = message.charCodeAt(index); if (code < 0x80) { - blocks[i >> 2] |= code << SHIFT[i++ & 3]; + blocks[i >>> 2] |= code << SHIFT[i++ & 3]; } else if (code < 0x800) { - blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0xc0 | (code >>> 6)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; } else if (code < 0xd800 || code >= 0xe000) { - blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0xe0 | (code >>> 12)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0x80 | ((code >>> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; } else { code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); - blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0xf0 | (code >>> 18)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0x80 | ((code >>> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0x80 | ((code >>> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; } } + } else { + for (i = this.start; index < length && i < 64; ++index) { + blocks[i >>> 2] |= message[index] << SHIFT[i++ & 3]; + } } this.lastByteIndex = i; @@ -157,7 +235,7 @@ this.finalized = true; var blocks = this.blocks, i = this.lastByteIndex; blocks[16] = this.block; - blocks[i >> 2] |= EXTRA[i & 3]; + blocks[i >>> 2] |= EXTRA[i & 3]; this.block = blocks[16]; if (i >= 56) { if (!this.hashed) { @@ -303,26 +381,26 @@ var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4; - return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + - HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + - HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + - HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + - HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + - HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + - HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + - HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + - HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + - HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + - HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + - HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + - HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + - HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + - HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + - HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + - HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + - HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + - HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + - HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F]; + return HEX_CHARS[(h0 >>> 28) & 0x0F] + HEX_CHARS[(h0 >>> 24) & 0x0F] + + HEX_CHARS[(h0 >>> 20) & 0x0F] + HEX_CHARS[(h0 >>> 16) & 0x0F] + + HEX_CHARS[(h0 >>> 12) & 0x0F] + HEX_CHARS[(h0 >>> 8) & 0x0F] + + HEX_CHARS[(h0 >>> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + + HEX_CHARS[(h1 >>> 28) & 0x0F] + HEX_CHARS[(h1 >>> 24) & 0x0F] + + HEX_CHARS[(h1 >>> 20) & 0x0F] + HEX_CHARS[(h1 >>> 16) & 0x0F] + + HEX_CHARS[(h1 >>> 12) & 0x0F] + HEX_CHARS[(h1 >>> 8) & 0x0F] + + HEX_CHARS[(h1 >>> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + + HEX_CHARS[(h2 >>> 28) & 0x0F] + HEX_CHARS[(h2 >>> 24) & 0x0F] + + HEX_CHARS[(h2 >>> 20) & 0x0F] + HEX_CHARS[(h2 >>> 16) & 0x0F] + + HEX_CHARS[(h2 >>> 12) & 0x0F] + HEX_CHARS[(h2 >>> 8) & 0x0F] + + HEX_CHARS[(h2 >>> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + + HEX_CHARS[(h3 >>> 28) & 0x0F] + HEX_CHARS[(h3 >>> 24) & 0x0F] + + HEX_CHARS[(h3 >>> 20) & 0x0F] + HEX_CHARS[(h3 >>> 16) & 0x0F] + + HEX_CHARS[(h3 >>> 12) & 0x0F] + HEX_CHARS[(h3 >>> 8) & 0x0F] + + HEX_CHARS[(h3 >>> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + + HEX_CHARS[(h4 >>> 28) & 0x0F] + HEX_CHARS[(h4 >>> 24) & 0x0F] + + HEX_CHARS[(h4 >>> 20) & 0x0F] + HEX_CHARS[(h4 >>> 16) & 0x0F] + + HEX_CHARS[(h4 >>> 12) & 0x0F] + HEX_CHARS[(h4 >>> 8) & 0x0F] + + HEX_CHARS[(h4 >>> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F]; }; Sha1.prototype.toString = Sha1.prototype.hex; @@ -333,11 +411,11 @@ var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4; 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 + (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 ]; }; @@ -356,7 +434,68 @@ return buffer; }; + function HmacSha1(key, sharedMemory) { + var i, result = formatMessage(key); + key = result[0]; + if (result[1]) { + var bytes = [], length = key.length, index = 0, code; + for (i = 0; i < length; ++i) { + code = key.charCodeAt(i); + if (code < 0x80) { + bytes[index++] = code; + } else if (code < 0x800) { + bytes[index++] = (0xc0 | (code >>> 6)); + bytes[index++] = (0x80 | (code & 0x3f)); + } else if (code < 0xd800 || code >= 0xe000) { + bytes[index++] = (0xe0 | (code >>> 12)); + bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); + bytes[index++] = (0x80 | (code & 0x3f)); + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff)); + bytes[index++] = (0xf0 | (code >>> 18)); + bytes[index++] = (0x80 | ((code >>> 12) & 0x3f)); + bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); + bytes[index++] = (0x80 | (code & 0x3f)); + } + } + key = bytes; + } + + if (key.length > 64) { + key = (new Sha1(true)).update(key).array(); + } + + var oKeyPad = [], iKeyPad = []; + for (i = 0; i < 64; ++i) { + var b = key[i] || 0; + oKeyPad[i] = 0x5c ^ b; + iKeyPad[i] = 0x36 ^ b; + } + + Sha1.call(this, sharedMemory); + + this.update(iKeyPad); + this.oKeyPad = oKeyPad; + this.inner = true; + this.sharedMemory = sharedMemory; + } + HmacSha1.prototype = new Sha1(); + + HmacSha1.prototype.finalize = function () { + Sha1.prototype.finalize.call(this); + if (this.inner) { + this.inner = false; + var innerHash = this.array(); + Sha1.call(this, this.sharedMemory); + this.update(this.oKeyPad); + this.update(innerHash); + Sha1.prototype.finalize.call(this); + } + }; + var exports = createMethod(); + exports.sha1 = exports; + exports.sha1.hmac = createHmacMethod(); if (COMMON_JS) { module.exports = exports; diff --git a/tests/hmac-test.js b/tests/hmac-test.js new file mode 100644 index 0000000..92cd3e6 --- /dev/null +++ b/tests/hmac-test.js @@ -0,0 +1,202 @@ +(function (sha1) { + Array.prototype.toHexString = ArrayBuffer.prototype.toHexString = function () { + var array = new Uint8Array(this); + var hex = ''; + for (var i = 0; i < array.length; ++i) { + var c = array[i].toString('16'); + hex += c.length === 1 ? '0' + c : c; + } + return hex; + }; + + var testCases = { + sha1_hmac: { + 'Test Vectors': { + 'b617318655057264e28bc0b6fb378c8ef146be00': [ + [0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b], + 'Hi There' + ], + 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79': [ + 'Jefe', + 'what do ya want for nothing?' + ], + '125d7342b9ac11cd91a39af48aa17b4f63f175d3': [ + [0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa], + [0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd] + ], + '4c9007f4026250c6bc8414f9bf50c86c2d7235da': [ + [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19], + [0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd] + ], + '4c1a03424b55e07fe7f27be1d58bb9324a9a5a04': [ + [0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c], + 'Test With Truncation' + ], + 'aa4ae5e15272d00e95705637ce8a3b55ed402112': [ + [0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa], + 'Test Using Larger Than Block-Size Key - Hash Key First' + ], + 'e8e99d0f45237d786d6bbaa7965c7808bbff1a91': [ + [0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa], + 'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data' + ] + }, + 'UTF8': { + 'f495de6d0f1b5681070a024bbaed5b5f42847306': ['中文', '中文'], + '58891d68487ffebddba5925abedec77a5a578db2': ['aécio', 'aécio'], + 'a1816bff2dae324c283aeab564d5edb5170fbada': ['𠜎', '𠜎'] + } + } + }; + + if (!(typeof JS_SHA1_NO_ARRAY_BUFFER === 'boolean' && JS_SHA1_NO_ARRAY_BUFFER)) { + testCases.sha1_hmac.Uint8Array = { + '69536cc84eee5fe51c5b051aff8485f5c9ef0b58': [ + new Uint8Array(0), + 'Hi There' + ] + }; + testCases.sha1_hmac.ArrayBuffer = { + '69536cc84eee5fe51c5b051aff8485f5c9ef0b58': [ + new ArrayBuffer(0), + 'Hi There' + ] + }; + } + + var errorTestCases = [null, undefined, { length: 0 }, 0, 1, false, true, NaN, Infinity, function () {}]; + + function runTestCases(name, algorithm) { + var methods = [ + { + name: name, + call: algorithm, + }, + { + name: name + '.hex', + call: algorithm.hex + }, + { + name: name + '.array', + call: function (key, message) { + return algorithm.array(key, message).toHexString(); + } + }, + { + name: name + '.digest', + call: function (key, message) { + return algorithm.digest(key, message).toHexString(); + } + }, + { + name: name + '.arrayBuffer', + call: function (key, message) { + return algorithm.arrayBuffer(key, message).toHexString(); + } + } + ]; + + var classMethods = [ + { + name: 'create', + call: function (key, message) { + return algorithm.create(key).update(message).toString(); + } + }, + { + name: 'update', + call: function (key, message) { + return algorithm.update(key, message).toString(); + } + }, + { + name: 'hex', + call: function (key, message) { + return algorithm.update(key, message).hex(); + } + }, + { + name: 'array', + call: function (key, message) { + return algorithm.update(key, message).array().toHexString(); + } + }, + { + name: 'digest', + call: function (key, message) { + return algorithm.update(key, message).digest().toHexString(); + } + }, + { + name: 'arrayBuffer', + call: function (key, message) { + return algorithm.update(key, message).arrayBuffer().toHexString(); + } + }, + { + name: 'finalize', + call: function (key, message) { + var hash = algorithm.update(key, message); + hash.hex(); + return hash.hex(); + } + } + ]; + + var subTestCases = testCases[name]; + + describe(name, function () { + methods.forEach(function (method) { + describe('#' + method.name, function () { + for (var testCaseName in subTestCases) { + (function (testCaseName) { + var testCase = subTestCases[testCaseName]; + context('when ' + testCaseName, function () { + for (var hash in testCase) { + (function (message, hash) { + it('should be equal', function () { + expect(method.call(message[0], message[1])).to.be(hash); + }); + })(testCase[hash], hash); + } + }); + })(testCaseName); + } + }); + }); + + classMethods.forEach(function (method) { + describe('#' + method.name, function () { + for (var testCaseName in subTestCases) { + (function (testCaseName) { + var testCase = subTestCases[testCaseName]; + context('when ' + testCaseName, function () { + for (var hash in testCase) { + (function (message, hash) { + it('should be equal', function () { + expect(method.call(message[0], message[1])).to.be(hash); + }); + })(testCase[hash], hash); + } + }); + })(testCaseName); + } + }); + }); + + describe('#' + name, function () { + errorTestCases.forEach(function (testCase) { + context('when ' + testCase, function () { + it('should throw error', function () { + expect(function () { + algorithm(testCase, ''); + }).to.throwError(/input is invalid type/); + }); + }); + }); + }); + }); + } + + runTestCases('sha1_hmac', sha1.hmac); +})(sha1); diff --git a/tests/node-test.js b/tests/node-test.js index 8359a27..3da2756 100644 --- a/tests/node-test.js +++ b/tests/node-test.js @@ -1,32 +1,63 @@ -// Node.js env expect = require('expect.js'); -sha1 = require('../src/sha1.js'); -require('./test.js'); +Worker = require("tiny-worker"); + +function unset() { + delete require.cache[require.resolve('../src/sha1.js')]; + delete require.cache[require.resolve('./test.js')]; + delete require.cache[require.resolve('./hmac-test.js')]; + sha1 = null; + BUFFER = undefined; + JS_SHA1_NO_WINDOW = undefined; + JS_SHA1_NO_NODE_JS = undefined; + JS_SHA1_NO_COMMON_JS = undefined; + JS_SHA1_NO_ARRAY_BUFFER = undefined; + JS_SHA1_NO_ARRAY_BUFFER_IS_VIEW = undefined; + window = undefined; +} + +function runCommonJsTest() { + sha1 = require('../src/sha1.js'); + require('./test.js'); + require('./hmac-test.js'); + unset(); +} + +function runWindowTest() { + window = global; + require('../src/sha1.js'); + require('./test.js'); + require('./hmac-test.js'); + unset(); +} + +// Node.js env +BUFFER = true; +runCommonJsTest(); -delete require.cache[require.resolve('../src/sha1.js')]; -delete require.cache[require.resolve('./test.js')]; -sha1 = null; +// Node.js env, no Buffer.from +JS_SHA1_NO_BUFFER_FROM = true +runCommonJsTest(); // Webpack browser env JS_SHA1_NO_NODE_JS = true; -window = global; -sha1 = require('../src/sha1.js'); -require('./test.js'); - -delete require.cache[require.resolve('../src/sha1.js')]; -delete require.cache[require.resolve('./test.js')]; -sha1 = null; +runCommonJsTest(); // browser env JS_SHA1_NO_NODE_JS = true; JS_SHA1_NO_COMMON_JS = true; -window = global; -require('../src/sha1.js'); -require('./test.js'); +runWindowTest(); -delete require.cache[require.resolve('../src/sha1.js')]; -delete require.cache[require.resolve('./test.js')]; -sha1 = null; +// browser env and no array buffer +JS_SHA1_NO_NODE_JS = true; +JS_SHA1_NO_COMMON_JS = true; +JS_SHA1_NO_ARRAY_BUFFER = true; +runWindowTest(); + +// browser env and no isView +JS_SHA1_NO_NODE_JS = true; +JS_SHA1_NO_COMMON_JS = true; +JS_SHA1_NO_ARRAY_BUFFER_IS_VIEW = true; +runWindowTest(); // browser AMD JS_SHA1_NO_NODE_JS = true; @@ -35,7 +66,93 @@ window = global; define = function (func) { sha1 = func(); require('./test.js'); + require('./hmac-test.js'); }; define.amd = true; require('../src/sha1.js'); +unset(); + +// webworker +WORKER = 'tests/worker.js'; +SOURCE = 'src/sha1.js'; + +require('./worker-test.js'); + +delete require.cache[require.resolve('./worker-test.js')]; + +// cover webworker +JS_SHA1_NO_WINDOW = true; +JS_SHA1_NO_NODE_JS = true; +WORKER = './worker.js'; +SOURCE = '../src/sha1.js'; +window = global; +self = global; + +Worker = function (file) { + require(file); + currentWorker = this; + + this.postMessage = function (data) { + onmessage({data: data}); + }; +} + +postMessage = function (data) { + currentWorker.onmessage({data: data}); +} + +importScripts = function () {}; + +sha1 = require('../src/sha1.js'); +require('./worker-test.js'); + + + + + + + +// sha1 = require('../src/sha1.js'); +// require('./test.js'); + +// delete require.cache[require.resolve('../src/sha1.js')]; +// delete require.cache[require.resolve('./test.js')]; +// delete require.cache[require.resolve('./hmac-test.js')]; +// sha1 = null; + +// // Webpack browser env +// JS_SHA1_NO_NODE_JS = true; +// window = global; +// sha1 = require('../src/sha1.js'); +// require('./test.js'); + +// delete require.cache[require.resolve('../src/sha1.js')]; +// delete require.cache[require.resolve('./test.js')]; +// delete require.cache[require.resolve('./hmac-test.js')]; +// sha1 = null; + +// // browser env +// JS_SHA1_NO_NODE_JS = true; +// JS_SHA1_NO_COMMON_JS = true; +// window = global; +// require('../src/sha1.js'); +// require('./test.js'); + +// delete require.cache[require.resolve('../src/sha1.js')]; +// delete require.cache[require.resolve('./test.js')]; +// delete require.cache[require.resolve('./hmac-test.js')]; +// sha1 = null; + +// // browser AMD +// JS_SHA1_NO_NODE_JS = true; +// JS_SHA1_NO_COMMON_JS = true; +// window = global; +// define = function (func) { +// sha1 = func(); +// require('./test.js'); +// require('./hmac-test.js'); +// }; +// define.amd = true; + +// require('../src/sha1.js'); diff --git a/tests/requirejs.html b/tests/requirejs.html new file mode 100644 index 0000000..e750f82 --- /dev/null +++ b/tests/requirejs.html @@ -0,0 +1,24 @@ + + + + + SHA1 + + + + + + +
+ + + diff --git a/tests/test.js b/tests/test.js index 7ee9d34..1aed9f2 100644 --- a/tests/test.js +++ b/tests/test.js @@ -21,7 +21,8 @@ 'UTF8': { '7be2d2d20c106eee0836c9bc2b939890a78e8fb3': '中文', '9e4e5d978deced901d621475b03f1ded19e945bf': 'aécio', - '4667688a63420661469c8dbc0f871770349bab08': '𠜎' + '4667688a63420661469c8dbc0f871770349bab08': '𠜎', + '20cc8fef058da244b90ed814ab1b6d9d5b4796bf': 'Tehtäväsi on muotoilla teksti, jossa käyttäjälle suositellaan hänen henkilökohtaisiin tietoihinsa perustuen avioehdon tekemistä. Suosittelemme nimenomaan tätä tuotetta käyttäjän henkilökohtaisista tiedoista johtuen. Tuottamasi tekstin tulee olla lyhyt, persoonallinen, ymmärrettävä ja todenmukainen. Suositus perustuu seuraaviin seikkoihin:\n\nSeikka 0: Avioehdon tekeminen on verohyötyjen vuoksi suositeltavaa, koska olet ilmaissut että haluat kuoleman tapauksessa turvata ensisijaisesti aviopuolisosi asemaa (ennemmin kuin lasten asemaa). Avioehdolla voit määrätä, että puolet kuolleen puolison omaisuudesta siirtyy verovapaasti leskelle.\n\nVoit halutessasi hyödyntää seuraavia tietoja tekstin muotoilussa persoonallisemmaksi: Käyttäjällä on kumppani nimeltä PARTNER_NAME. Käyttäjällä on suurperhe. Käyttäjällä on lapsiperhe.\n\nPuhuttele käyttäjää siihen sävyyn että tiedät jo mitä käyttäjä haluaa, koska hän on kertonut toiveistaan, ja niiden perusteella tehty suositus on ilmiselvä. Joten älä käytä epävarmoja ilmaisuja kuten "halutessasi", vaan kirjoita itsevarmoilla ilmaisuilla kuten "koska haluat". Älä tee oletuksia käyttäjän sukupuolesta, emme tiedä onko hän mies vai nainen. Älä käytä sanaa jälkikasvu, puhu ennemmin lapsesta tai lapsista riippuen onko lapsia yksi vai useampia. Älä puhuttele käyttäjää ensimmäisessä persoonassa, käytä ennemmin passiivimuotoa. Tekstin sävyn tulisi olla neutraalin asiallinen, ei melodramaattinen eikä leikkisä. Pysy totuudessa, älä keksi uusia seikkoja yllä listattujen lisäksi. Viittaa ihmisiin nimillä silloin kun se on mahdollista. Tekstin tulisi olla vain muutaman lauseen mittainen. Älä siis kirjoita pitkiä selityksiä äläkä kirjoita listoja. Tiivistä oleellinen tieto lyhyeksi ja persoonalliseksi tekstiksi.' }, 'UTF8 more than 64 bytes': { 'ad8aae581c915fe01c4964a5e8b322cae74ee5c5': '訊息摘要演算法第五版(英語:Message-Digest Algorithm 5,縮寫為MD5),是當前電腦領域用於確保資訊傳輸完整一致而廣泛使用的雜湊演算法之一', @@ -38,28 +39,30 @@ 'da39a3ee5e6b4b0d3255bfef95601890afd80709': [], '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12': [84, 104, 101, 32, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 32, 106, 117, 109, 112, 115, 32, 111, 118, 101, 114, 32, 116, 104, 101, 32, 108, 97, 122, 121, 32, 100, 111, 103], '55a13698cdc010c0d16dab2f7dc10f43a713f12f': [48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55, 56, 48, 49, 50, 51, 52, 53, 54, 55] - }, - 'Uint8Array': { + } + }; + + if (!(typeof JS_SHA1_NO_ARRAY_BUFFER === 'boolean' && JS_SHA1_NO_ARRAY_BUFFER)) { + testCases['Uint8Array'] = { '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12': new Uint8Array([84, 104, 101, 32, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 32, 106, 117, 109, 112, 115, 32, 111, 118, 101, 114, 32, 116, 104, 101, 32, 108, 97, 122, 121, 32, 100, 111, 103]) - }, - 'Int8Array': { + }; + testCases['Int8Array'] = { '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12': new Int8Array([84, 104, 101, 32, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 32, 106, 117, 109, 112, 115, 32, 111, 118, 101, 114, 32, 116, 104, 101, 32, 108, 97, 122, 121, 32, 100, 111, 103]) - }, - 'ArrayBuffer': { + }; + testCases['ArrayBuffer'] = { '5ba93c9db0cff93f52b521d7420e43f6eda2784f': new ArrayBuffer(1) - }, - 'Object': { - 'da39a3ee5e6b4b0d3255bfef95601890afd80709': {what: 'ever'} - } - }; + }; + } - if (typeof process == 'object') { + if (typeof BUFFER === 'boolean' && BUFFER) { testCases['Buffer'] = { - 'da39a3ee5e6b4b0d3255bfef95601890afd80709': new Buffer(0), - '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12': new Buffer(new Uint8Array([84, 104, 101, 32, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 32, 106, 117, 109, 112, 115, 32, 111, 118, 101, 114, 32, 116, 104, 101, 32, 108, 97, 122, 121, 32, 100, 111, 103])) - }; + 'da39a3ee5e6b4b0d3255bfef95601890afd80709': Buffer.from([]), + '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12': Buffer.from(new Uint8Array([84, 104, 101, 32, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 32, 106, 117, 109, 112, 115, 32, 111, 118, 101, 114, 32, 116, 104, 101, 32, 108, 97, 122, 121, 32, 100, 111, 103])) + } } + var errorTestCases = [null, undefined, { length: 0 }, 0, 1, false, true, NaN, Infinity, function () {}]; + var methods = [ { name: 'sha1', @@ -131,32 +134,31 @@ call: function (message) { var hash = sha1.update(message); hash.hex(); - hash.update(message); return hash.hex(); } } ]; - methods.forEach(function (method) { - describe('#' + method.name, function () { - for (var testCaseName in testCases) { - (function (testCaseName) { - var testCase = testCases[testCaseName]; - context('when ' + testCaseName, function () { - for (var hash in testCase) { - (function (message, hash) { - it('should be equal', function () { - expect(method.call(message)).to.be(hash); - }); - })(testCase[hash], hash); - } - }); - })(testCaseName); - } + describe('sha1', function () { + methods.forEach(function (method) { + describe('#' + method.name, function () { + for (var testCaseName in testCases) { + (function (testCaseName) { + var testCase = testCases[testCaseName]; + context('when ' + testCaseName, function () { + for (var hash in testCase) { + (function (message, hash) { + it('should be equal', function () { + expect(method.call(message)).to.be(hash); + }); + })(testCase[hash], hash); + } + }); + })(testCaseName); + } + }); }); - }); - describe('Sha1', function () { classMethods.forEach(function (method) { describe('#' + method.name, function () { for (var testCaseName in testCases) { @@ -175,6 +177,28 @@ } }); }); + }); + + describe('#sha1', function () { + errorTestCases.forEach(function (testCase) { + context('when ' + testCase, function () { + it('should throw error', function () { + expect(function () { + sha1(testCase); + }).to.throwError(/input is invalid type/); + }); + }); + }); + + context('when update after finalize', function () { + it('should throw error', function () { + expect(function () { + var hash = sha1.update('any'); + hash.hex(); + hash.update('any'); + }).to.throwError(/finalize already called/); + }); + }); context('when large size', function () { var hash = sha1.create(); diff --git a/tests/worker-test.js b/tests/worker-test.js new file mode 100644 index 0000000..bb3b94a --- /dev/null +++ b/tests/worker-test.js @@ -0,0 +1,24 @@ +(function (Worker, WORKER, SOURCE) { + var cases = { + 'da39a3ee5e6b4b0d3255bfef95601890afd80709': '', + '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12': 'The quick brown fox jumps over the lazy dog', + '408d94384216f890ff7a0c3528e8bed1e0b01621': 'The quick brown fox jumps over the lazy dog.' + }; + + describe('#sha1', function () { + Object.keys(cases).forEach(function (hash) { + it('should be equal', function (done) { + var worker = new Worker(WORKER); + worker.onmessage = function(event) { + expect(event.data).to.be(hash); + if (worker.terminate) { + worker.terminate(); + } + done(); + }; + worker.postMessage(SOURCE); + worker.postMessage(cases[hash]); + }); + }); + }); +})(Worker, WORKER, SOURCE); diff --git a/tests/worker.html b/tests/worker.html new file mode 100644 index 0000000..cc4125d --- /dev/null +++ b/tests/worker.html @@ -0,0 +1,25 @@ + + + + + SHA1 + + + + + + +
+ + + + + + diff --git a/tests/worker.js b/tests/worker.js new file mode 100644 index 0000000..1a1dcf4 --- /dev/null +++ b/tests/worker.js @@ -0,0 +1,12 @@ +var imported = false; +onmessage = function(e) { + if (imported) { + postMessage(sha1(e.data)); + if (typeof exports !== 'undefined') { + imported = false; + } + } else { + imported = true; + importScripts(e.data); + } +}