sha256_password.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. 'use strict';
  2. const PLUGIN_NAME = 'sha256_password';
  3. const crypto = require('crypto');
  4. const { xor } = require('../auth_41');
  5. const REQUEST_SERVER_KEY_PACKET = Buffer.from([1]);
  6. const STATE_INITIAL = 0;
  7. const STATE_WAIT_SERVER_KEY = 1;
  8. const STATE_FINAL = -1;
  9. function encrypt(password, scramble, key) {
  10. const stage1 = xor(
  11. Buffer.from(`${password}\0`, 'utf8').toString('binary'),
  12. scramble.toString('binary')
  13. );
  14. return crypto.publicEncrypt(key, stage1);
  15. }
  16. module.exports = (pluginOptions = {}) => ({ connection }) => {
  17. let state = 0;
  18. let scramble = null;
  19. const password = connection.config.password;
  20. const authWithKey = serverKey => {
  21. const _password = encrypt(password, scramble, serverKey);
  22. state = STATE_FINAL;
  23. return _password;
  24. };
  25. return data => {
  26. switch (state) {
  27. case STATE_INITIAL:
  28. scramble = data.slice(0, 20);
  29. // if client provides key we can save one extra roundrip on first connection
  30. if (pluginOptions.serverPublicKey) {
  31. return authWithKey(pluginOptions.serverPublicKey);
  32. }
  33. state = STATE_WAIT_SERVER_KEY;
  34. return REQUEST_SERVER_KEY_PACKET;
  35. case STATE_WAIT_SERVER_KEY:
  36. if (pluginOptions.onServerPublicKey) {
  37. pluginOptions.onServerPublicKey(data);
  38. }
  39. return authWithKey(data);
  40. case STATE_FINAL:
  41. throw new Error(
  42. `Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
  43. );
  44. }
  45. throw new Error(
  46. `Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
  47. );
  48. };
  49. };