/*
* 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 + '\'.');
}
}
}