sha256-password-auth.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. const PluginAuth = require('./plugin-auth');
  2. const fs = require('fs');
  3. const crypto = require('crypto');
  4. const Errors = require('../../../misc/errors');
  5. /**
  6. * Use Sha256 authentication
  7. */
  8. class Sha256PasswordAuth extends PluginAuth {
  9. constructor(packSeq, compressPackSeq, pluginData, resolve, reject, multiAuthResolver) {
  10. super(resolve, reject, multiAuthResolver);
  11. this.pluginData = pluginData;
  12. this.sequenceNo = packSeq;
  13. this.counter = 0;
  14. this.initialState = true;
  15. }
  16. start(out, opts, info) {
  17. this.exchange(this.pluginData, out, opts, info);
  18. this.onPacketReceive = this.response;
  19. }
  20. exchange(buffer, out, opts, info) {
  21. if (this.initialState) {
  22. if (!opts.password) {
  23. out.startPacket(this);
  24. out.writeEmptyPacket(true);
  25. return;
  26. } else if (opts.ssl) {
  27. // using SSL, so sending password in clear
  28. out.startPacket(this);
  29. if (opts.password) {
  30. out.writeString(opts.password);
  31. }
  32. out.writeInt8(0);
  33. out.flushBuffer(true);
  34. return;
  35. } else {
  36. // retrieve public key from configuration or from server
  37. if (opts.rsaPublicKey) {
  38. try {
  39. let key = opts.rsaPublicKey;
  40. if (!key.includes('-----BEGIN')) {
  41. // rsaPublicKey contain path
  42. key = fs.readFileSync(key, 'utf8');
  43. }
  44. this.publicKey = Sha256PasswordAuth.retreivePublicKey(key);
  45. } catch (err) {
  46. return this.throwError(err, info);
  47. }
  48. } else {
  49. if (!opts.allowPublicKeyRetrieval) {
  50. return this.throwError(
  51. Errors.createError(
  52. 'RSA public key is not available client side. Either set option `rsaPublicKey` to indicate' +
  53. ' public key path, or allow public key retrieval with option `allowPublicKeyRetrieval`',
  54. true,
  55. info,
  56. '08S01',
  57. Errors.ER_CANNOT_RETRIEVE_RSA_KEY
  58. ),
  59. info
  60. );
  61. }
  62. this.initialState = false;
  63. // ask public Key Retrieval
  64. out.startPacket(this);
  65. out.writeInt8(0x01);
  66. out.flushBuffer(true);
  67. return;
  68. }
  69. }
  70. // send Sha256Password Packet
  71. Sha256PasswordAuth.sendSha256PwdPacket(
  72. this,
  73. this.pluginData,
  74. this.publicKey,
  75. opts.password,
  76. out
  77. );
  78. } else {
  79. // has request public key
  80. this.publicKey = Sha256PasswordAuth.retreivePublicKey(buffer.toString('utf8', 1));
  81. Sha256PasswordAuth.sendSha256PwdPacket(
  82. this,
  83. this.pluginData,
  84. this.publicKey,
  85. opts.password,
  86. out
  87. );
  88. }
  89. }
  90. static retreivePublicKey(key) {
  91. return key.replace('(-+BEGIN PUBLIC KEY-+\\r?\\n|\\n?-+END PUBLIC KEY-+\\r?\\n?)', '');
  92. }
  93. static sendSha256PwdPacket(cmd, pluginData, publicKey, password, out) {
  94. const truncatedSeed = pluginData.slice(0, pluginData.length - 1);
  95. out.startPacket(cmd);
  96. const enc = Sha256PasswordAuth.encrypt(truncatedSeed, password, publicKey);
  97. out.writeBuffer(enc, 0, enc.length);
  98. out.flushBuffer(cmd);
  99. }
  100. // encrypt password with public key
  101. static encrypt(seed, password, publicKey) {
  102. const nullFinishedPwd = Buffer.from(password + '\0');
  103. const xorBytes = Buffer.allocUnsafe(nullFinishedPwd.length);
  104. const seedLength = seed.length;
  105. for (let i = 0; i < xorBytes.length; i++) {
  106. xorBytes[i] = nullFinishedPwd[i] ^ seed[i % seedLength];
  107. }
  108. return crypto.publicEncrypt(
  109. { key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
  110. xorBytes
  111. );
  112. }
  113. response(packet, out, opts, info) {
  114. const marker = packet.peek();
  115. switch (marker) {
  116. //*********************************************************************************************************
  117. //* OK_Packet and Err_Packet ending packet
  118. //*********************************************************************************************************
  119. case 0x00:
  120. case 0xff:
  121. this.emit('send_end');
  122. return this.successSend(packet, out, opts, info);
  123. default:
  124. let promptData = packet.readBufferRemaining();
  125. this.exchange(promptData, out, opts, info);
  126. this.onPacketReceive = this.response;
  127. }
  128. }
  129. }
  130. module.exports = Sha256PasswordAuth;