encryptor.js 1.9 KB

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