You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					56 lines
				
				1.9 KiB
			
		
		
			
		
	
	
					56 lines
				
				1.9 KiB
			| 
											2 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | const crypto = require('crypto'); | ||
|  | 
 | ||
|  | const Encryptor = { | ||
|  |   /** | ||
|  |    * Calculate a hash of the concatenated buffers with the given algorithm. | ||
|  |    * @param {string} algorithm - The hash algorithm. | ||
|  |    * @returns {Buffer} The hash | ||
|  |    */ | ||
|  |   hash(algorithm, ...buffers) { | ||
|  |     const hash = crypto.createHash(algorithm); | ||
|  |     hash.update(Buffer.concat(buffers)); | ||
|  |     return hash.digest(); | ||
|  |   }, | ||
|  |   /** | ||
|  |    * Convert a password into an encryption key | ||
|  |    * @param {string} password - The password | ||
|  |    * @param {string} hashAlgorithm - The hash algoritm | ||
|  |    * @param {string} saltValue - The salt value | ||
|  |    * @param {number} spinCount - The spin count | ||
|  |    * @param {number} keyBits - The length of the key in bits | ||
|  |    * @param {Buffer} blockKey - The block key | ||
|  |    * @returns {Buffer} The encryption key | ||
|  |    */ | ||
|  |   convertPasswordToHash(password, hashAlgorithm, saltValue, spinCount) { | ||
|  |     hashAlgorithm = hashAlgorithm.toLowerCase(); | ||
|  |     const hashes = crypto.getHashes(); | ||
|  |     if (hashes.indexOf(hashAlgorithm) < 0) { | ||
|  |       throw new Error(`Hash algorithm '${hashAlgorithm}' not supported!`); | ||
|  |     } | ||
|  | 
 | ||
|  |     // Password must be in unicode buffer
 | ||
|  |     const passwordBuffer = Buffer.from(password, 'utf16le'); | ||
|  |     // Generate the initial hash
 | ||
|  |     let key = this.hash(hashAlgorithm, Buffer.from(saltValue, 'base64'), passwordBuffer); | ||
|  |     // Now regenerate until spin count
 | ||
|  |     for (let i = 0; i < spinCount; i++) { | ||
|  |       const iterator = Buffer.alloc(4); | ||
|  |       // this is the 'special' element of Excel password hashing
 | ||
|  |       // that stops us from using crypto.pbkdf2()
 | ||
|  |       iterator.writeUInt32LE(i, 0); | ||
|  |       key = this.hash(hashAlgorithm, key, iterator); | ||
|  |     } | ||
|  |     return key.toString('base64'); | ||
|  |   }, | ||
|  |   /** | ||
|  |    * Generates cryptographically strong pseudo-random data. | ||
|  |    * @param size The size argument is a number indicating the number of bytes to generate. | ||
|  |    */ | ||
|  |   randomBytes(size) { | ||
|  |     return crypto.randomBytes(size); | ||
|  |   }, | ||
|  | }; | ||
|  | module.exports = Encryptor; |