encryptor.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. 'use strict';
  2. const crypto = require('crypto');
  3. const Encryptor = {
  4. /**
  5. * Calculate a hash of the concatenated buffers with the given algorithm.
  6. * @param {string} algorithm - The hash algorithm.
  7. * @returns {Buffer} The hash
  8. */
  9. hash(algorithm) {
  10. const hash = crypto.createHash(algorithm);
  11. for (var _len = arguments.length, buffers = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  12. buffers[_key - 1] = arguments[_key];
  13. }
  14. hash.update(Buffer.concat(buffers));
  15. return hash.digest();
  16. },
  17. /**
  18. * Convert a password into an encryption key
  19. * @param {string} password - The password
  20. * @param {string} hashAlgorithm - The hash algoritm
  21. * @param {string} saltValue - The salt value
  22. * @param {number} spinCount - The spin count
  23. * @param {number} keyBits - The length of the key in bits
  24. * @param {Buffer} blockKey - The block key
  25. * @returns {Buffer} The encryption key
  26. */
  27. convertPasswordToHash(password, hashAlgorithm, saltValue, spinCount) {
  28. hashAlgorithm = hashAlgorithm.toLowerCase();
  29. const hashes = crypto.getHashes();
  30. if (hashes.indexOf(hashAlgorithm) < 0) {
  31. throw new Error(`Hash algorithm '${hashAlgorithm}' not supported!`);
  32. }
  33. // Password must be in unicode buffer
  34. const passwordBuffer = Buffer.from(password, 'utf16le');
  35. // Generate the initial hash
  36. let key = this.hash(hashAlgorithm, Buffer.from(saltValue, 'base64'), passwordBuffer);
  37. // Now regenerate until spin count
  38. for (let i = 0; i < spinCount; i++) {
  39. const iterator = Buffer.alloc(4);
  40. // this is the 'special' element of Excel password hashing
  41. // that stops us from using crypto.pbkdf2()
  42. iterator.writeUInt32LE(i, 0);
  43. key = this.hash(hashAlgorithm, key, iterator);
  44. }
  45. return key.toString('base64');
  46. },
  47. /**
  48. * Generates cryptographically strong pseudo-random data.
  49. * @param size The size argument is a number indicating the number of bytes to generate.
  50. */
  51. randomBytes(size) {
  52. return crypto.randomBytes(size);
  53. }
  54. };
  55. module.exports = Encryptor;
  56. //# sourceMappingURL=encryptor.js.map