Auth.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. var Buffer = require('buffer').Buffer;
  2. var Crypto = require('crypto');
  3. var Auth = exports;
  4. function sha1(msg) {
  5. var hash = Crypto.createHash('sha1');
  6. hash.update(msg);
  7. // hash.digest() does not output buffers yet
  8. return hash.digest('binary');
  9. };
  10. Auth.sha1 = sha1;
  11. function xor(a, b) {
  12. a = new Buffer(a, 'binary');
  13. b = new Buffer(b, 'binary');
  14. var result = new Buffer(a.length);
  15. for (var i = 0; i < a.length; i++) {
  16. result[i] = (a[i] ^ b[i]);
  17. }
  18. return result;
  19. };
  20. Auth.xor = xor;
  21. Auth.token = function(password, scramble) {
  22. if (!password) {
  23. return new Buffer(0);
  24. }
  25. var stage1 = sha1(password);
  26. var stage2 = sha1(stage1);
  27. var stage3 = sha1(scramble.toString('binary') + stage2);
  28. return xor(stage3, stage1);
  29. };
  30. // This is a port of sql/password.c:hash_password which needs to be used for
  31. // pre-4.1 passwords.
  32. Auth.hashPassword = function(password) {
  33. var nr = [0x5030, 0x5735],
  34. add = 7,
  35. nr2 = [0x1234, 0x5671],
  36. result = new Buffer(8);
  37. if (typeof password == 'string'){
  38. password = new Buffer(password);
  39. }
  40. for (var i = 0; i < password.length; i++) {
  41. var c = password[i];
  42. if (c == 32 || c == 9) {
  43. // skip space in password
  44. continue;
  45. }
  46. // nr^= (((nr & 63)+add)*c)+ (nr << 8);
  47. // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8)))
  48. nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0,63]), [0,add]), [0,c]), this.shl32(nr, 8)));
  49. // nr2+=(nr2 << 8) ^ nr;
  50. // nr2 = add(nr2, xor(shl(nr2, 8), nr))
  51. nr2 = this.add32(nr2, this.xor32(this.shl32(nr2, 8), nr));
  52. // add+=tmp;
  53. add += c;
  54. }
  55. this.int31Write(result, nr, 0);
  56. this.int31Write(result, nr2, 4);
  57. return result;
  58. };
  59. Auth.randomInit = function(seed1, seed2) {
  60. return {
  61. max_value: 0x3FFFFFFF,
  62. max_value_dbl: 0x3FFFFFFF,
  63. seed1: seed1 % 0x3FFFFFFF,
  64. seed2: seed2 % 0x3FFFFFFF
  65. };
  66. };
  67. Auth.myRnd = function(r){
  68. r.seed1 = (r.seed1 * 3 + r.seed2) % r.max_value;
  69. r.seed2 = (r.seed1 + r.seed2 + 33) % r.max_value;
  70. return r.seed1 / r.max_value_dbl;
  71. };
  72. Auth.scramble323 = function(message, password) {
  73. var to = new Buffer(8),
  74. hashPass = this.hashPassword(password),
  75. hashMessage = this.hashPassword(message.slice(0, 8)),
  76. seed1 = this.int32Read(hashPass, 0) ^ this.int32Read(hashMessage, 0),
  77. seed2 = this.int32Read(hashPass, 4) ^ this.int32Read(hashMessage, 4),
  78. r = this.randomInit(seed1, seed2);
  79. for (var i = 0; i < 8; i++){
  80. to[i] = Math.floor(this.myRnd(r) * 31) + 64;
  81. }
  82. var extra = (Math.floor(this.myRnd(r) * 31));
  83. for (var i = 0; i < 8; i++){
  84. to[i] ^= extra;
  85. }
  86. return to;
  87. };
  88. Auth.fmt32 = function(x){
  89. var a = x[0].toString(16),
  90. b = x[1].toString(16);
  91. if (a.length == 1) a = '000'+a;
  92. if (a.length == 2) a = '00'+a;
  93. if (a.length == 3) a = '0'+a;
  94. if (b.length == 1) b = '000'+b;
  95. if (b.length == 2) b = '00'+b;
  96. if (b.length == 3) b = '0'+b;
  97. return '' + a + '/' + b;
  98. };
  99. Auth.xor32 = function(a,b){
  100. return [a[0] ^ b[0], a[1] ^ b[1]];
  101. };
  102. Auth.add32 = function(a,b){
  103. var w1 = a[1] + b[1],
  104. w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16);
  105. return [w2 & 0xFFFF, w1 & 0xFFFF];
  106. };
  107. Auth.mul32 = function(a,b){
  108. // based on this example of multiplying 32b ints using 16b
  109. // http://www.dsprelated.com/showmessage/89790/1.php
  110. var w1 = a[1] * b[1],
  111. w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF);
  112. return [w2 & 0xFFFF, w1 & 0xFFFF];
  113. };
  114. Auth.and32 = function(a,b){
  115. return [a[0] & b[0], a[1] & b[1]];
  116. };
  117. Auth.shl32 = function(a,b){
  118. // assume b is 16 or less
  119. var w1 = a[1] << b,
  120. w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16);
  121. return [w2 & 0xFFFF, w1 & 0xFFFF];
  122. };
  123. Auth.int31Write = function(buffer, number, offset) {
  124. buffer[offset] = (number[0] >> 8) & 0x7F;
  125. buffer[offset + 1] = (number[0]) & 0xFF;
  126. buffer[offset + 2] = (number[1] >> 8) & 0xFF;
  127. buffer[offset + 3] = (number[1]) & 0xFF;
  128. };
  129. Auth.int32Read = function(buffer, offset){
  130. return (buffer[offset] << 24)
  131. + (buffer[offset+1] << 16)
  132. + (buffer[offset+2] << 8)
  133. + (buffer[offset+3]);
  134. };