/* * Copyright 2018 Scytl Secure Electronic Voting SA * * All rights reserved * * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package */ /* jshint node:true */ 'use strict'; var validator = require('./input-validator'); var cryptoPolicy = require('scytl-cryptopolicy'); var codec = require('scytl-codec'); var forge = require('node-forge'); module.exports = MessageDigester; /** * @class MessageDigester * @classdesc The message digester API. To instantiate this object, use the * method {@link MessageDigestService.newDigester}. * @hideconstructor * @param {Policy} * policy The cryptographic policy to use. */ function MessageDigester(policy) { var digester_ = getDigester(policy.primitives.messageDigest.algorithm); digester_.start(); var updated_ = false; /** * Generates a message digest from the provided data. If there were any * prior calls to the method update, then the provided data * will be bitwise appended to the data provided to those calls before * digesting. If no data is provided here the digest will only by generated * for the data provided to prior calls to the method update. * The message digester will be automatically reinitialized after this * method completes. * * @function digest * @memberof MessageDigester * @param {Uint8Array|string} * [data] The data from which to generate the message digest. * NOTE: Data of type string will be UTF-8 * encoded. * @returns {Uint8Array} The generated message digest. * @throws {Error} * If no data was provided as input and the update method was * not previously called. */ this.digest = function(data) { if (typeof data !== 'undefined') { if (typeof data === 'string') { data = codec.utf8Encode(data); } validator.checkIsInstanceOf( data, Uint8Array, 'Uint8Array', 'Data to digest'); this.update(data); } else if (!updated_) { throw new Error( 'Attempt to generate message digest without either providing data as input or having made previous call to method \'update\''); } var bytesBinaryEncoded = digester_.digest().getBytes(); // Reinitialize digester. digester_.start(); updated_ = false; return codec.binaryDecode(bytesBinaryEncoded); }; /** * Updates the message digester with the provided data. The data will be * internally bitwise appended to any data provided to previous calls to * this method, after the last call to the method digest. * * @function update * @memberof MessageDigester * @param {Uint8Array|string} * data The data with which to update the message digester. * NOTE: Data of type string will be UTF-8 * encoded. * @returns {MessageDigester} A reference to this object, to facilitate * method chaining. * @throws {Error} * If the input data validation fails. */ this.update = function(data) { if (typeof data === 'string') { data = codec.utf8Encode(data); } validator.checkIsInstanceOf( data, Uint8Array, 'Uint8Array', 'Data to update message digester'); digester_.update(codec.binaryEncode(data)); updated_ = true; return this; }; function getDigester(algorithm) { if (algorithm === cryptoPolicy.options.primitives.messageDigest.algorithm.SHA256) { return forge.md.sha256.create(); } else if ( algorithm === cryptoPolicy.options.primitives.messageDigest.algorithm.SHA512_224) { return forge.md.sha512.sha224.create(); } else { throw new Error( 'Could not create new message digester for unrecognized hash algorithm \'' + algorithm + '\'.'); } } }