diff --git a/.covignore b/.covignore new file mode 100644 index 0000000..016f806 --- /dev/null +++ b/.covignore @@ -0,0 +1 @@ +/tests/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f5cd45c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: node_js +node_js: + - "0.11" + - "0.10" + - "0.8" +install: + - npm install mocha -g + - npm install coveralls -g + - npm install mocha-lcov-reporter -g + - npm install +script: + - npm run-script coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md index 678a8fe..9a37e77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v0.1.2 / 2015-01-07 + +* Add bower package. +* Fixed JSHint warnings. +* Add travis. +* Add coveralls. + # v0.1.1 / 2014-07-27 Fixed accents bug diff --git a/LICENSE.txt b/LICENSE.txt index dff2ebd..58074d3 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright 2014 emn178@gmail.com +Copyright 2014-2015 emn178@gmail.com 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 cf5df9f..d0efb15 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,49 @@ # js-md2 +[![Build Status](https://api.travis-ci.org/emn178/js-md5.png)](https://travis-ci.org/emn178/js-md5) +[![Build Status](https://coveralls.io/repos/emn178/js-md5/badge.png?branch=master)](https://coveralls.io/r/emn178/js-md5?branch=master) +[![NPM](https://nodei.co/npm/js-md5.png?stars&downloads)](https://nodei.co/npm/js-md5/) A simple MD2 hash function for JavaScript supports UTF-8 encoding. -## Install +## Demo +[MD2 Online](http://emn178.github.io/online-tools/md2.html) + +## Download +[Compress](https://raw.github.com/emn178/js-md2/master/build/md2.min.js) +[Uncompress](https://raw.github.com/emn178/js-md2/master/src/md2.js) + +## Installation +You can also install js-md2 by using Bower. + + bower install js-md2 + For node.js, you can use this command to install: npm install js-md2 ## Usage -If you use node.js, you should require the module first: +You could use like this: ```JavaScript -md2 = require('js-md2'); +md2('Message to hash'); ``` -And you could use like this: +If you use node.js, you should require the module first: ```JavaScript -md2('Message to hash'); +md2 = require('js-md2'); ``` + +### Methods + +#### md2(str, asciiOnly) + +Hash string to md2, set asciiOnly to true for better performace if you ensure input is ascii. + +##### *str: `String`* + +String to hash. + +##### *asciiOnly: `Boolean` (default: `false`)* + +Specify the string encoding is ASCII. + ## Example Code ```JavaScript @@ -38,15 +67,6 @@ Output 7af93c270b0ec392ca2f0d90a927cf8a -## Tests -You can open `tests/index.html` in browser or use node.js to run test - - node tests/node-test.js - -or - - npm test - ## Extensions ### jQuery If you prefer jQuery style, you can add following code to add a jQuery extension. diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..5e5e044 --- /dev/null +++ b/bower.json @@ -0,0 +1,9 @@ +{ + "name": "js-md2", + "version": "0.1.2", + "main": ["build/md2.min.js"], + "ignore": [ + "samples", + "tests" + ] +} diff --git a/build/md2.min.js b/build/md2.min.js index 669af33..a7f97a3 100644 --- a/build/md2.min.js +++ b/build/md2.min.js @@ -1,4 +1,4 @@ -(function(h,n){var k={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:10,B:11,C:12,D:13,E:14,F:15},l=[41,46,67,201,162,216,124,1,61,54,84,161,236,240,6,19,98,167,5,243,192,199,115,140,152,147,43,217,188,76,130,202,30,155,87,60,253,212,224,22,103,66,111,24,138,23,229,18,190,78,196,214,218,158,222,73,160,251,245,142,187,47,238,122,169,104,121,145,21,178,7,63,148,194,16,137,11,34,95,33,128,127,93,154,90,144,50,39,53,62,204,231,191,247,151,3,255,25,48,179,72,165,181,209,215,94, -146,42,172,86,170,198,79,184,56,210,150,164,125,182,118,252,107,226,156,116,4,241,69,157,112,89,100,113,135,32,134,91,207,101,230,45,168,2,27,96,37,173,174,176,185,246,28,70,97,105,52,64,126,15,85,71,163,35,221,81,175,58,195,92,249,206,186,197,234,38,44,83,13,110,133,40,132,9,211,223,205,244,65,129,77,82,106,220,55,200,108,193,171,250,36,225,123,8,12,189,177,74,120,136,149,139,227,99,232,109,233,203,213,254,59,0,29,57,242,239,183,14,102,88,208,228,166,119,114,248,235,117,75,10,49,68,80,180,143,237, -31,26,219,153,141,51,159,17,131,20],m=function(d){var a;a:{for(a=d.length;a--;)if(127>4)+1<<4;b=16-(c&15);for(a=c;a>4)+1<<4;c=[];for(e=0;e>4;for(b=0;bf;++f)a[f]^=l[d[(b<<4)+f]^ -c],c=a[f];e=d.length;for(b=0;16>b;++b)d[e+b]=a[b];a=[];for(c=0;48>c;++c)a[c]=0;e=d.length>>4;for(c=0;cb;++b)a[16+b]=d[(c<<4)+b],a[32+b]=a[16+b]^a[b];for(b=f=0;18>b;++b){for(var g=0;48>g;++g)a[g]=f=a[g]^l[f];f=f+b&255}}d="";for(c=0;16>c;++c)d+="0123456789abcdef".charAt(a[c]>>4&15)+"0123456789abcdef".charAt(a[c]&15);return d};"undefined"!=typeof module?module.exports=m:h&&(h.md2=m)})(this); +(function(l,q){var m="0123456789abcdef".split(""),n=[41,46,67,201,162,216,124,1,61,54,84,161,236,240,6,19,98,167,5,243,192,199,115,140,152,147,43,217,188,76,130,202,30,155,87,60,253,212,224,22,103,66,111,24,138,23,229,18,190,78,196,214,218,158,222,73,160,251,245,142,187,47,238,122,169,104,121,145,21,178,7,63,148,194,16,137,11,34,95,33,128,127,93,154,90,144,50,39,53,62,204,231,191,247,151,3,255,25,48,179,72,165,181,209,215,94,146,42,172,86,170,198,79,184,56,210,150,164,125,182,118,252,107,226,156, +116,4,241,69,157,112,89,100,113,135,32,134,91,207,101,230,45,168,2,27,96,37,173,174,176,185,246,28,70,97,105,52,64,126,15,85,71,163,35,221,81,175,58,195,92,249,206,186,197,234,38,44,83,13,110,133,40,132,9,211,223,205,244,65,129,77,82,106,220,55,200,108,193,171,250,36,225,123,8,12,189,177,74,120,136,149,139,227,99,232,109,233,203,213,254,59,0,29,57,242,239,183,14,102,88,208,228,166,119,114,248,235,117,75,10,49,68,80,180,143,237,31,26,219,153,141,51,159,17,131,20],p=function(k,l){var d,h=[],b,a;if(!l&& +/[^\x00-\x7F]/.test(k)){d=[];for(a=b=0;ac?d[b++]=c:(2048>c?d[b++]=192|c>>6:(55296>c||57344<=c?d[b++]=224|c>>12:(c=65536+((c&1023)<<10|k.charCodeAt(++a)&1023),d[b++]=240|c>>18,d[b++]=128|c>>12&63),d[b++]=128|c>>6&63),d[b++]=128|c&63)}var f=d.length;b=(f>>4)+1<<4;a=[];for(c=0;c>4)+1<<4;b=[];for(a=0;a> +4,e;for(e=0;eg;++g)a[g]^=n[b[(e<<4)+g]^c],c=a[g];f=b.length;for(e=0;16>e;++e)b[f+e]=a[e];for(b=0;48>b;++b)h[b]=0;c=d.length>>4;f="";for(b=0;ba;++a)h[16+a]=d[(b<<4)+a],h[32+a]=h[16+a]^h[a];for(a=e=0;18>a;++a){for(g=0;48>g;++g)h[g]=e=h[g]^n[e];e=e+a&255}}for(b=0;16>b;++b)f+=m[h[b]>>4&15]+m[h[b]&15];return f};"undefined"!=typeof module?module.exports=p:l&&(l.md2=p)})(this); diff --git a/package.json b/package.json index b034dcc..4a1fc31 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,15 @@ { "name": "js-md2", - "version": "0.1.1", + "version": "0.1.2", "description": "A simple MD2 hash function for JavaScript supports UTF-8 encoding.", "main": "src/md2.js", + "devDependencies": { + "expect.js": "~0.3.1", + "jscoverage": "~0.5.9" + }, "scripts": { - "test": "node tests/node-test.js" + "test": "mocha tests/node-test.js -r jscoverage", + "coveralls": "mocha tests/node-test.js -R mocha-lcov-reporter -r jscoverage | coveralls" }, "repository": { "type": "git", diff --git a/src/md2.js b/src/md2.js index c1de679..42b9e0e 100644 --- a/src/md2.js +++ b/src/md2.js @@ -1,22 +1,16 @@ /* - * js-md5 v0.1.1 + * js-md5 v0.1.2 * https://github.com/emn178/js-md2 * - * Copyright 2014, emn178@gmail.com + * Copyright 2014-2015, emn178@gmail.com * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ - -;(function(root, undefined){ +;(function(root, undefined) { 'use strict'; - var HEX_CHARS = "0123456789abcdef"; - var HEX_TABLE = { - '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': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15 - }; + var HEX_CHARS = '0123456789abcdef'.split(''); var S = [ 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, @@ -35,99 +29,114 @@ 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14]; - var md2 = function(message) { - var M = hasUTF8(message) ? UTF8toBlocks(message) : ASCIItoBlocks(message); + var md2 = function(message, asciiOnly) { + var M, X = [], i, j; + if(!asciiOnly && /[^\x00-\x7F]/.test(message)) { + M = getBlocksFromUtf8(message); + } else { + M = getBlocksFromAscii(message); + } appendChecksum(M); - var X = []; - for(var i = 0;i < 48;++i) + for(i = 0;i < 48;++i) { X[i] = 0; - var length = M.length >> 4; - for(var i = 0;i < length;++i) - { - for(var j = 0;j < 16;++j) - { + } + var length = M.length >> 4, hex = ''; + for(i = 0;i < length;++i) { + for(j = 0;j < 16;++j) { X[16 + j] = M[(i << 4) + j]; X[32 + j] = X[16 + j] ^ X[j]; } var t = 0; - for(var j = 0;j < 18;++j) - { - for(var k = 0;k < 48;++k) + for(j = 0;j < 18;++j) { + for(var k = 0;k < 48;++k) { X[k] = t = X[k] ^ S[t]; + } t = (t + j) & 0xFF; } } - var hex = ''; - for(var i = 0;i < 16;++i) - hex += HEX_CHARS.charAt((X[i] >> 4) & 0x0F) + HEX_CHARS.charAt(X[i] & 0x0F); + for(i = 0;i < 16;++i) { + hex += HEX_CHARS[(X[i] >> 4) & 0x0F] + HEX_CHARS[X[i] & 0x0F]; + } return hex; }; - var hasUTF8 = function(message) { - for(var i = message.length;i--;) - if(message.charCodeAt(i) > 127) - return true; - return false; + var getBytesFromUtf8 = function(str) { + var bytes = [], index = 0; + for (var i = 0;i < str.length; i++) { + var c = str.charCodeAt(i); + if (c < 0x80) { + bytes[index++] = c; + } else if (c < 0x800) { + bytes[index++] = 0xc0 | (c >> 6); + bytes[index++] = 0x80 | (c & 0x3f); + } else if (c < 0xd800 || c >= 0xe000) { + bytes[index++] = 0xe0 | (c >> 12); + bytes[index++] = 0x80 | ((c >> 6) & 0x3f); + bytes[index++] = 0x80 | (c & 0x3f); + } else { + c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff)); + bytes[index++] = 0xf0 | (c >> 18); + bytes[index++] = 0x80 | ((c >> 12) & 0x3f); + bytes[index++] = 0x80 | ((c >> 6) & 0x3f); + bytes[index++] = 0x80 | (c & 0x3f); + } + } + return bytes; }; - var ASCIItoBlocks = function(message) { + var getBlocksFromAscii = function(message) { // a block is 8 bits(1 bytes), a chunk is 128 bits(16 bytes) var length = message.length; var chunkCount = (length >> 4) + 1; var blockCount = chunkCount << 4; // chunkCount * 16 - var blocks = []; - var i; - for(i = 0;i < length;++i) + var blocks = [], i; + for(i = 0;i < length;++i) { blocks[i] = message.charCodeAt(i); + } var ibit = 16 - (length & 15); - for(;i < blockCount;++i) + for(;i < blockCount;++i) { blocks[i] = ibit; + } return blocks; }; - var UTF8toBlocks = function(message) { - var uri = encodeURIComponent(message); - var blocks = []; - for(var i = 0, bytes = 0, length = uri.length;i < length;++i) - { - var c = uri.charCodeAt(i); - if(c == 37) // % - blocks[bytes] = (HEX_TABLE[uri.charAt(++i)] << 4) | HEX_TABLE[uri.charAt(++i)]; - else - blocks[bytes] = c; - ++bytes; + var getBlocksFromUtf8 = function(message) { + // a block is 8 bits(1 bytes), a chunk is 128 bits(16 bytes) + var bytes = getBytesFromUtf8(message); + var length = bytes.length; + var chunkCount = (length >> 4) + 1; + var blockCount = chunkCount << 4; // chunkCount * 16 + var blocks = [], i; + for(i = 0;i < length;++i) { + blocks[i] = bytes[i]; } - var chunkCount = (bytes >> 4) + 1; - var blockCount = chunkCount << 4; // chunkCount * 4 - var ibit = 16 - (bytes & 15); - for(var i = bytes;i < blockCount;++i) + var ibit = 16 - (length & 15); + for(;i < blockCount;++i) { blocks[i] = ibit; + } return blocks; }; var appendChecksum = function(M) { - var checksum = []; - var L = 0; - var length = M.length >> 4; - for(var i = 0;i < length;++i) - { - for(var j = 0;j < 16;++j) - { + var checksum = [], L = 0, length = M.length >> 4, i; + for(i = 0;i < length;++i) { + for(var j = 0;j < 16;++j) { var c = M[(i << 4) + j]; checksum[j] ^= S[c ^ L]; L = checksum[j]; } } length = M.length; - for(var i = 0;i < 16;++i) + for(i = 0;i < 16;++i) { M[length + i] = checksum[i]; + } }; - if(typeof(module) != 'undefined') + if(typeof(module) != 'undefined') { module.exports = md2; - else if(root) + } else if(root) { root.md2 = md2; + } }(this)); - diff --git a/tests/debug.js b/tests/debug.js deleted file mode 100644 index 23900bf..0000000 --- a/tests/debug.js +++ /dev/null @@ -1,12 +0,0 @@ -(function(root) { - var assert = function (title, expect, actual) { - if(expect == actual) - console.log(title + ': true'); - else - console.log(title + ': false', 'Except:' + expect, 'Actual: ' + actual); - }; - if(typeof(module) != 'undefined') - global.assert = assert; - else if(root) - root.assert = assert; -})(this); diff --git a/tests/index.html b/tests/index.html index 76b1f6d..3bd963b 100644 --- a/tests/index.html +++ b/tests/index.html @@ -3,10 +3,20 @@ MD2 + + + - - +
+ + + diff --git a/tests/node-test.js b/tests/node-test.js index 682b7fd..935baa7 100644 --- a/tests/node-test.js +++ b/tests/node-test.js @@ -1,3 +1,3 @@ md2 = require('../src/md2.js'); -require('./debug.js'); +expect = require('expect.js'); require('./test.js'); diff --git a/tests/test.js b/tests/test.js index 9ded4bb..9d2a949 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,5 +1,30 @@ -assert('md2 1', '8350e5a3e24c153df2275c9f80692773', md2('')); -assert('md2 2', '03d85a0d629d2c442e987525319fc471', md2('The quick brown fox jumps over the lazy dog')); -assert('md2 3', '71eaa7e440b611e41a6f0d97384b342a', md2('The quick brown fox jumps over the lazy dog.')); -assert('md2 4', '7af93c270b0ec392ca2f0d90a927cf8a', md2('中文')); -assert('md2 5', '628657f2dbd637b6b13500e8567a1c83', md2('aécio')); +describe('ascii', function() { + describe('less than 64 bytes', function() { + it('should be successful', function() { + expect(md2('')).to.be('8350e5a3e24c153df2275c9f80692773'); + expect(md2('The quick brown fox jumps over the lazy dog')).to.be('03d85a0d629d2c442e987525319fc471'); + expect(md2('The quick brown fox jumps over the lazy dog.')).to.be('71eaa7e440b611e41a6f0d97384b342a'); + }); + }); + + describe('more than 64 bytes', function() { + it('should be successful', function() { + expect(md2('The MD5 message-digest algorithm is a widely used cryptographic hash function producing a 128-bit (16-byte) hash value, typically expressed in text format as a 32 digit hexadecimal number. MD5 has been utilized in a wide variety of cryptographic applications, and is also commonly used to verify data integrity.')).to.be('3658f72434eecc8bdb99047f9710c263'); + }); + }); +}); + +describe('UTF8', function() { + describe('less than 64 bytes', function() { + it('should be successful', function() { + expect(md2('中文')).to.be('7af93c270b0ec392ca2f0d90a927cf8a'); + expect(md2('aécio')).to.be('628657f2dbd637b6b13500e8567a1c83'); + }); + }); + + describe('more than 64 bytes', function() { + it('should be successful', function() { + expect(md2('訊息摘要演算法第五版(英語:Message-Digest Algorithm 5,縮寫為MD5),是當前電腦領域用於確保資訊傳輸完整一致而廣泛使用的雜湊演算法之一(又譯雜湊演算法、摘要演算法等),主流程式語言普遍已有MD5的實作。')).to.be('4a0cf02bb374a56e9a9a17e426dee995'); + }); + }); +});