auth_41.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use strict';
  2. /*
  3. 4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
  4. SERVER: public_seed=create_random_string()
  5. send(public_seed)
  6. CLIENT: recv(public_seed)
  7. hash_stage1=sha1("password")
  8. hash_stage2=sha1(hash_stage1)
  9. reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
  10. // this three steps are done in scramble()
  11. send(reply)
  12. SERVER: recv(reply)
  13. hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
  14. candidate_hash2=sha1(hash_stage1)
  15. check(candidate_hash2==hash_stage2)
  16. server stores sha1(sha1(password)) ( hash_stag2)
  17. */
  18. const crypto = require('crypto');
  19. function sha1(msg, msg1, msg2) {
  20. const hash = crypto.createHash('sha1');
  21. hash.update(msg);
  22. if (msg1) {
  23. hash.update(msg1);
  24. }
  25. if (msg2) {
  26. hash.update(msg2);
  27. }
  28. return hash.digest();
  29. }
  30. function xor(a, b) {
  31. const result = Buffer.allocUnsafe(a.length);
  32. for (let i = 0; i < a.length; i++) {
  33. result[i] = a[i] ^ b[i];
  34. }
  35. return result;
  36. }
  37. exports.xor = xor;
  38. function token(password, scramble1, scramble2) {
  39. if (!password) {
  40. return Buffer.alloc(0);
  41. }
  42. const stage1 = sha1(password);
  43. return exports.calculateTokenFromPasswordSha(stage1, scramble1, scramble2);
  44. }
  45. exports.calculateTokenFromPasswordSha = function(
  46. passwordSha,
  47. scramble1,
  48. scramble2
  49. ) {
  50. // we use AUTH 41 here, and we need only the bytes we just need.
  51. const authPluginData1 = scramble1.slice(0, 8);
  52. const authPluginData2 = scramble2.slice(0, 12);
  53. const stage2 = sha1(passwordSha);
  54. const stage3 = sha1(authPluginData1, authPluginData2, stage2);
  55. return xor(stage3, passwordSha);
  56. };
  57. exports.calculateToken = token;
  58. exports.verifyToken = function(publicSeed1, publicSeed2, token, doubleSha) {
  59. const hashStage1 = xor(token, sha1(publicSeed1, publicSeed2, doubleSha));
  60. const candidateHash2 = sha1(hashStage1);
  61. return candidateHash2.compare(doubleSha) === 0;
  62. };
  63. exports.doubleSha1 = function(password) {
  64. return sha1(sha1(password));
  65. };
  66. function xorRotating(a, seed) {
  67. const result = Buffer.allocUnsafe(a.length);
  68. const seedLen = seed.length;
  69. for (let i = 0; i < a.length; i++) {
  70. result[i] = a[i] ^ seed[i % seedLen];
  71. }
  72. return result;
  73. }
  74. exports.xorRotating = xorRotating;