From c61d471a8e2e80132ef0a0c071e80b18ec7aa891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Tue, 31 Aug 2010 13:39:16 +0200 Subject: [PATCH 01/23] Simplify tests --- lib/mysql/client.js | 2 +- test/common.js | 4 ++-- test/simple/test-client.js | 2 +- test/system/.test-client-connect.js.un~ | Bin 0 -> 3760 bytes .../.test-client-query-calculated-fields.js.un~ | Bin 0 -> 2068 bytes test/system/.test-client-query-empty.js.un~ | Bin 0 -> 1547 bytes .../system/.test-client-query-long-fields.js.un~ | Bin 0 -> 1103 bytes test/system/.test-client-query-null.js.un~ | Bin 0 -> 1547 bytes test/system/.test-client-query.js.un~ | Bin 0 -> 3887 bytes test/system/.test-client-sequential-query.js.un~ | Bin 0 -> 1966 bytes test/system/test-client-connect.js | 9 +++------ .../test-client-query-calculated-fields.js | 5 +---- test/system/test-client-query-empty.js | 5 +---- test/system/test-client-query-long-fields.js | 4 +--- test/system/test-client-query-null.js | 5 +---- test/system/test-client-query.js | 7 ++----- test/system/test-client-sequential-query.js | 5 +---- 17 files changed, 14 insertions(+), 34 deletions(-) create mode 100644 test/system/.test-client-connect.js.un~ create mode 100644 test/system/.test-client-query-calculated-fields.js.un~ create mode 100644 test/system/.test-client-query-empty.js.un~ create mode 100644 test/system/.test-client-query-long-fields.js.un~ create mode 100644 test/system/.test-client-query-null.js.un~ create mode 100644 test/system/.test-client-query.js.un~ create mode 100644 test/system/.test-client-sequential-query.js.un~ diff --git a/lib/mysql/client.js b/lib/mysql/client.js index b609377f0..9c9ac8bea 100644 --- a/lib/mysql/client.js +++ b/lib/mysql/client.js @@ -19,7 +19,7 @@ function Client(config) { this.port = 3306; this.user = null; this.password = null; - this.database = null; + this.database = ''; this.flags = Client.defaultFlags; this.maxPacketSize = 0x01000000; diff --git a/test/common.js b/test/common.js index 08e45acbb..cf91bdc8f 100644 --- a/test/common.js +++ b/test/common.js @@ -3,12 +3,12 @@ var path = require('path') require.paths.unshift(path.dirname(__dirname)+'/lib'); +global.TEST_DB = 'node_mysql_test'; global.TEST_CONFIG = { host: 'localhost', port: 3306, user: 'root', - password: 'root', - database: 'node_mysql_test', + password: 'root' }; global.TEST_TABLE = 'posts'; diff --git a/test/simple/test-client.js b/test/simple/test-client.js index a0d858ac4..7dd78c896 100644 --- a/test/simple/test-client.js +++ b/test/simple/test-client.js @@ -26,7 +26,7 @@ test(function constructor() { assert.strictEqual(client.port, 3306); assert.strictEqual(client.user, null); assert.strictEqual(client.password, null); - assert.strictEqual(client.database, null); + assert.strictEqual(client.database, ''); assert.strictEqual(client.debug, false); diff --git a/test/system/.test-client-connect.js.un~ b/test/system/.test-client-connect.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..3ab1457707d91e9d84f65a6c0e5b5637ee6b5e95 GIT binary patch literal 3760 zcmeH}ze^lJ6vyZ8%ny~62_e<%_6|~>&yZ{F_C4Da*4GrJhCeR-2SF~3yt zWcT#bcXROdH~OM zQp<<_g`&4GcyuF-&$zir2;{cU8DJdB;ZW-MKF>YCJ)|EfX2! zvmNWij`nXBgeJal^<9l_27yR#{ZdXmA|^T z%ExWH!p`w~G(+~OV@%Egrj0(psqv|Q23vXH(k zk$EY7q#g){xdUMD+(y*>DtmAkhu>tp2#ERBicIvQNm$aC;9g$}&SR3=!p49s$J7r* Zm_wqGzQnZPFqL{r3h8(Hn%w@q^B1C|vB&@b literal 0 HcmV?d00001 diff --git a/test/system/.test-client-query-calculated-fields.js.un~ b/test/system/.test-client-query-calculated-fields.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..156390b3d16c45e309c8025102d71022408cf592 GIT binary patch literal 2068 zcmWH`%$*;a=aT=Ff$87hZOdnw-VoQC^km-z1OEj_zjw(VIP#wP|JhB?tDQRh85kIN zf!MGtu}C2~Co?s#M8Q^}D7COOvnW+VJ-4#BFh^Ze&lxPE5#kyg67THq=jQ3I3Dm>{ z(g?(iK+FQfAONCan8By!r8NskmYE^`0!S7JK$>6xB*g~f{09QCQ80l~n#v&nj1F#a zbTBY{l>nN}3dFGB2StUWzP>_!X^}!nYH^7|N|HiuW_m`6LSBA}LTW`OP^dDsL`R`G zUm+zwPrXE;q^MG%BwrypKQAve8OY67$Sg5!1jjQZ$`P&y#W~C(hS7LN1PpCh@OWm# z9?znXjINiGSdy5OSey#X@#^Z<(6|G|6)ZD@oW~5r@H{&jcc37l0Kh{MXa*=`VIT~~ z0LGmKIFB+x;trOTct8rkxfUb>GX_Mff{JcP0gb!p)&VM1Q~&~a8IPq%*MTMhWQPIu zfs+HsCQw;FntefmKnZ}w9mot2+W=}9auTqD)|&7L2So{}o(4re>2IR8HofJKlLj50|G0eDCP^}wP7 zq&*B~1~57j!O_9M@KpjR2#Ys9kOH^}%oq@@T9#O(;GC10npdJ=t5B3$SejXss-d1+ zSzMT-uBiu+(E%z{Q~-ixm_mrSMu=;0NW8PZpPQ$ sqwx$15lR4Z=;DuOMo7j+k7rRxUe!xUEJ;jCEKUXHZgq8Q)5hnk0Ol!byZ`_I literal 0 HcmV?d00001 diff --git a/test/system/.test-client-query-long-fields.js.un~ b/test/system/.test-client-query-long-fields.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..0fb30d1c5d5f0bc97106558317b097c8fd992fac GIT binary patch literal 1103 zcmWH`%$*;a=aT=Ffhm4Xt?G@b*;;4ftyhY!e!g~Dp2-#WH!E$~b-q7!zjy0D0|SEw z5F-OdAcqMm0HR@-!KdbB0Sic$ksKn!dTwQL zVUD_{9z;e5s8CS>2$Eq6A>tY#uE8Pk&i;OGp6;4Drj6hv0J0MqfNWuf35+HISV)jb z!{QF49mF<-nuDAK@}W5r9N{cL1+d@;MUA7rzCwO!kwQsoafw1ol0t4~dPa#tUVe!} uYDFecs4}%gN1-@hAtgUgy+om;s8XRMUm-a^FE2G2$jw*CEHQ0-z6t>O%3Fm1 literal 0 HcmV?d00001 diff --git a/test/system/.test-client-query-null.js.un~ b/test/system/.test-client-query-null.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..29d5d5e780e1ba6f892abbd3f93780eef9d018b5 GIT binary patch literal 1547 zcmWH`%$*;a=aT=FfvMR#==%Rx>&~e)Om{Y0w3A(+NUoVD^(7;xrufpI4L$)33=Dig zj0~8792TemGn5VH`_#N_VqpY|FfznnKvDo@GJrIKFc|y?0-(ZCKyC=YLlS5JC>mfO z48{OPM;$mi7#O}v00lvT4N}MtQUDi$83UqK%MyzeoO3c$^GXzK6^c>|OEZg7HPmw} ziwkqqHT57eIzWYr3P6wyQwR~)2yqP#iFfw*bMti9)G=)YCjpSDu(SeXg6(GoF+gB6 z2|&VuY!ViCAOk>bL#Ro}NuUuq34o#k7W|;(;Ha;!kY8G)P?B0)qL7lLkeivFQKFES zU!ss&kqH#4OfAt-D9%?%$@R4B<;NY2m8OHBrH^A$2npz(~H06~sGwrDh- qK_Nm3AU>WMAsHJv_(Ab33dyT_DTyVCNr}a&z}&5_Zf)B5d=&t~j%e%v literal 0 HcmV?d00001 diff --git a/test/system/.test-client-query.js.un~ b/test/system/.test-client-query.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..4479e3bc251bc5bbb914d341bbfe36caf9a4983d GIT binary patch literal 3887 zcmeH~L2DCH5XWDWSgRmdK@cf2Ld&)`w$xHD;$f4GB8Y-X>oKIsqDz}yx_K!Ed+{P3 z#DX3?dh_5%@SsP%2!h{05cLCyc+&ar?yRrUXiTmNIGCe)zzJ^ zuM2pZSM~SFfLvl>@F>0i$rAM#1G46SL?DeM&&eC})}+li?ngM3`gVdlV=_uP7?AeJ zGO#n-jgZQlp6hG6NTIvc^+I>nYWF%@o7UVy{G`YOPZLX12FCrfwMw;CFJHfQ>B{A~ z;>x`!1;i&@Lg3{<)Z$B)0uqTKZ5m0Qf6!RNOo0bx3ZQ&t5^}~~T%@2Il6E_qTI99vSpl0CvZj)~V@~}S~j}u{`)zFRgM#tsUv8)St zog@hW9iBzt8JosQbYw|@D2yP&6HAzFGYKA=Nq|f_#9CrSeV!q*$~P)@twN4nvrBfh zLe{)d%_&)_Y5+7{0WN?}v1ULKgi$1oBrgJ1N0P<1*`7z6H}>7X0iEg()F~x331s6~ zED_+GWR09~NrZ4L{t_Q$N5@#DCQmWK)qmC@pqcwVfC3^kt3w1~6d45K z(+Fa2e~6QNAv&e`r1-!ItBZhP`jO0vPr@>!9faFUbN`e>subTj9D~!-ZJ%TCzQL-etz)_1OMSU literal 0 HcmV?d00001 diff --git a/test/system/.test-client-sequential-query.js.un~ b/test/system/.test-client-sequential-query.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..e4c8846a6a56795037e4b549e56d8c0366f4a1d5 GIT binary patch literal 1966 zcmWH`%$*;a=aT=FfoUT54go{0n+Nk&v&;TJxv@Ijcfqnx#|!S<60A1tUf1Tzz`!63 z#K?dV$YDXl%pe6mH7^&ifMl5%;xB*%fPe`?fk}uIRNy}lFn~lx0eK;S9J1ixhZ++G zGY%LXbHLHT$naGHCpp`Ke= zT$rP-sRxnK0V-5f0D@$gLWsCVh-+|2ytBWbo2R>`j%gz}3Bc?GSqTClTUfy?ATgQ* zU?D*!4U0RFb`aYTY7TM|m=8_@&sk+ TFnz?w9a0`;gXuPHe7*_*W4U#Q literal 0 HcmV?d00001 diff --git a/test/system/test-client-connect.js b/test/system/test-client-connect.js index 0be5b06a7..ad36a3c2e 100644 --- a/test/system/test-client-connect.js +++ b/test/system/test-client-connect.js @@ -1,13 +1,10 @@ require('../common'); -var client = require('mysql').Client(TEST_CONFIG) - , gently = new Gently(); - -// our test db does not exist yet, so don't try to connect to it -client.database = ''; +var client = require('mysql').Client(TEST_CONFIG), + gently = new Gently(); client.connect(gently.expect(function connectCb(err, result) { if (err) throw err; assert.strictEqual(result.affectedRows, 0); client.end(); -})); \ No newline at end of file +})); diff --git a/test/system/test-client-query-calculated-fields.js b/test/system/test-client-query-calculated-fields.js index b40f6a7bc..4217351d7 100644 --- a/test/system/test-client-query-calculated-fields.js +++ b/test/system/test-client-query-calculated-fields.js @@ -1,10 +1,7 @@ require('../common'); -var Client = require('mysql').Client, - client = Client(TEST_CONFIG), +var client = require('mysql').Client(TEST_CONFIG), gently = new Gently(); -// our test db might not exist yet, so don't try to connect to it -client.database = ''; client.connect(); client.query('SELECT 1 as field_a, 2 as field_b', function(err, results) { diff --git a/test/system/test-client-query-empty.js b/test/system/test-client-query-empty.js index cb99062be..8def3a635 100644 --- a/test/system/test-client-query-empty.js +++ b/test/system/test-client-query-empty.js @@ -1,10 +1,7 @@ require('../common'); -var Client = require('mysql').Client, - client = Client(TEST_CONFIG), +var client = require('mysql').Client(TEST_CONFIG), gently = new Gently(); -// our test db might not exist yet, so don't try to connect to it -client.database = ''; client.connect(); client.query('SELECT "" as field_a', function(err, results) { diff --git a/test/system/test-client-query-long-fields.js b/test/system/test-client-query-long-fields.js index 8486d22e9..b1a7810d3 100644 --- a/test/system/test-client-query-long-fields.js +++ b/test/system/test-client-query-long-fields.js @@ -1,9 +1,7 @@ require('../common'); -var Client = require('mysql').Client, - client = Client(TEST_CONFIG), +var client = require('mysql').Client(TEST_CONFIG), gently = new Gently(); -// our test db might not exist yet, so don't try to connect to it client.connect(); function makeString(length) { diff --git a/test/system/test-client-query-null.js b/test/system/test-client-query-null.js index 4d672673e..463d98d01 100644 --- a/test/system/test-client-query-null.js +++ b/test/system/test-client-query-null.js @@ -1,10 +1,7 @@ require('../common'); -var Client = require('mysql').Client, - client = Client(TEST_CONFIG), +var client = require('mysql').Client(TEST_CONFIG), gently = new Gently(); -// our test db might not exist yet, so don't try to connect to it -client.database = ''; client.connect(); client.query('SELECT NULL as field_a, NULL as field_b', function(err, results) { diff --git a/test/system/test-client-query.js b/test/system/test-client-query.js index fd3e5c61b..54e90b678 100644 --- a/test/system/test-client-query.js +++ b/test/system/test-client-query.js @@ -3,13 +3,10 @@ var Client = require('mysql').Client, client = Client(TEST_CONFIG), gently = new Gently(); -// our test db might not exist yet, so don't try to connect to it -client.database = ''; - client.connect(); client.query( - 'CREATE DATABASE '+TEST_CONFIG.database, + 'CREATE DATABASE '+TEST_DB, gently.expect(function createDbCb(err) { if (err && err.number != Client.ERROR_DB_CREATE_EXISTS) { throw err; @@ -18,7 +15,7 @@ client.query( ); client.query( - 'USE '+TEST_CONFIG.database, + 'USE '+TEST_DB, gently.expect(function useDbCb(err) { if (err) { throw err; diff --git a/test/system/test-client-sequential-query.js b/test/system/test-client-sequential-query.js index b5049a06a..239d54944 100644 --- a/test/system/test-client-sequential-query.js +++ b/test/system/test-client-sequential-query.js @@ -1,10 +1,7 @@ require('../common'); -var Client = require('mysql').Client, - client = Client(TEST_CONFIG), +var client = require('mysql').Client(TEST_CONFIG), gently = new Gently(); -// our test db might not exist yet, so don't try to connect to it -client.database = ''; client.connect(); client.query('SELECT 1 as field_a, 2 as field_b', function(err, results) { From 4a0fb91a0387352a5a3b57699c40eba9b154275f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Tue, 31 Aug 2010 13:59:57 +0200 Subject: [PATCH 02/23] Ignore vim 7.3 undo files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b4b8eb20d..7f7017231 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.swo +*.un~ From a5013dda6fbcfeb4fcb3a256de8e2a45baec02f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Tue, 31 Aug 2010 14:01:04 +0200 Subject: [PATCH 03/23] Simple insert benchmark --- benchmark/insert.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 benchmark/insert.js diff --git a/benchmark/insert.js b/benchmark/insert.js new file mode 100644 index 000000000..6dc573461 --- /dev/null +++ b/benchmark/insert.js @@ -0,0 +1,42 @@ +require('../test/common'); +var Client = require('mysql/client'), + client = Client(TEST_CONFIG); + +client.connect(); + +client.query('CREATE DATABASE '+TEST_DB, function(err) { + if (err && err.number != Client.ERROR_DB_CREATE_EXISTS) { + throw err; + } +}); +client.query('USE '+TEST_DB); +client.query( + 'CREATE TEMPORARY TABLE '+TEST_TABLE+' ('+ + 'id INT(11) AUTO_INCREMENT, '+ + 'title VARCHAR(255), '+ + 'text TEXT, '+ + 'created DATETIME, '+ + 'PRIMARY KEY (id));', + function(err) { + if (err) throw err; + + var start = +new Date, inserts = 0, total = 10000; + console.log('performing %d inserts ...\n', total); + + function insertOne() { + client.query('INSERT INTO '+TEST_TABLE+' SET title = ?', ['super'], function() { + inserts++; + if (inserts < total) { + insertOne(); + } else { + var duration = (+new Date - start) / 1000, + insertsPerSecond = inserts / duration; + + console.log('%d inserts / second', insertsPerSecond.toFixed(2)); + client.end(); + } + }); + } + insertOne(); + } +); From 5887e9da0921c9827f3f573753716e1bcf243a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 12:55:21 +0200 Subject: [PATCH 04/23] Remove vim undo files commited by accident --- test/system/.test-client-connect.js.un~ | Bin 3760 -> 0 bytes .../.test-client-query-calculated-fields.js.un~ | Bin 2068 -> 0 bytes test/system/.test-client-query-empty.js.un~ | Bin 1547 -> 0 bytes .../system/.test-client-query-long-fields.js.un~ | Bin 1103 -> 0 bytes test/system/.test-client-query-null.js.un~ | Bin 1547 -> 0 bytes test/system/.test-client-query.js.un~ | Bin 3887 -> 0 bytes test/system/.test-client-sequential-query.js.un~ | Bin 1966 -> 0 bytes 7 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test/system/.test-client-connect.js.un~ delete mode 100644 test/system/.test-client-query-calculated-fields.js.un~ delete mode 100644 test/system/.test-client-query-empty.js.un~ delete mode 100644 test/system/.test-client-query-long-fields.js.un~ delete mode 100644 test/system/.test-client-query-null.js.un~ delete mode 100644 test/system/.test-client-query.js.un~ delete mode 100644 test/system/.test-client-sequential-query.js.un~ diff --git a/test/system/.test-client-connect.js.un~ b/test/system/.test-client-connect.js.un~ deleted file mode 100644 index 3ab1457707d91e9d84f65a6c0e5b5637ee6b5e95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3760 zcmeH}ze^lJ6vyZ8%ny~62_e<%_6|~>&yZ{F_C4Da*4GrJhCeR-2SF~3yt zWcT#bcXROdH~OM zQp<<_g`&4GcyuF-&$zir2;{cU8DJdB;ZW-MKF>YCJ)|EfX2! zvmNWij`nXBgeJal^<9l_27yR#{ZdXmA|^T z%ExWH!p`w~G(+~OV@%Egrj0(psqv|Q23vXH(k zk$EY7q#g){xdUMD+(y*>DtmAkhu>tp2#ERBicIvQNm$aC;9g$}&SR3=!p49s$J7r* Zm_wqGzQnZPFqL{r3h8(Hn%w@q^B1C|vB&@b diff --git a/test/system/.test-client-query-calculated-fields.js.un~ b/test/system/.test-client-query-calculated-fields.js.un~ deleted file mode 100644 index 156390b3d16c45e309c8025102d71022408cf592..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2068 zcmWH`%$*;a=aT=Ff$87hZOdnw-VoQC^km-z1OEj_zjw(VIP#wP|JhB?tDQRh85kIN zf!MGtu}C2~Co?s#M8Q^}D7COOvnW+VJ-4#BFh^Ze&lxPE5#kyg67THq=jQ3I3Dm>{ z(g?(iK+FQfAONCan8By!r8NskmYE^`0!S7JK$>6xB*g~f{09QCQ80l~n#v&nj1F#a zbTBY{l>nN}3dFGB2StUWzP>_!X^}!nYH^7|N|HiuW_m`6LSBA}LTW`OP^dDsL`R`G zUm+zwPrXE;q^MG%BwrypKQAve8OY67$Sg5!1jjQZ$`P&y#W~C(hS7LN1PpCh@OWm# z9?znXjINiGSdy5OSey#X@#^Z<(6|G|6)ZD@oW~5r@H{&jcc37l0Kh{MXa*=`VIT~~ z0LGmKIFB+x;trOTct8rkxfUb>GX_Mff{JcP0gb!p)&VM1Q~&~a8IPq%*MTMhWQPIu zfs+HsCQw;FntefmKnZ}w9mot2+W=}9auTqD)|&7L2So{}o(4re>2IR8HofJKlLj50|G0eDCP^}wP7 zq&*B~1~57j!O_9M@KpjR2#Ys9kOH^}%oq@@T9#O(;GC10npdJ=t5B3$SejXss-d1+ zSzMT-uBiu+(E%z{Q~-ixm_mrSMu=;0NW8PZpPQ$ sqwx$15lR4Z=;DuOMo7j+k7rRxUe!xUEJ;jCEKUXHZgq8Q)5hnk0Ol!byZ`_I diff --git a/test/system/.test-client-query-long-fields.js.un~ b/test/system/.test-client-query-long-fields.js.un~ deleted file mode 100644 index 0fb30d1c5d5f0bc97106558317b097c8fd992fac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcmWH`%$*;a=aT=Ffhm4Xt?G@b*;;4ftyhY!e!g~Dp2-#WH!E$~b-q7!zjy0D0|SEw z5F-OdAcqMm0HR@-!KdbB0Sic$ksKn!dTwQL zVUD_{9z;e5s8CS>2$Eq6A>tY#uE8Pk&i;OGp6;4Drj6hv0J0MqfNWuf35+HISV)jb z!{QF49mF<-nuDAK@}W5r9N{cL1+d@;MUA7rzCwO!kwQsoafw1ol0t4~dPa#tUVe!} uYDFecs4}%gN1-@hAtgUgy+om;s8XRMUm-a^FE2G2$jw*CEHQ0-z6t>O%3Fm1 diff --git a/test/system/.test-client-query-null.js.un~ b/test/system/.test-client-query-null.js.un~ deleted file mode 100644 index 29d5d5e780e1ba6f892abbd3f93780eef9d018b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1547 zcmWH`%$*;a=aT=FfvMR#==%Rx>&~e)Om{Y0w3A(+NUoVD^(7;xrufpI4L$)33=Dig zj0~8792TemGn5VH`_#N_VqpY|FfznnKvDo@GJrIKFc|y?0-(ZCKyC=YLlS5JC>mfO z48{OPM;$mi7#O}v00lvT4N}MtQUDi$83UqK%MyzeoO3c$^GXzK6^c>|OEZg7HPmw} ziwkqqHT57eIzWYr3P6wyQwR~)2yqP#iFfw*bMti9)G=)YCjpSDu(SeXg6(GoF+gB6 z2|&VuY!ViCAOk>bL#Ro}NuUuq34o#k7W|;(;Ha;!kY8G)P?B0)qL7lLkeivFQKFES zU!ss&kqH#4OfAt-D9%?%$@R4B<;NY2m8OHBrH^A$2npz(~H06~sGwrDh- qK_Nm3AU>WMAsHJv_(Ab33dyT_DTyVCNr}a&z}&5_Zf)B5d=&t~j%e%v diff --git a/test/system/.test-client-query.js.un~ b/test/system/.test-client-query.js.un~ deleted file mode 100644 index 4479e3bc251bc5bbb914d341bbfe36caf9a4983d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3887 zcmeH~L2DCH5XWDWSgRmdK@cf2Ld&)`w$xHD;$f4GB8Y-X>oKIsqDz}yx_K!Ed+{P3 z#DX3?dh_5%@SsP%2!h{05cLCyc+&ar?yRrUXiTmNIGCe)zzJ^ zuM2pZSM~SFfLvl>@F>0i$rAM#1G46SL?DeM&&eC})}+li?ngM3`gVdlV=_uP7?AeJ zGO#n-jgZQlp6hG6NTIvc^+I>nYWF%@o7UVy{G`YOPZLX12FCrfwMw;CFJHfQ>B{A~ z;>x`!1;i&@Lg3{<)Z$B)0uqTKZ5m0Qf6!RNOo0bx3ZQ&t5^}~~T%@2Il6E_qTI99vSpl0CvZj)~V@~}S~j}u{`)zFRgM#tsUv8)St zog@hW9iBzt8JosQbYw|@D2yP&6HAzFGYKA=Nq|f_#9CrSeV!q*$~P)@twN4nvrBfh zLe{)d%_&)_Y5+7{0WN?}v1ULKgi$1oBrgJ1N0P<1*`7z6H}>7X0iEg()F~x331s6~ zED_+GWR09~NrZ4L{t_Q$N5@#DCQmWK)qmC@pqcwVfC3^kt3w1~6d45K z(+Fa2e~6QNAv&e`r1-!ItBZhP`jO0vPr@>!9faFUbN`e>subTj9D~!-ZJ%TCzQL-etz)_1OMSU diff --git a/test/system/.test-client-sequential-query.js.un~ b/test/system/.test-client-sequential-query.js.un~ deleted file mode 100644 index e4c8846a6a56795037e4b549e56d8c0366f4a1d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1966 zcmWH`%$*;a=aT=FfoUT54go{0n+Nk&v&;TJxv@Ijcfqnx#|!S<60A1tUf1Tzz`!63 z#K?dV$YDXl%pe6mH7^&ifMl5%;xB*%fPe`?fk}uIRNy}lFn~lx0eK;S9J1ixhZ++G zGY%LXbHLHT$naGHCpp`Ke= zT$rP-sRxnK0V-5f0D@$gLWsCVh-+|2ytBWbo2R>`j%gz}3Bc?GSqTClTUfy?ATgQ* zU?D*!4U0RFb`aYTY7TM|m=8_@&sk+ TFnz?w9a0`;gXuPHe7*_*W4U#Q From aef575b5f3ddc4b99bd63668b1963bdfbb5084e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Sat, 21 Aug 2010 12:12:35 +0200 Subject: [PATCH 05/23] Initial work on porting mysql < 4.1 authentication code --- lib/mysql/auth.js | 53 +++++++++++++++++++ lib/mysql/client.js | 26 ++++++++++ lib/mysql/parser.js | 9 ++++ test/fixture/libmysql_password.c | 88 ++++++++++++++++++++++++++++++++ test/simple/test-auth.js | 12 +++++ test/simple/test-client.js | 78 +++++++++++++++++++++++++++- test/simple/test-parser.js | 14 +++++ 7 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 test/fixture/libmysql_password.c diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 09e2d6c1c..0c4c062d9 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -30,3 +30,56 @@ exports.token = function(password, scramble) { var stage3 = sha1(scramble.toString('binary') + stage2); return xor(stage3, stage1); }; + +// This is a port of sql/password.c:hash_password which needs to be used for +// pre-4.1 passwords. +exports.hashPassword = function(password) { + var nr = 1345345333, + add = 7, + nr2 = 0x12345671, + result = new Buffer(8); + + password = new Buffer(password); + for (var i = 0; i < password.length; i++) { + var c = password[i]; + if (c == 32 || c == 9) { + // skip space in password + continue; + } + + nr ^= this.multiply(((nr & 63) + add), c) + (nr << 8); + nr2 += (nr2 << 8) ^ nr; + add += c; + } + + this.int32Write(result, nr & ((1 << 31) - 1), 0); + this.int32Write(result, nr2 & ((1 << 31) - 1), 4); + + return result; +} + +// Provided by Herbert Vojčík, needed to deal with float point precision problems in JS +exports.multiply = function(x, y) { + var lowX = x & 0xffff, + highX = (x >> 16) & 0xffff, + lowY = y & 0xffff, + highY = (y >> 16) & 0xffff + result = + 0x10000 * ((highX * lowY + lowX * highY) & 0xffff) + lowY * lowX; + + //result = result & 0xffffffff; + result = result % 0x100000000; + return result; +} + +exports.int32Write = function(buffer, number, offset) { + var unsigned = (number < 0) ? (number + 0x100000000) : number; + buffer[offset] = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + buffer[offset + 1] = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + buffer[offset + 2] = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + buffer[offset + 3] = Math.floor(unsigned); +}; + diff --git a/lib/mysql/client.js b/lib/mysql/client.js index 9c9ac8bea..ab4bc2b34 100644 --- a/lib/mysql/client.js +++ b/lib/mysql/client.js @@ -194,6 +194,11 @@ Client.prototype._handlePacket = function(packet) { return; } + if (packet.type == Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET) { + this._sendOldAuth(packet); + return; + } + var type = packet.type, task = this._queue[0], delegate = (task) @@ -284,6 +289,27 @@ Client.prototype._debugPacket = function(packet) { console.log('<- %s: %j', packetName, packet); }; +Client.prototype._sendOldAuth = function(greeting) { + //var token = auth.token(this.password, greeting.scrambleBuffer), + //packetSize = ( + //4 + 4 + 1 + 23 + + //this.user.length + 1 + + //token.length + 1 + + //this.database.length + 1 + //), + //packet = new OutgoingPacket(packetSize, greeting.number+1); + + //packet.writeNumber(4, this.flags); + //packet.writeNumber(4, this.maxPacketSize); + //packet.writeNumber(1, this.charsetNumber); + //packet.writeFiller(23); + //packet.writeNullTerminated(this.user); + //packet.writeLengthCoded(token); + //packet.writeNullTerminated(this.database); + + //this.write(packet); +}; + // Client Flags Client.LONG_PASSWORD = 1; Client.FOUND_ROWS = 2; diff --git a/lib/mysql/parser.js b/lib/mysql/parser.js index 0ab523585..077a0e88f 100644 --- a/lib/mysql/parser.js +++ b/lib/mysql/parser.js @@ -12,6 +12,7 @@ function Parser() { this.state = Parser.PACKET_LENGTH; this.packet = null; this.greeted = false; + this.authenticated = false; this.receivingFieldPackets = false; this.receivingRowPackets = false; @@ -211,7 +212,14 @@ Parser.prototype.write = function(buffer) { break; } + if (c == 0xfe && !this.authenticated) { + packet.type = Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET; + break; + } + if (c === 0x00) { + // after the first OK PACKET, we are authenticated + this.authenticated = true; packet.type = Parser.OK_PACKET; advance(Parser.AFFECTED_ROWS) break; @@ -606,3 +614,4 @@ Parser.ROW_DATA_PACKET = p++; Parser.ROW_DATA_BINARY_PACKET = p++; Parser.OK_FOR_PREPARED_STATEMENT_PACKET = p++; Parser.PARAMETER_PACKET = p++; +Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET = p++; diff --git a/test/fixture/libmysql_password.c b/test/fixture/libmysql_password.c new file mode 100644 index 000000000..048d95f85 --- /dev/null +++ b/test/fixture/libmysql_password.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#define SCRAMBLE_LENGTH_323 8 + +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned char uchar; + +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + +void hash_password(ulong *result, const char *password, uint password_len) +{ + register ulong nr=1345345333L, add=7, nr2=0x12345671L; + ulong tmp; + const char *password_end= password + password_len; + for (; password < password_end; password++) + { + if (*password == ' ' || *password == '\t') + continue; /* skip space in password */ + tmp= (ulong) (uchar) *password; + nr^= (((nr & 63)+add)*tmp)+ (nr << 8); + nr2+=(nr2 << 8) ^ nr; + add+=tmp; + } + result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */; + result[1]=nr2 & (((ulong) 1L << 31) -1L); +} + +void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2) +{ /* For mysql 3.21.# */ +#ifdef HAVE_purify + bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ +#endif + rand_st->max_value= 0x3FFFFFFFL; + rand_st->max_value_dbl=(double) rand_st->max_value; + rand_st->seed1=seed1%rand_st->max_value ; + rand_st->seed2=seed2%rand_st->max_value; +} + +double my_rnd(struct rand_struct *rand_st) +{ + rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; + rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value; + return (((double) rand_st->seed1)/rand_st->max_value_dbl); +} + +void scramble_323(char *to, const char *message, const char *password) +{ + struct rand_struct rand_st; + ulong hash_pass[2], hash_message[2]; + + if (password && password[0]) + { + char extra, *to_start=to; + const char *message_end= message + SCRAMBLE_LENGTH_323; + hash_password(hash_pass,password, (uint) strlen(password)); + hash_password(hash_message, message, SCRAMBLE_LENGTH_323); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], + hash_pass[1] ^ hash_message[1]); + for (; message < message_end; message++) + *to++= (char) (floor(my_rnd(&rand_st)*31)+64); + extra=(char) (floor(my_rnd(&rand_st)*31)); + while (to_start != to) + *(to_start++)^=extra; + } + *to= 0; +} + +int main() { + const char password[] = "root"; + uint password_len = 4; + ulong result[2]; + + printf("hash_password(\"%s\"):\n", password); + + hash_password(result, password, password_len); + + printf("result 1: %ld\n", result[0]); + printf("result 2: %ld\n", result[1]); + + return 23; +} + diff --git a/test/simple/test-auth.js b/test/simple/test-auth.js index ac89dc686..3eb982355 100644 --- a/test/simple/test-auth.js +++ b/test/simple/test-auth.js @@ -45,3 +45,15 @@ test(function token() { assert.deepEqual(auth.token(null, SCRAMBLE), new Buffer(0)); })(); }); + +(function testHashPassword() { + var BUFFER; + gently.expect(auth, 'int32Write', 2, function (buffer, number, offset) { + assert.equal(number, [1732607522, 1780094397][offset / 4]); + assert.equal(buffer.length, 8); + BUFFER = buffer; + }); + + var result = auth.hashPassword('root'); + assert.strictEqual(result, BUFFER); +})(); diff --git a/test/simple/test-client.js b/test/simple/test-client.js index 7dd78c896..809e2380b 100644 --- a/test/simple/test-client.js +++ b/test/simple/test-client.js @@ -363,6 +363,16 @@ test(function _handlePacket() { client._handlePacket(PACKET); })(); + (function testUseOldPasswordProtocol() { + var PACKET = {type: Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET}; + + gently.expect(client, '_sendOldAuth', function (packet) { + assert.strictEqual(packet, PACKET); + }); + + client._handlePacket(PACKET); + })(); + (function testNormalOk() { var PACKET = {type: Parser.OK_PACKET}; @@ -437,9 +447,9 @@ test(function _handlePacket() { })(); }); -test(function _sendPacket() { +test(function _sendAuth() { var GREETING = {scrambleBuffer: new Buffer(20), number: 1}, - TOKEN = new Buffer(8), + TOKEN = new Buffer(20), PACKET; client.user = 'root'; @@ -541,3 +551,67 @@ test(function _packetToUserObject() { assert.equal(err.errorNumber, undefined); })(); }); + +test(function _sendOldAuth() { + var GREETING = {scrambleBuffer: new Buffer(20), number: 1}, + TOKEN = new Buffer(8), + PACKET; + + client.user = 'root'; + client.password = 'hello world'; + + //gently.expect(HIJACKED['./auth'], 'token', function(password, scramble) { + //assert.strictEqual(password, client.password); + //assert.strictEqual(scramble, GREETING.scrambleBuffer); + //return TOKEN; + //}); + + //gently.expect(OutgoingPacketStub, 'new', function(size, number) { + //assert.equal(size, ( + //4 + 4 + 1 + 23 + + //client.user.length + 1 + + //TOKEN.length + 1 + + //client.database.length + 1 + //)); + + //assert.equal(number, GREETING.number + 1); + //PACKET = this; + + //gently.expect(PACKET, 'writeNumber', function(bytes, number) { + //assert.strictEqual(bytes, 4); + //assert.strictEqual(client.flags, number); + //}); + + //gently.expect(PACKET, 'writeNumber', function(bytes, number) { + //assert.strictEqual(bytes, 4); + //assert.strictEqual(client.maxPacketSize, number); + //}); + + //gently.expect(PACKET, 'writeNumber', function(bytes, number) { + //assert.strictEqual(bytes, 1); + //assert.strictEqual(client.charsetNumber, number); + //}); + + //gently.expect(PACKET, 'writeFiller', function(bytes) { + //assert.strictEqual(bytes, 23); + //}); + + //gently.expect(PACKET, 'writeNullTerminated', function(user) { + //assert.strictEqual(user, client.user); + //}); + + //gently.expect(PACKET, 'writeLengthCoded', function(token) { + //assert.strictEqual(token, TOKEN); + //}); + + //gently.expect(PACKET, 'writeNullTerminated', function(database) { + //assert.strictEqual(database, client.database); + //}); + + //gently.expect(client, 'write', function(packet) { + //assert.strictEqual(packet, PACKET); + //}); + //}); + + client._sendOldAuth(GREETING); +}); diff --git a/test/simple/test-parser.js b/test/simple/test-parser.js index ccdc9d00e..9ea60161d 100644 --- a/test/simple/test-parser.js +++ b/test/simple/test-parser.js @@ -15,6 +15,7 @@ test(function constructor() { assert.strictEqual(parser.state, Parser.PACKET_LENGTH); assert.strictEqual(parser.packet, null); assert.strictEqual(parser.greeted, false); + assert.strictEqual(parser.authenticated, false); assert.strictEqual(parser.receivingFieldPackets, false); assert.strictEqual(parser.receivingRowPackets, false); assert.strictEqual(parser._lengthCodedLength, null); @@ -114,6 +115,18 @@ test(function write() { assert.strictEqual(parser.packet, null); })(); + (function testUseOldPasswordProtocolPacket() { + parser.write(new Buffer([1, 0, 0, 1])); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(val.type, Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET); + }); + + parser.write(new Buffer([254])); + })(); + + (function testErrorPacket() { parser.write(new Buffer([12, 0, 0, 1])); assert.equal(parser.state, Parser.FIELD_COUNT); @@ -151,6 +164,7 @@ test(function write() { parser.write(new Buffer([0x00])); assert.equal(packet.type, Parser.OK_PACKET); + assert.equal(parser.authenticated, true); assert.equal(parser.state, Parser.AFFECTED_ROWS); parser.write(new Buffer([252, 17, 23])); From 59dc8423de6a4568011d9570a98a52f93b50361c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Mon, 23 Aug 2010 14:40:57 +0200 Subject: [PATCH 06/23] Use improved multiply function See https://gist.github.com/d4f70ded68e0d79c3eab --- lib/mysql/auth.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 0c4c062d9..da6d317c1 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -59,17 +59,12 @@ exports.hashPassword = function(password) { } // Provided by Herbert Vojčík, needed to deal with float point precision problems in JS -exports.multiply = function(x, y) { - var lowX = x & 0xffff, - highX = (x >> 16) & 0xffff, - lowY = y & 0xffff, - highY = (y >> 16) & 0xffff - result = - 0x10000 * ((highX * lowY + lowX * highY) & 0xffff) + lowY * lowX; +exports.multiply = function(a, b) { + var a1 = a >>> 16, + a2 = a & 0xffff; + // Precondition: b is in 32bit range - //result = result & 0xffffffff; - result = result % 0x100000000; - return result; + return ((a1 * b << 16) + a2 * b) >>> 0; } exports.int32Write = function(buffer, number, offset) { From ff657862e606b5ea45c71483530a9334ba256d3a Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 15:56:48 -0500 Subject: [PATCH 07/23] test a few rounds of the hashPassword function. looks to be buggy right now --- test/fixture/libmysql_password.c | 15 +++++++++------ test/simple/test-auth-old.js | 13 +++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 test/simple/test-auth-old.js diff --git a/test/fixture/libmysql_password.c b/test/fixture/libmysql_password.c index 048d95f85..29dc545d9 100644 --- a/test/fixture/libmysql_password.c +++ b/test/fixture/libmysql_password.c @@ -72,16 +72,19 @@ void scramble_323(char *to, const char *message, const char *password) } int main() { - const char password[] = "root"; - uint password_len = 4; + const char password1[] = "root"; + const char password2[] = "long password test"; + const char password3[] = "saf789yasfbsd89f"; ulong result[2]; - printf("hash_password(\"%s\"):\n", password); + hash_password((ulong*)result, password1, strlen(password1)); + printf("hash_password(\"%s\") = %08x%08x\n", password1, result[0], result[1]); - hash_password(result, password, password_len); + hash_password((ulong*)result, password2, strlen(password2)); + printf("hash_password(\"%s\") = %08x%08x\n", password2, result[0], result[1]); - printf("result 1: %ld\n", result[0]); - printf("result 2: %ld\n", result[1]); + hash_password((ulong*)result, password3, strlen(password3)); + printf("hash_password(\"%s\") = %08x%08x\n", password3, result[0], result[1]); return 23; } diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js new file mode 100644 index 000000000..c0eea4bf3 --- /dev/null +++ b/test/simple/test-auth-old.js @@ -0,0 +1,13 @@ +require('../common'); + +var auth = require('mysql/auth'); + +function test_hash_password(password, bytes){ + var expected = new Buffer(bytes); + var actual = auth.hashPassword(password); + assert.deepEqual(actual, expected); // , 'hashPassword('+password+') failed'); +} + +test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); +test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); +test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); From 4cc30d31fbaac40d9d41a40bf1a542b9dbacfadb Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 16:02:21 -0500 Subject: [PATCH 08/23] let's see which one is failing --- test/simple/test-auth-old.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js index c0eea4bf3..241ddf9c2 100644 --- a/test/simple/test-auth-old.js +++ b/test/simple/test-auth-old.js @@ -1,11 +1,15 @@ require('../common'); +var sys = require('sys'); var auth = require('mysql/auth'); function test_hash_password(password, bytes){ var expected = new Buffer(bytes); var actual = auth.hashPassword(password); + + sys.print('hashPassword('+password+')...'); assert.deepEqual(actual, expected); // , 'hashPassword('+password+') failed'); + sys.print('ok\n'); } test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); From 7c06248a4c9178a2cb9580b12f59e1ac9346b4dc Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 17:54:35 -0500 Subject: [PATCH 09/23] made password hashing function work by only doing 16bit operations --- lib/mysql/auth.js | 129 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index da6d317c1..d3a7ffd08 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -34,30 +34,113 @@ exports.token = function(password, scramble) { // This is a port of sql/password.c:hash_password which needs to be used for // pre-4.1 passwords. exports.hashPassword = function(password) { - var nr = 1345345333, - add = 7, - nr2 = 0x12345671, - result = new Buffer(8); - - password = new Buffer(password); - for (var i = 0; i < password.length; i++) { - var c = password[i]; - if (c == 32 || c == 9) { - // skip space in password - continue; - } - - nr ^= this.multiply(((nr & 63) + add), c) + (nr << 8); - nr2 += (nr2 << 8) ^ nr; - add += c; - } - this.int32Write(result, nr & ((1 << 31) - 1), 0); - this.int32Write(result, nr2 & ((1 << 31) - 1), 4); + var nr = [0x5030, 0x5735]; + var add = 7; + var nr2 = [0x1234, 0x5671]; + var result = new Buffer(8); - return result; + password = new Buffer(password); + for (var i = 0; i < password.length; i++) { + var c = password[i]; + if (c == 32 || c == 9) { + // skip space in password + continue; + } + + // nr^= (((nr & 63)+add)*c)+ (nr << 8); + // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8))) + nr = this.xor32( + nr, + this.add32( + this.mul32( + this.add32( + this.and32(nr, [0,63]), + [0,add] + ), + [0,c] + ), + this.shl32(nr, 8) + ) + ); + + // nr2+=(nr2 << 8) ^ nr; + // nr2 = add(nr2, xor(shl(nr2, 8), nr)) + nr2 = this.add32(nr2, this.xor32(this.shl32(nr2, 8), nr)); + + // add+=tmp; + add += c; + } + + this.int32Write2(result, nr, 0); + this.int32Write2(result, nr2, 4); + + return result; +} + +exports.fmt32 = function(x){ + var a = x[0].toString(16); + var b = x[1].toString(16); + + if (a.length == 1) a = "000"+a; + if (a.length == 2) a = "00"+a; + if (a.length == 3) a = "0"+a; + if (b.length == 1) b = "000"+b; + if (b.length == 2) b = "00"+b; + if (b.length == 3) b = "0"+b; + return "" + a + '/' + b; +} + +exports.xor32 = function(a,b){ + return [a[0] ^ b[0], a[1] ^ b[1]]; +} + +exports.add32 = function(a,b){ + + var low = a[1] + b[1]; + var rem = (low & 0xFFFF0000) >> 16; + var high = a[0] + b[0] + rem; + + return [high & 0xFFFF, low & 0xFFFF]; +} + +exports.mul32 = function(a,b){ + + var x = a[1] * b[1]; + var y = a[0] * b[1]; + var z = a[1] * b[0]; + var w = a[0] * b[0]; + + var col1 = x & 0xFFFF; + var col2 = ((x >> 16) & 0xFFFF) + (y & 0xFFFF) + (z & 0xFFFF); + var col3 = ((y >> 16) & 0xFFFF) + ((z >> 16) & 0xFFFF) + (w & 0xFFFF); + var col4 = ((w >> 16) & 0xFFFF); + + var w1 = col1; + var w2 = col2 & 0xFFFF; + var col2_over = ((col2 >> 16) & 0xFFFF); + var w3 = (col3 + col2_over) & 0xFFFF; + var col3_over = ((w3 >> 16) & 0xFFFF); + var w4 = (col4 + col3_over) & 0xFFFF; + + return [w2, w1]; } +exports.and32 = function(a,b){ + return [a[0] & b[0], a[1] & b[1]] +} + +exports.shl32 = function(a,b){ + // assume b is 16 or less + var low = a[1] << b; + var rem = (low & 0xFFFF0000) >> 16; + var high = (a[0] << b) | rem; + + return [high & 0xFFFF, low & 0xFFFF]; +} + + + // Provided by Herbert Vojčík, needed to deal with float point precision problems in JS exports.multiply = function(a, b) { var a1 = a >>> 16, @@ -78,3 +161,9 @@ exports.int32Write = function(buffer, number, offset) { buffer[offset + 3] = Math.floor(unsigned); }; +exports.int32Write2 = function(buffer, number, offset) { + buffer[offset] = (number[0] >> 8) & 0x7F; + buffer[offset+1] = (number[0]) & 0xFF; + buffer[offset+2] = (number[1] >> 8) & 0xFF; + buffer[offset+3] = (number[1]) & 0xFF; +}; From 45a240a649cfef91726367cbdeea28b0dcc6ebca Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 18:00:57 -0500 Subject: [PATCH 10/23] cleanup --- lib/mysql/auth.js | 72 ++++++++++------------------------------------- 1 file changed, 15 insertions(+), 57 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index d3a7ffd08..2fb3ebead 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -50,19 +50,7 @@ exports.hashPassword = function(password) { // nr^= (((nr & 63)+add)*c)+ (nr << 8); // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8))) - nr = this.xor32( - nr, - this.add32( - this.mul32( - this.add32( - this.and32(nr, [0,63]), - [0,add] - ), - [0,c] - ), - this.shl32(nr, 8) - ) - ); + nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0,63]), [0,add]), [0,c]), this.shl32(nr, 8))); // nr2+=(nr2 << 8) ^ nr; // nr2 = add(nr2, xor(shl(nr2, 8), nr)) @@ -72,8 +60,8 @@ exports.hashPassword = function(password) { add += c; } - this.int32Write2(result, nr, 0); - this.int32Write2(result, nr2, 4); + this.int31Write(result, nr, 0); + this.int31Write(result, nr2, 4); return result; } @@ -96,34 +84,17 @@ exports.xor32 = function(a,b){ } exports.add32 = function(a,b){ - - var low = a[1] + b[1]; - var rem = (low & 0xFFFF0000) >> 16; - var high = a[0] + b[0] + rem; - - return [high & 0xFFFF, low & 0xFFFF]; + var w1 = a[1] + b[1]; + var w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.mul32 = function(a,b){ - - var x = a[1] * b[1]; - var y = a[0] * b[1]; - var z = a[1] * b[0]; - var w = a[0] * b[0]; - - var col1 = x & 0xFFFF; - var col2 = ((x >> 16) & 0xFFFF) + (y & 0xFFFF) + (z & 0xFFFF); - var col3 = ((y >> 16) & 0xFFFF) + ((z >> 16) & 0xFFFF) + (w & 0xFFFF); - var col4 = ((w >> 16) & 0xFFFF); - - var w1 = col1; - var w2 = col2 & 0xFFFF; - var col2_over = ((col2 >> 16) & 0xFFFF); - var w3 = (col3 + col2_over) & 0xFFFF; - var col3_over = ((w3 >> 16) & 0xFFFF); - var w4 = (col4 + col3_over) & 0xFFFF; - - return [w2, w1]; + // based on this example of multiplying 32b ints using 16b + // http://www.dsprelated.com/showmessage/89790/1.php + var w1 = a[1] * b[1]; + var w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.and32 = function(a,b){ @@ -132,22 +103,9 @@ exports.and32 = function(a,b){ exports.shl32 = function(a,b){ // assume b is 16 or less - var low = a[1] << b; - var rem = (low & 0xFFFF0000) >> 16; - var high = (a[0] << b) | rem; - - return [high & 0xFFFF, low & 0xFFFF]; -} - - - -// Provided by Herbert Vojčík, needed to deal with float point precision problems in JS -exports.multiply = function(a, b) { - var a1 = a >>> 16, - a2 = a & 0xffff; - // Precondition: b is in 32bit range - - return ((a1 * b << 16) + a2 * b) >>> 0; + var w1 = a[1] << b; + var w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.int32Write = function(buffer, number, offset) { @@ -161,7 +119,7 @@ exports.int32Write = function(buffer, number, offset) { buffer[offset + 3] = Math.floor(unsigned); }; -exports.int32Write2 = function(buffer, number, offset) { +exports.int31Write = function(buffer, number, offset) { buffer[offset] = (number[0] >> 8) & 0x7F; buffer[offset+1] = (number[0]) & 0xFF; buffer[offset+2] = (number[1] >> 8) & 0xFF; From 8ab6841af6856479431e83ad675c3020a54c72bc Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 18:08:03 -0500 Subject: [PATCH 11/23] these functions will be next --- lib/mysql/auth.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 2fb3ebead..6c5bf7252 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -64,7 +64,23 @@ exports.hashPassword = function(password) { this.int31Write(result, nr2, 4); return result; -} +}; + +exports.randomInit = function(rand_struct, seed1, seed2) { + + rand_struct = { + max_value : 0x3FFFFFFFL, + max_value_dbl : 0x3FFFFFFFL, + seed1 : seed1 % 0x3FFFFFFFL, + seed2 : seed1 % 0x3FFFFFFFL, + }; +}; + +exports.myRnd = function(rand_struct) { +}; + +exports.scramble323 = function(message, password) { +}; exports.fmt32 = function(x){ var a = x[0].toString(16); From 274280bd7d26beef3ac809e9ae6b70ec5bf11dec Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 18:25:14 -0500 Subject: [PATCH 12/23] fixtures and test for randomInit --- lib/mysql/auth.js | 12 ++++++------ test/fixture/libmysql_password.c | 17 +++++++++++++++++ test/simple/test-auth-old.js | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 6c5bf7252..44d37c0c3 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -66,13 +66,13 @@ exports.hashPassword = function(password) { return result; }; -exports.randomInit = function(rand_struct, seed1, seed2) { +exports.randomInit = function(seed1, seed2) { - rand_struct = { - max_value : 0x3FFFFFFFL, - max_value_dbl : 0x3FFFFFFFL, - seed1 : seed1 % 0x3FFFFFFFL, - seed2 : seed1 % 0x3FFFFFFFL, + return { + max_value : 0x3FFFFFFF, + max_value_dbl : 0x3FFFFFFF, + seed1 : seed1 % 0x3FFFFFFF, + seed2 : seed2 % 0x3FFFFFFF, }; }; diff --git a/test/fixture/libmysql_password.c b/test/fixture/libmysql_password.c index 29dc545d9..de86402bc 100644 --- a/test/fixture/libmysql_password.c +++ b/test/fixture/libmysql_password.c @@ -76,7 +76,9 @@ int main() { const char password2[] = "long password test"; const char password3[] = "saf789yasfbsd89f"; ulong result[2]; + struct rand_struct rand_st; + // test hash_password hash_password((ulong*)result, password1, strlen(password1)); printf("hash_password(\"%s\") = %08x%08x\n", password1, result[0], result[1]); @@ -86,6 +88,21 @@ int main() { hash_password((ulong*)result, password3, strlen(password3)); printf("hash_password(\"%s\") = %08x%08x\n", password3, result[0], result[1]); + + // test randominit + randominit(&rand_st, 0, 0); + printf("randominit(0x00000000,0x00000000) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + randominit(&rand_st, 0xFFFF, 0xFFFF); + printf("randominit(0x0000FFFF,0x0000FFFF) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + randominit(&rand_st, 0x50000000, 0x50000000); + printf("randominit(0x50000000,0x50000000) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + randominit(&rand_st, 0xFFFFFFFF, 0xFFFFFFFF); + printf("randominit(0xFFFFFFFF,0xFFFFFFFF) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + return 23; } diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js index 241ddf9c2..ed841e124 100644 --- a/test/simple/test-auth-old.js +++ b/test/simple/test-auth-old.js @@ -12,6 +12,21 @@ function test_hash_password(password, bytes){ sys.print('ok\n'); } +function test_randominit(in1, in2, out1, out2){ + var r = auth.randomInit(in1, in2); + sys.print('randomInit('+in1+','+in2+')...'); + assert.equal(out1, r.seed1); + assert.equal(out2, r.seed2); + sys.print('ok\n'); +} + test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); + + +test_randominit(0x00000000, 0x00000000, 0x00000000, 0x00000000); +test_randominit(0x0000FFFF, 0x0000FFFF, 0x0000ffff, 0x0000ffff); +test_randominit(0x50000000, 0x50000000, 0x10000001, 0x10000001); +test_randominit(0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000003); + From 0ee929bc403bb1ec61e7f5402c7a488bdcb54f60 Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 18:49:49 -0500 Subject: [PATCH 13/23] implementation, fixtures and tests for myRnd() --- lib/mysql/auth.js | 7 ++++++- test/fixture/libmysql_password.c | 8 ++++++++ test/simple/test-auth-old.js | 35 +++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 44d37c0c3..55160ac6d 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -76,7 +76,12 @@ exports.randomInit = function(seed1, seed2) { }; }; -exports.myRnd = function(rand_struct) { +exports.myRnd = function(r){ + + r.seed1 = (r.seed1 * 3 + r.seed2) % r.max_value; + r.seed2 = (r.seed1 + r.seed2 + 33) % r.max_value; + + return r.seed1 / r.max_value_dbl; }; exports.scramble323 = function(message, password) { diff --git a/test/fixture/libmysql_password.c b/test/fixture/libmysql_password.c index de86402bc..a4a72040a 100644 --- a/test/fixture/libmysql_password.c +++ b/test/fixture/libmysql_password.c @@ -77,6 +77,7 @@ int main() { const char password3[] = "saf789yasfbsd89f"; ulong result[2]; struct rand_struct rand_st; + int i; // test hash_password hash_password((ulong*)result, password1, strlen(password1)); @@ -103,6 +104,13 @@ int main() { printf("randominit(0xFFFFFFFF,0xFFFFFFFF) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + // test my_rnd + randominit(&rand_st, 3252345, 7149734); + printf("randominit(3252345, 7149734) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + for (i=0; i<10; i++){ + printf("my_rnd() : %.16f\n", my_rnd(&rand_st)); + } + return 23; } diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js index ed841e124..1e581baa0 100644 --- a/test/simple/test-auth-old.js +++ b/test/simple/test-auth-old.js @@ -20,13 +20,46 @@ function test_randominit(in1, in2, out1, out2){ sys.print('ok\n'); } +function test_myrnd_sequence(seed1, seed2, expected){ + + var r = auth.randomInit(seed1, seed2); + + for(var i=0; i'+a.substr(1, 16)+'...'); + assert.equal(a.substr(1, 16), b.substr(1, 16)); + sys.print('ok\n'); + } +} + test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); - test_randominit(0x00000000, 0x00000000, 0x00000000, 0x00000000); test_randominit(0x0000FFFF, 0x0000FFFF, 0x0000ffff, 0x0000ffff); test_randominit(0x50000000, 0x50000000, 0x10000001, 0x10000001); test_randominit(0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000003); +test_randominit(3252345, 7149734, 0x0031a079, 0x006d18a6); + +test_myrnd_sequence(3252345, 7149734, [ + 0.0157456556481734, + 0.0696413620092360, + 0.3009698738353047, + 0.2959253138824602, + 0.5767169786400320, + 0.9958089822864243, + 0.2488940062456708, + 0.2570431151027261, + 0.5385335875102631, + 0.9215386229767824, +]); From f920b2b2c49d075081d0c9671f8592c7976e8f1c Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 19:34:46 -0500 Subject: [PATCH 14/23] partially working scramble323 - the hashes and randominit work. slow progress --- lib/mysql/auth.js | 32 +++++++++++++++++++++++++++++++- test/fixture/libmysql_password.c | 14 ++++++++++++++ test/simple/test-auth-old.js | 5 ++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 55160ac6d..27a7be726 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -40,7 +40,10 @@ exports.hashPassword = function(password) { var nr2 = [0x1234, 0x5671]; var result = new Buffer(8); - password = new Buffer(password); + if (typeof password == 'string'){ + password = new Buffer(password); + } + for (var i = 0; i < password.length; i++) { var c = password[i]; if (c == 32 || c == 9) { @@ -85,6 +88,26 @@ exports.myRnd = function(r){ }; exports.scramble323 = function(message, password) { + + if (!password) return new Buffer(); + var to = new Buffer(8); + + var hash_pass = this.hashPassword(password); + var hash_message = this.hashPassword(message.slice(0, 8)); +console.log(hash_pass); +console.log(hash_message); + + var seed1 = this.int32Read(hash_pass, 0) ^ this.int32Read(hash_message, 0); + var seed2 = this.int32Read(hash_pass, 4) ^ this.int32Read(hash_message, 4); + var r = this.randomInit(seed1, seed2); + +console.log(r); + + for (var i=0; i<8; i++){ + to[i] = Math.floor(this.myRnd(r)*31) + 64; + } + + return to; }; exports.fmt32 = function(x){ @@ -146,3 +169,10 @@ exports.int31Write = function(buffer, number, offset) { buffer[offset+2] = (number[1] >> 8) & 0xFF; buffer[offset+3] = (number[1]) & 0xFF; }; + +exports.int32Read = function(buffer, offset){ + return (buffer[offset] << 24) + + (buffer[offset+1] << 16) + + (buffer[offset+2] << 8) + + (buffer[offset+3]); +}; diff --git a/test/fixture/libmysql_password.c b/test/fixture/libmysql_password.c index a4a72040a..9c26d0ca8 100644 --- a/test/fixture/libmysql_password.c +++ b/test/fixture/libmysql_password.c @@ -60,8 +60,16 @@ void scramble_323(char *to, const char *message, const char *password) const char *message_end= message + SCRAMBLE_LENGTH_323; hash_password(hash_pass,password, (uint) strlen(password)); hash_password(hash_message, message, SCRAMBLE_LENGTH_323); + +printf("hash_pass = %08x%08x\n", hash_pass[0], hash_pass[1]); +printf("hash_message = %08x%08x\n", hash_message[0], hash_message[1]); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]); + +printf("rs.seed1: %d\n", rand_st.seed1); +printf("rs.seed2: %d\n", rand_st.seed2); + for (; message < message_end; message++) *to++= (char) (floor(my_rnd(&rand_st)*31)+64); extra=(char) (floor(my_rnd(&rand_st)*31)); @@ -76,6 +84,7 @@ int main() { const char password2[] = "long password test"; const char password3[] = "saf789yasfbsd89f"; ulong result[2]; + char scrm[9]; // SCRAMBLE_LENGTH_323+1 struct rand_struct rand_st; int i; @@ -111,6 +120,11 @@ int main() { printf("my_rnd() : %.16f\n", my_rnd(&rand_st)); } + + // test scramble_323 + scramble_323(scrm, "8bytesofstuff", "root"); + printf("scramble: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", scrm[0], scrm[1], scrm[2], scrm[3], scrm[4], scrm[5], scrm[6], scrm[7], scrm[8]); + return 23; } diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js index 1e581baa0..a383a1c54 100644 --- a/test/simple/test-auth-old.js +++ b/test/simple/test-auth-old.js @@ -60,6 +60,9 @@ test_myrnd_sequence(3252345, 7149734, [ 0.2488940062456708, 0.2570431151027261, 0.5385335875102631, - 0.9215386229767824, + 0.9215386229767824, ]); + +var b = auth.scramble323(new Buffer("8bytesofstuff"), "root"); +console.log(b); From 7bc90da59974d99f9a1272ac378f925cb5894ac2 Mon Sep 17 00:00:00 2001 From: Cal Henderson Date: Wed, 1 Sep 2010 19:44:22 -0500 Subject: [PATCH 15/23] cleanup and more tests --- lib/mysql/auth.js | 9 +++++---- test/fixture/libmysql_password.c | 15 ++++++--------- test/simple/test-auth-old.js | 14 +++++++++++--- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 27a7be726..f8f47e2dd 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -94,18 +94,19 @@ exports.scramble323 = function(message, password) { var hash_pass = this.hashPassword(password); var hash_message = this.hashPassword(message.slice(0, 8)); -console.log(hash_pass); -console.log(hash_message); var seed1 = this.int32Read(hash_pass, 0) ^ this.int32Read(hash_message, 0); var seed2 = this.int32Read(hash_pass, 4) ^ this.int32Read(hash_message, 4); var r = this.randomInit(seed1, seed2); -console.log(r); - for (var i=0; i<8; i++){ to[i] = Math.floor(this.myRnd(r)*31) + 64; } + var extra = (Math.floor(this.myRnd(r)*31)); + + for (var i=0; i<8; i++){ + to[i] ^= extra; + } return to; }; diff --git a/test/fixture/libmysql_password.c b/test/fixture/libmysql_password.c index 9c26d0ca8..3e19c83eb 100644 --- a/test/fixture/libmysql_password.c +++ b/test/fixture/libmysql_password.c @@ -60,16 +60,8 @@ void scramble_323(char *to, const char *message, const char *password) const char *message_end= message + SCRAMBLE_LENGTH_323; hash_password(hash_pass,password, (uint) strlen(password)); hash_password(hash_message, message, SCRAMBLE_LENGTH_323); - -printf("hash_pass = %08x%08x\n", hash_pass[0], hash_pass[1]); -printf("hash_message = %08x%08x\n", hash_message[0], hash_message[1]); - randominit(&rand_st,hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]); - -printf("rs.seed1: %d\n", rand_st.seed1); -printf("rs.seed2: %d\n", rand_st.seed2); - for (; message < message_end; message++) *to++= (char) (floor(my_rnd(&rand_st)*31)+64); extra=(char) (floor(my_rnd(&rand_st)*31)); @@ -123,7 +115,12 @@ int main() { // test scramble_323 scramble_323(scrm, "8bytesofstuff", "root"); - printf("scramble: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", scrm[0], scrm[1], scrm[2], scrm[3], scrm[4], scrm[5], scrm[6], scrm[7], scrm[8]); + printf("scramble323(8bytesofstuff, root): %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + scrm[0], scrm[1], scrm[2], scrm[3], scrm[4], scrm[5], scrm[6], scrm[7], scrm[8]); + + scramble_323(scrm, "e8cf00cec9ec825af22", "saf789yasfbsd"); + printf("scramble323(e8cf00cec9ec825af22, saf789yasfbsd): %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + scrm[0], scrm[1], scrm[2], scrm[3], scrm[4], scrm[5], scrm[6], scrm[7], scrm[8]); return 23; } diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js index a383a1c54..6c26e1bd4 100644 --- a/test/simple/test-auth-old.js +++ b/test/simple/test-auth-old.js @@ -40,6 +40,15 @@ function test_myrnd_sequence(seed1, seed2, expected){ } } +function test_scramble323(message, password, bytes){ + var expected = new Buffer(bytes); + var actual = auth.scramble323(new Buffer(message), password); + + sys.print('test_scramble323('+message+', '+password+')...'); + assert.deepEqual(actual, expected); + sys.print('ok\n'); +} + test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); @@ -63,6 +72,5 @@ test_myrnd_sequence(3252345, 7149734, [ 0.9215386229767824, ]); - -var b = auth.scramble323(new Buffer("8bytesofstuff"), "root"); -console.log(b); +test_scramble323("8bytesofstuff", "root", [0x5a, 0x4d, 0x46, 0x47, 0x43, 0x53, 0x58, 0x5f]); +test_scramble323("e8cf00cec9ec825af22", "saf789yasfbsd", [0x4d, 0x54, 0x5b, 0x47, 0x5f, 0x52, 0x4d, 0x45]); From fff1c0ad2961663e331398c402ea744aa8592de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 13:08:47 +0200 Subject: [PATCH 16/23] Remove old hashPassword test --- test/simple/test-auth.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/simple/test-auth.js b/test/simple/test-auth.js index 3eb982355..ac89dc686 100644 --- a/test/simple/test-auth.js +++ b/test/simple/test-auth.js @@ -45,15 +45,3 @@ test(function token() { assert.deepEqual(auth.token(null, SCRAMBLE), new Buffer(0)); })(); }); - -(function testHashPassword() { - var BUFFER; - gently.expect(auth, 'int32Write', 2, function (buffer, number, offset) { - assert.equal(number, [1732607522, 1780094397][offset / 4]); - assert.equal(buffer.length, 8); - BUFFER = buffer; - }); - - var result = auth.hashPassword('root'); - assert.strictEqual(result, BUFFER); -})(); From 246d1f18c9fa49f4156e2384a2d76ff6b25a14ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:17:00 +0200 Subject: [PATCH 17/23] Script for sniffing mysql traffic --- tool/pcap-mysql.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 tool/pcap-mysql.js diff --git a/tool/pcap-mysql.js b/tool/pcap-mysql.js new file mode 100755 index 000000000..7810b0e8d --- /dev/null +++ b/tool/pcap-mysql.js @@ -0,0 +1,48 @@ +#!/usr/bin/env node + +var sys = require("sys"), + pcap = require("pcap"), + mysqlPort = parseInt(process.argv[3]) || 3306, + pcap_session = pcap.createSession(process.argv[2] || '', 'tcp port '+mysqlPort); + +sys.puts('This tool allows to reverse engineer the mysql procotocol using node-pcap.'); +sys.puts(''); +sys.puts('Available devices (active one is denoted by *):'); + +// Print all devices, currently listening device prefixed with an asterisk +pcap_session.findalldevs().forEach(function (dev) { + sys.print(' '); + if (pcap_session.device_name === dev.name) { + sys.print("* "); + } + sys.print(dev.name + " "); + if (dev.addresses.length > 0) { + dev.addresses.forEach(function (address) { + sys.print(address.addr + "/" + address.netmask); + }); + sys.print("\n"); + } else { + sys.print("no address\n"); + } +}); + +sys.puts(''); +sys.puts('Execute `./pcap-mysql.js ` to listen on another device.'); +sys.puts(''); + +// Listen for packets, decode them, and feed the simple printer. No tricks. +pcap_session.on('packet', function (raw_packet) { + var packet = pcap.decode.packet(raw_packet); + //sys.puts(pcap.print.packet(packet)); + var tcp = packet.link.ip.tcp; + if (!tcp.data) { + return; + } + + if (tcp.sport == mysqlPort) { + sys.puts('<- '+tcp.data.inspect()); + } else { + sys.puts('-> '+tcp.data.inspect()); + } +}); + From d4c697050955f9eabe439c3a704376ad05a5e36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:29:13 +0200 Subject: [PATCH 18/23] Wire up _sendOldAuth --- lib/mysql/auth.js | 2 +- lib/mysql/client.js | 36 ++++++++-------- test/simple/test-client.js | 85 ++++++++++++++------------------------ 3 files changed, 48 insertions(+), 75 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index f8f47e2dd..2c28b0b88 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -89,7 +89,7 @@ exports.myRnd = function(r){ exports.scramble323 = function(message, password) { - if (!password) return new Buffer(); + if (!password) return new Buffer(); // @todo, this fails, needs fixing var to = new Buffer(8); var hash_pass = this.hashPassword(password); diff --git a/lib/mysql/client.js b/lib/mysql/client.js index ab4bc2b34..aecf3042a 100644 --- a/lib/mysql/client.js +++ b/lib/mysql/client.js @@ -26,6 +26,7 @@ function Client(config) { this.charsetNumber = 8; this.debug = false; + this._greeting = null; this._queue = []; this._connection = null; this._parser = null; @@ -195,7 +196,7 @@ Client.prototype._handlePacket = function(packet) { } if (packet.type == Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET) { - this._sendOldAuth(packet); + this._sendOldAuth(this._greeting); return; } @@ -244,6 +245,11 @@ Client.prototype._sendAuth = function(greeting) { packet.writeNullTerminated(this.database); this.write(packet); + + // Keep a reference to the greeting packet. We might receive a + // USE_OLD_PASSWORD_PROTOCOL_PACKET as a response, in which case we will need + // the greeting packet again. See _sendOldAuth() + this._greeting = greeting; }; Client._packetToUserObject = function(packet) { @@ -290,24 +296,16 @@ Client.prototype._debugPacket = function(packet) { }; Client.prototype._sendOldAuth = function(greeting) { - //var token = auth.token(this.password, greeting.scrambleBuffer), - //packetSize = ( - //4 + 4 + 1 + 23 + - //this.user.length + 1 + - //token.length + 1 + - //this.database.length + 1 - //), - //packet = new OutgoingPacket(packetSize, greeting.number+1); - - //packet.writeNumber(4, this.flags); - //packet.writeNumber(4, this.maxPacketSize); - //packet.writeNumber(1, this.charsetNumber); - //packet.writeFiller(23); - //packet.writeNullTerminated(this.user); - //packet.writeLengthCoded(token); - //packet.writeNullTerminated(this.database); - - //this.write(packet); + var token = auth.scramble323(greeting.scrambleBuffer, this.password), + packetSize = ( + token.length + 1 + ), + packet = new OutgoingPacket(packetSize, greeting.number+3); + + packet.write(token); + packet.writeFiller(1); + + this.write(packet); }; // Client Flags diff --git a/test/simple/test-client.js b/test/simple/test-client.js index 809e2380b..7ab26c949 100644 --- a/test/simple/test-client.js +++ b/test/simple/test-client.js @@ -34,6 +34,7 @@ test(function constructor() { assert.strictEqual(client.maxPacketSize, 0x01000000); assert.strictEqual(client.charsetNumber, 8); + assert.strictEqual(client._greeting, null); assert.deepEqual(client._queue, []); assert.strictEqual(client._connection, null); assert.strictEqual(client._parser, null); @@ -364,10 +365,11 @@ test(function _handlePacket() { })(); (function testUseOldPasswordProtocol() { + client._greeting = {}; var PACKET = {type: Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET}; - gently.expect(client, '_sendOldAuth', function (packet) { - assert.strictEqual(packet, PACKET); + gently.expect(client, '_sendOldAuth', function (greeting) { + assert.strictEqual(greeting, client._greeting); }); client._handlePacket(PACKET); @@ -510,6 +512,7 @@ test(function _sendAuth() { }); client._sendAuth(GREETING); + assert.strictEqual(client._greeting, GREETING); }); test(function _packetToUserObject() { @@ -553,65 +556,37 @@ test(function _packetToUserObject() { }); test(function _sendOldAuth() { - var GREETING = {scrambleBuffer: new Buffer(20), number: 1}, + var GREETING = {scrambleBuffer: new Buffer(8), number: 1}, TOKEN = new Buffer(8), PACKET; client.user = 'root'; client.password = 'hello world'; - //gently.expect(HIJACKED['./auth'], 'token', function(password, scramble) { - //assert.strictEqual(password, client.password); - //assert.strictEqual(scramble, GREETING.scrambleBuffer); - //return TOKEN; - //}); - - //gently.expect(OutgoingPacketStub, 'new', function(size, number) { - //assert.equal(size, ( - //4 + 4 + 1 + 23 + - //client.user.length + 1 + - //TOKEN.length + 1 + - //client.database.length + 1 - //)); - - //assert.equal(number, GREETING.number + 1); - //PACKET = this; - - //gently.expect(PACKET, 'writeNumber', function(bytes, number) { - //assert.strictEqual(bytes, 4); - //assert.strictEqual(client.flags, number); - //}); - - //gently.expect(PACKET, 'writeNumber', function(bytes, number) { - //assert.strictEqual(bytes, 4); - //assert.strictEqual(client.maxPacketSize, number); - //}); - - //gently.expect(PACKET, 'writeNumber', function(bytes, number) { - //assert.strictEqual(bytes, 1); - //assert.strictEqual(client.charsetNumber, number); - //}); - - //gently.expect(PACKET, 'writeFiller', function(bytes) { - //assert.strictEqual(bytes, 23); - //}); - - //gently.expect(PACKET, 'writeNullTerminated', function(user) { - //assert.strictEqual(user, client.user); - //}); - - //gently.expect(PACKET, 'writeLengthCoded', function(token) { - //assert.strictEqual(token, TOKEN); - //}); - - //gently.expect(PACKET, 'writeNullTerminated', function(database) { - //assert.strictEqual(database, client.database); - //}); - - //gently.expect(client, 'write', function(packet) { - //assert.strictEqual(packet, PACKET); - //}); - //}); + gently.expect(HIJACKED['./auth'], 'scramble323', function(scramble, password) { + assert.strictEqual(scramble, GREETING.scrambleBuffer); + assert.strictEqual(password, client.password); + return TOKEN; + }); + + gently.expect(OutgoingPacketStub, 'new', function(size, number) { + assert.equal(size, TOKEN.length + 1); + + assert.equal(number, GREETING.number + 3); + PACKET = this; + + gently.expect(PACKET, 'write', function(token) { + assert.strictEqual(token, TOKEN); + }); + + gently.expect(PACKET, 'writeFiller', function(bytes) { + assert.strictEqual(bytes, 1); + }); + + gently.expect(client, 'write', function(packet) { + assert.strictEqual(packet, PACKET); + }); + }); client._sendOldAuth(GREETING); }); From c54e50a2cba6a337d4aef48e15a877f128033703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:34:27 +0200 Subject: [PATCH 19/23] Add some comments --- lib/mysql/client.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mysql/client.js b/lib/mysql/client.js index aecf3042a..66ac060c1 100644 --- a/lib/mysql/client.js +++ b/lib/mysql/client.js @@ -302,6 +302,9 @@ Client.prototype._sendOldAuth = function(greeting) { ), packet = new OutgoingPacket(packetSize, greeting.number+3); + // I could not find any official documentation for this, but from sniffing + // the mysql command line client, I think this is the right way to send the + // scrambled token after receiving the USE_OLD_PASSWORD_PROTOCOL_PACKET. packet.write(token); packet.writeFiller(1); From 41b0091eeb9943aa9333941288805a8fb2f5b256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:40:05 +0200 Subject: [PATCH 20/23] Tabs to spaces --- lib/mysql/auth.js | 176 +++++++++++++++++------------------ test/simple/test-auth-old.js | 80 ++++++++-------- 2 files changed, 128 insertions(+), 128 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 2c28b0b88..f40d3e82c 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -35,122 +35,122 @@ exports.token = function(password, scramble) { // pre-4.1 passwords. exports.hashPassword = function(password) { - var nr = [0x5030, 0x5735]; - var add = 7; - var nr2 = [0x1234, 0x5671]; - var result = new Buffer(8); - - if (typeof password == 'string'){ - password = new Buffer(password); - } - - for (var i = 0; i < password.length; i++) { - var c = password[i]; - if (c == 32 || c == 9) { - // skip space in password - continue; - } - - // nr^= (((nr & 63)+add)*c)+ (nr << 8); - // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8))) - nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0,63]), [0,add]), [0,c]), this.shl32(nr, 8))); - - // nr2+=(nr2 << 8) ^ nr; - // nr2 = add(nr2, xor(shl(nr2, 8), nr)) - nr2 = this.add32(nr2, this.xor32(this.shl32(nr2, 8), nr)); - - // add+=tmp; - add += c; - } - - this.int31Write(result, nr, 0); - this.int31Write(result, nr2, 4); - - return result; + var nr = [0x5030, 0x5735]; + var add = 7; + var nr2 = [0x1234, 0x5671]; + var result = new Buffer(8); + + if (typeof password == 'string'){ + password = new Buffer(password); + } + + for (var i = 0; i < password.length; i++) { + var c = password[i]; + if (c == 32 || c == 9) { + // skip space in password + continue; + } + + // nr^= (((nr & 63)+add)*c)+ (nr << 8); + // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8))) + nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0,63]), [0,add]), [0,c]), this.shl32(nr, 8))); + + // nr2+=(nr2 << 8) ^ nr; + // nr2 = add(nr2, xor(shl(nr2, 8), nr)) + nr2 = this.add32(nr2, this.xor32(this.shl32(nr2, 8), nr)); + + // add+=tmp; + add += c; + } + + this.int31Write(result, nr, 0); + this.int31Write(result, nr2, 4); + + return result; }; exports.randomInit = function(seed1, seed2) { - return { - max_value : 0x3FFFFFFF, - max_value_dbl : 0x3FFFFFFF, - seed1 : seed1 % 0x3FFFFFFF, - seed2 : seed2 % 0x3FFFFFFF, - }; + return { + max_value : 0x3FFFFFFF, + max_value_dbl : 0x3FFFFFFF, + seed1 : seed1 % 0x3FFFFFFF, + seed2 : seed2 % 0x3FFFFFFF, + }; }; exports.myRnd = function(r){ - r.seed1 = (r.seed1 * 3 + r.seed2) % r.max_value; - r.seed2 = (r.seed1 + r.seed2 + 33) % r.max_value; + r.seed1 = (r.seed1 * 3 + r.seed2) % r.max_value; + r.seed2 = (r.seed1 + r.seed2 + 33) % r.max_value; - return r.seed1 / r.max_value_dbl; + return r.seed1 / r.max_value_dbl; }; exports.scramble323 = function(message, password) { - if (!password) return new Buffer(); // @todo, this fails, needs fixing - var to = new Buffer(8); + if (!password) return new Buffer(); // @todo, this fails, needs fixing + var to = new Buffer(8); - var hash_pass = this.hashPassword(password); - var hash_message = this.hashPassword(message.slice(0, 8)); + var hash_pass = this.hashPassword(password); + var hash_message = this.hashPassword(message.slice(0, 8)); - var seed1 = this.int32Read(hash_pass, 0) ^ this.int32Read(hash_message, 0); - var seed2 = this.int32Read(hash_pass, 4) ^ this.int32Read(hash_message, 4); - var r = this.randomInit(seed1, seed2); + var seed1 = this.int32Read(hash_pass, 0) ^ this.int32Read(hash_message, 0); + var seed2 = this.int32Read(hash_pass, 4) ^ this.int32Read(hash_message, 4); + var r = this.randomInit(seed1, seed2); - for (var i=0; i<8; i++){ - to[i] = Math.floor(this.myRnd(r)*31) + 64; - } - var extra = (Math.floor(this.myRnd(r)*31)); + for (var i=0; i<8; i++){ + to[i] = Math.floor(this.myRnd(r)*31) + 64; + } + var extra = (Math.floor(this.myRnd(r)*31)); - for (var i=0; i<8; i++){ - to[i] ^= extra; - } + for (var i=0; i<8; i++){ + to[i] ^= extra; + } - return to; + return to; }; exports.fmt32 = function(x){ - var a = x[0].toString(16); - var b = x[1].toString(16); - - if (a.length == 1) a = "000"+a; - if (a.length == 2) a = "00"+a; - if (a.length == 3) a = "0"+a; - if (b.length == 1) b = "000"+b; - if (b.length == 2) b = "00"+b; - if (b.length == 3) b = "0"+b; - return "" + a + '/' + b; + var a = x[0].toString(16); + var b = x[1].toString(16); + + if (a.length == 1) a = "000"+a; + if (a.length == 2) a = "00"+a; + if (a.length == 3) a = "0"+a; + if (b.length == 1) b = "000"+b; + if (b.length == 2) b = "00"+b; + if (b.length == 3) b = "0"+b; + return "" + a + '/' + b; } exports.xor32 = function(a,b){ - return [a[0] ^ b[0], a[1] ^ b[1]]; + return [a[0] ^ b[0], a[1] ^ b[1]]; } exports.add32 = function(a,b){ - var w1 = a[1] + b[1]; - var w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); - return [w2 & 0xFFFF, w1 & 0xFFFF]; + var w1 = a[1] + b[1]; + var w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.mul32 = function(a,b){ - // based on this example of multiplying 32b ints using 16b - // http://www.dsprelated.com/showmessage/89790/1.php - var w1 = a[1] * b[1]; - var w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); - return [w2 & 0xFFFF, w1 & 0xFFFF]; + // based on this example of multiplying 32b ints using 16b + // http://www.dsprelated.com/showmessage/89790/1.php + var w1 = a[1] * b[1]; + var w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.and32 = function(a,b){ - return [a[0] & b[0], a[1] & b[1]] + return [a[0] & b[0], a[1] & b[1]] } exports.shl32 = function(a,b){ - // assume b is 16 or less - var w1 = a[1] << b; - var w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); - return [w2 & 0xFFFF, w1 & 0xFFFF]; + // assume b is 16 or less + var w1 = a[1] << b; + var w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.int32Write = function(buffer, number, offset) { @@ -165,15 +165,15 @@ exports.int32Write = function(buffer, number, offset) { }; exports.int31Write = function(buffer, number, offset) { - buffer[offset] = (number[0] >> 8) & 0x7F; - buffer[offset+1] = (number[0]) & 0xFF; - buffer[offset+2] = (number[1] >> 8) & 0xFF; - buffer[offset+3] = (number[1]) & 0xFF; + buffer[offset] = (number[0] >> 8) & 0x7F; + buffer[offset+1] = (number[0]) & 0xFF; + buffer[offset+2] = (number[1] >> 8) & 0xFF; + buffer[offset+3] = (number[1]) & 0xFF; }; exports.int32Read = function(buffer, offset){ - return (buffer[offset] << 24) - + (buffer[offset+1] << 16) - + (buffer[offset+2] << 8) - + (buffer[offset+3]); + return (buffer[offset] << 24) + + (buffer[offset+1] << 16) + + (buffer[offset+2] << 8) + + (buffer[offset+3]); }; diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js index 6c26e1bd4..a1c304801 100644 --- a/test/simple/test-auth-old.js +++ b/test/simple/test-auth-old.js @@ -4,54 +4,54 @@ var sys = require('sys'); var auth = require('mysql/auth'); function test_hash_password(password, bytes){ - var expected = new Buffer(bytes); - var actual = auth.hashPassword(password); + var expected = new Buffer(bytes); + var actual = auth.hashPassword(password); - sys.print('hashPassword('+password+')...'); - assert.deepEqual(actual, expected); // , 'hashPassword('+password+') failed'); - sys.print('ok\n'); + sys.print('hashPassword('+password+')...'); + assert.deepEqual(actual, expected); // , 'hashPassword('+password+') failed'); + sys.print('ok\n'); } function test_randominit(in1, in2, out1, out2){ - var r = auth.randomInit(in1, in2); - sys.print('randomInit('+in1+','+in2+')...'); - assert.equal(out1, r.seed1); - assert.equal(out2, r.seed2); - sys.print('ok\n'); + var r = auth.randomInit(in1, in2); + sys.print('randomInit('+in1+','+in2+')...'); + assert.equal(out1, r.seed1); + assert.equal(out2, r.seed2); + sys.print('ok\n'); } function test_myrnd_sequence(seed1, seed2, expected){ - var r = auth.randomInit(seed1, seed2); + var r = auth.randomInit(seed1, seed2); - for(var i=0; i'+a.substr(1, 16)+'...'); - assert.equal(a.substr(1, 16), b.substr(1, 16)); - sys.print('ok\n'); - } + sys.print('myRnd()->'+a.substr(1, 16)+'...'); + assert.equal(a.substr(1, 16), b.substr(1, 16)); + sys.print('ok\n'); + } } function test_scramble323(message, password, bytes){ - var expected = new Buffer(bytes); - var actual = auth.scramble323(new Buffer(message), password); + var expected = new Buffer(bytes); + var actual = auth.scramble323(new Buffer(message), password); - sys.print('test_scramble323('+message+', '+password+')...'); - assert.deepEqual(actual, expected); - sys.print('ok\n'); + sys.print('test_scramble323('+message+', '+password+')...'); + assert.deepEqual(actual, expected); + sys.print('ok\n'); } -test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); -test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); -test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); +test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); +test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); +test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); test_randominit(0x00000000, 0x00000000, 0x00000000, 0x00000000); test_randominit(0x0000FFFF, 0x0000FFFF, 0x0000ffff, 0x0000ffff); @@ -60,16 +60,16 @@ test_randominit(0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000003); test_randominit(3252345, 7149734, 0x0031a079, 0x006d18a6); test_myrnd_sequence(3252345, 7149734, [ - 0.0157456556481734, - 0.0696413620092360, - 0.3009698738353047, - 0.2959253138824602, - 0.5767169786400320, - 0.9958089822864243, - 0.2488940062456708, - 0.2570431151027261, - 0.5385335875102631, - 0.9215386229767824, + 0.0157456556481734, + 0.0696413620092360, + 0.3009698738353047, + 0.2959253138824602, + 0.5767169786400320, + 0.9958089822864243, + 0.2488940062456708, + 0.2570431151027261, + 0.5385335875102631, + 0.9215386229767824, ]); test_scramble323("8bytesofstuff", "root", [0x5a, 0x4d, 0x46, 0x47, 0x43, 0x53, 0x58, 0x5f]); From a303d9b551e030531ecfa6369411a7827636349f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:48:01 +0200 Subject: [PATCH 21/23] Reorganize old auth tests Moved them into the test-auth.js test and reformated things a little bit to be in sync with the projects overall style. --- lib/mysql/auth.js | 14 +++---- test/simple/test-auth-old.js | 76 ------------------------------------ test/simple/test-auth.js | 71 +++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 83 deletions(-) delete mode 100644 test/simple/test-auth-old.js diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index f40d3e82c..0a92122b3 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -115,13 +115,13 @@ exports.fmt32 = function(x){ var a = x[0].toString(16); var b = x[1].toString(16); - if (a.length == 1) a = "000"+a; - if (a.length == 2) a = "00"+a; - if (a.length == 3) a = "0"+a; - if (b.length == 1) b = "000"+b; - if (b.length == 2) b = "00"+b; - if (b.length == 3) b = "0"+b; - return "" + a + '/' + b; + if (a.length == 1) a = '000'+a; + if (a.length == 2) a = '00'+a; + if (a.length == 3) a = '0'+a; + if (b.length == 1) b = '000'+b; + if (b.length == 2) b = '00'+b; + if (b.length == 3) b = '0'+b; + return '' + a + '/' + b; } exports.xor32 = function(a,b){ diff --git a/test/simple/test-auth-old.js b/test/simple/test-auth-old.js deleted file mode 100644 index a1c304801..000000000 --- a/test/simple/test-auth-old.js +++ /dev/null @@ -1,76 +0,0 @@ -require('../common'); -var sys = require('sys'); - -var auth = require('mysql/auth'); - -function test_hash_password(password, bytes){ - var expected = new Buffer(bytes); - var actual = auth.hashPassword(password); - - sys.print('hashPassword('+password+')...'); - assert.deepEqual(actual, expected); // , 'hashPassword('+password+') failed'); - sys.print('ok\n'); -} - -function test_randominit(in1, in2, out1, out2){ - var r = auth.randomInit(in1, in2); - sys.print('randomInit('+in1+','+in2+')...'); - assert.equal(out1, r.seed1); - assert.equal(out2, r.seed2); - sys.print('ok\n'); -} - -function test_myrnd_sequence(seed1, seed2, expected){ - - var r = auth.randomInit(seed1, seed2); - - for(var i=0; i'+a.substr(1, 16)+'...'); - assert.equal(a.substr(1, 16), b.substr(1, 16)); - sys.print('ok\n'); - } -} - -function test_scramble323(message, password, bytes){ - var expected = new Buffer(bytes); - var actual = auth.scramble323(new Buffer(message), password); - - sys.print('test_scramble323('+message+', '+password+')...'); - assert.deepEqual(actual, expected); - sys.print('ok\n'); -} - -test_hash_password('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); -test_hash_password('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); -test_hash_password('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); - -test_randominit(0x00000000, 0x00000000, 0x00000000, 0x00000000); -test_randominit(0x0000FFFF, 0x0000FFFF, 0x0000ffff, 0x0000ffff); -test_randominit(0x50000000, 0x50000000, 0x10000001, 0x10000001); -test_randominit(0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000003); -test_randominit(3252345, 7149734, 0x0031a079, 0x006d18a6); - -test_myrnd_sequence(3252345, 7149734, [ - 0.0157456556481734, - 0.0696413620092360, - 0.3009698738353047, - 0.2959253138824602, - 0.5767169786400320, - 0.9958089822864243, - 0.2488940062456708, - 0.2570431151027261, - 0.5385335875102631, - 0.9215386229767824, -]); - -test_scramble323("8bytesofstuff", "root", [0x5a, 0x4d, 0x46, 0x47, 0x43, 0x53, 0x58, 0x5f]); -test_scramble323("e8cf00cec9ec825af22", "saf789yasfbsd", [0x4d, 0x54, 0x5b, 0x47, 0x5f, 0x52, 0x4d, 0x45]); diff --git a/test/simple/test-auth.js b/test/simple/test-auth.js index ac89dc686..dad5856e6 100644 --- a/test/simple/test-auth.js +++ b/test/simple/test-auth.js @@ -45,3 +45,74 @@ test(function token() { assert.deepEqual(auth.token(null, SCRAMBLE), new Buffer(0)); })(); }); + +test(function hashPassword() { + function verify(password, bytes){ + var expected = new Buffer(bytes); + var actual = auth.hashPassword(password); + + assert.deepEqual(actual, expected); + } + + verify('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); + verify('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); + verify('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); +}); + + +test(function randomInit() { + function verify(in1, in2, out1, out2){ + var r = auth.randomInit(in1, in2); + assert.equal(out1, r.seed1); + assert.equal(out2, r.seed2); + } + + verify(0x00000000, 0x00000000, 0x00000000, 0x00000000); + verify(0x0000FFFF, 0x0000FFFF, 0x0000ffff, 0x0000ffff); + verify(0x50000000, 0x50000000, 0x10000001, 0x10000001); + verify(0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000003); + verify(3252345, 7149734, 0x0031a079, 0x006d18a6); +}); + +test(function myRnd() { + function verifySequence(seed1, seed2, expected){ + var r = auth.randomInit(seed1, seed2); + for (var i = 0; i < expected.length; i++){ + var n = auth.myRnd(r); + + // we will test to 14 digits, since + // we only ever use this function mutliplied + // by small numbers anyway + + var a = ':'+n; + var b = ':'+expected[i]; + + assert.equal(a.substr(1, 16), b.substr(1, 16)); + } + } + + verifySequence(3252345, 7149734, [ + 0.0157456556481734, + 0.0696413620092360, + 0.3009698738353047, + 0.2959253138824602, + 0.5767169786400320, + 0.9958089822864243, + 0.2488940062456708, + 0.2570431151027261, + 0.5385335875102631, + 0.9215386229767824, + ]); +}); + +test(function scramble323() { + function verify(message, password, bytes){ + var expected = new Buffer(bytes); + var actual = auth.scramble323(new Buffer(message), password); + + assert.deepEqual(actual, expected); + } + + verify('8bytesofstuff', 'root', [0x5a, 0x4d, 0x46, 0x47, 0x43, 0x53, 0x58, 0x5f]); + verify('e8cf00cec9ec825af22', 'saf789yasfbsd', [0x4d, 0x54, 0x5b, 0x47, 0x5f, 0x52, 0x4d, 0x45]); +}); From ee8ce2ed4d1180d38735d0e8a9dafb4a6dd53b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:53:44 +0200 Subject: [PATCH 22/23] A few more style changes --- lib/mysql/auth.js | 81 +++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/lib/mysql/auth.js b/lib/mysql/auth.js index 0a92122b3..6077560de 100644 --- a/lib/mysql/auth.js +++ b/lib/mysql/auth.js @@ -34,11 +34,10 @@ exports.token = function(password, scramble) { // This is a port of sql/password.c:hash_password which needs to be used for // pre-4.1 passwords. exports.hashPassword = function(password) { - - var nr = [0x5030, 0x5735]; - var add = 7; - var nr2 = [0x1234, 0x5671]; - var result = new Buffer(8); + var nr = [0x5030, 0x5735], + add = 7, + nr2 = [0x1234, 0x5671], + result = new Buffer(8); if (typeof password == 'string'){ password = new Buffer(password); @@ -70,17 +69,15 @@ exports.hashPassword = function(password) { }; exports.randomInit = function(seed1, seed2) { - return { - max_value : 0x3FFFFFFF, - max_value_dbl : 0x3FFFFFFF, - seed1 : seed1 % 0x3FFFFFFF, - seed2 : seed2 % 0x3FFFFFFF, + max_value: 0x3FFFFFFF, + max_value_dbl: 0x3FFFFFFF, + seed1: seed1 % 0x3FFFFFFF, + seed2: seed2 % 0x3FFFFFFF, }; }; exports.myRnd = function(r){ - r.seed1 = (r.seed1 * 3 + r.seed2) % r.max_value; r.seed2 = (r.seed1 + r.seed2 + 33) % r.max_value; @@ -88,23 +85,19 @@ exports.myRnd = function(r){ }; exports.scramble323 = function(message, password) { - - if (!password) return new Buffer(); // @todo, this fails, needs fixing - var to = new Buffer(8); - - var hash_pass = this.hashPassword(password); - var hash_message = this.hashPassword(message.slice(0, 8)); - - var seed1 = this.int32Read(hash_pass, 0) ^ this.int32Read(hash_message, 0); - var seed2 = this.int32Read(hash_pass, 4) ^ this.int32Read(hash_message, 4); - var r = this.randomInit(seed1, seed2); - - for (var i=0; i<8; i++){ - to[i] = Math.floor(this.myRnd(r)*31) + 64; + var to = new Buffer(8), + hashPass = this.hashPassword(password), + hashMessage = this.hashPassword(message.slice(0, 8)), + seed1 = this.int32Read(hashPass, 0) ^ this.int32Read(hashMessage, 0), + seed2 = this.int32Read(hashPass, 4) ^ this.int32Read(hashMessage, 4), + r = this.randomInit(seed1, seed2); + + for (var i = 0; i < 8; i++){ + to[i] = Math.floor(this.myRnd(r) * 31) + 64; } - var extra = (Math.floor(this.myRnd(r)*31)); + var extra = (Math.floor(this.myRnd(r) * 31)); - for (var i=0; i<8; i++){ + for (var i = 0; i < 8; i++){ to[i] ^= extra; } @@ -112,8 +105,8 @@ exports.scramble323 = function(message, password) { }; exports.fmt32 = function(x){ - var a = x[0].toString(16); - var b = x[1].toString(16); + var a = x[0].toString(16), + b = x[1].toString(16); if (a.length == 1) a = '000'+a; if (a.length == 2) a = '00'+a; @@ -129,16 +122,18 @@ exports.xor32 = function(a,b){ } exports.add32 = function(a,b){ - var w1 = a[1] + b[1]; - var w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); + var w1 = a[1] + b[1], + w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } exports.mul32 = function(a,b){ // based on this example of multiplying 32b ints using 16b // http://www.dsprelated.com/showmessage/89790/1.php - var w1 = a[1] * b[1]; - var w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); + var w1 = a[1] * b[1], + w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } @@ -148,27 +143,17 @@ exports.and32 = function(a,b){ exports.shl32 = function(a,b){ // assume b is 16 or less - var w1 = a[1] << b; - var w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); + var w1 = a[1] << b, + w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); + return [w2 & 0xFFFF, w1 & 0xFFFF]; } -exports.int32Write = function(buffer, number, offset) { - var unsigned = (number < 0) ? (number + 0x100000000) : number; - buffer[offset] = Math.floor(unsigned / 0xffffff); - unsigned &= 0xffffff; - buffer[offset + 1] = Math.floor(unsigned / 0xffff); - unsigned &= 0xffff; - buffer[offset + 2] = Math.floor(unsigned / 0xff); - unsigned &= 0xff; - buffer[offset + 3] = Math.floor(unsigned); -}; - exports.int31Write = function(buffer, number, offset) { buffer[offset] = (number[0] >> 8) & 0x7F; - buffer[offset+1] = (number[0]) & 0xFF; - buffer[offset+2] = (number[1] >> 8) & 0xFF; - buffer[offset+3] = (number[1]) & 0xFF; + buffer[offset + 1] = (number[0]) & 0xFF; + buffer[offset + 2] = (number[1] >> 8) & 0xFF; + buffer[offset + 3] = (number[1]) & 0xFF; }; exports.int32Read = function(buffer, offset){ From 5eca50ca33392cce432231d044feaa1e24b094b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 2 Sep 2010 14:55:46 +0200 Subject: [PATCH 23/23] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 35f588028..a990106c8 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name" : "mysql" -, "version": "0.3.0" +, "version": "0.4.0" , "dependencies": {"gently": ">=0.8.0"} , "main" : "./lib/mysql" }