123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /*
- * 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 codec = require('scytl-codec');
- var forge = require('node-forge');
- module.exports = MacHandler;
- /**
- * @class MacHandler
- * @classdesc The MAC handler API. To instantiate this object, use the method
- * {@link SymmetricCryptographyService.newMacHandler}.
- * @hideconstructor
- * @param {Policy}
- * policy The cryptographic policy to use.
- */
- function MacHandler(policy) {
- var macHandler_;
- var keyByteBuffer_;
- var updated_ = false;
- /**
- * Initializes the MAC handler with the provided secret key.
- *
- * @function init
- * @memberof MacHandler
- * @param {Uint8Array}
- * key The key with which to initialize the MAC handler.
- * @returns {MacHandler} A reference to this object, to facilitate method
- * chaining.
- * @throws {Error}
- * If the input data validation fails or the MAC handler could
- * not be initialized.
- */
- this.init = function(key) {
- validator.checkIsInstanceOf(
- key, Uint8Array, 'Uint8Array',
- 'Secret key with which to initialize MAC handler');
- try {
- macHandler_ = forge.hmac.create();
- keyByteBuffer_ = new forge.util.ByteBuffer(codec.binaryEncode(key));
- macHandler_.start(policy.symmetric.mac.hashAlgorithm, keyByteBuffer_);
- } catch (error) {
- throw new Error('MAC handler could not be initialized: ' + error.message);
- }
- return this;
- };
- /**
- * Generates a MAC from the provided data. If there were any prior calls to
- * the method <code>update</code>, then the provided data will be bitwise
- * appended to the data provided to those calls. If no data is provided here
- * the MAC will only by generated for the data provided to prior calls to
- * the method <code>update</code>. The MAC handler will be automatically
- * reinitialized after this method completes. Before using this method, the
- * MAC handler must have been initialized with a secret key, via the method
- * {@link MacHandler.init}.
- *
- * @function generate
- * @memberof MacHandler
- * @param {Uint8Array|string}
- * [data] The data from which to generate the MAC. <b>NOTE:</b>
- * Data of type <code>string</code> will be UTF-8 encoded.
- * @returns {Uint8Array} The generated MAC.
- * @throws {Error}
- * If the input data validation fails, the MAC handler was not
- * initialized, the MAC handler was not updated with any data or
- * the MAC generation process fails.
- */
- this.generate = function(data) {
- if (typeof keyByteBuffer_ === 'undefined') {
- throw new Error(
- 'Could not generate MAC; MAC handler was not initialized with any secret key');
- }
- if (typeof data !== 'undefined') {
- if (typeof data === 'string') {
- data = codec.utf8Encode(data);
- }
- validator.checkIsInstanceOf(
- data, Uint8Array, 'Uint8Array', 'Data provided to MAC generator');
- this.update(data);
- } else if (!updated_) {
- throw new Error(
- 'Attempt to generate MAC without either providing data as input or having made previous call to method \'update\'');
- }
- try {
- var macBinaryEncoded = macHandler_.digest().getBytes();
- macHandler_.start(policy.symmetric.mac.hashAlgorithm, keyByteBuffer_);
- updated_ = false;
- return codec.binaryDecode(macBinaryEncoded);
- } catch (error) {
- throw new Error('MAC could not be generated: ' + error.message);
- }
- };
- /**
- * Verfies a that MAC was generated from the provided data. If there were
- * any prior calls to the method <code>update</code>, then the provided
- * data will be bitwise appended to the data provided to those calls. If no
- * data is provided here the MAC will only by verified for the data provided
- * to prior calls to the method <code>update</code>. The MAC handler will
- * be automatically reinitialized after this method completes. Before using
- * this method, the MAC handler must have been initialized with a secret
- * key, via the method {@link MacHandler.init}.
- *
- * @function verify
- * @memberof MacHandler
- * @param {Uint8Array}
- * mac The MAC to be verified.
- * @param {Uint8Array}
- * [data] The data to check against the MAC. <b>NOTE:</b> Data
- * of type <code>string</code> will be UTF-8 encoded.
- * @returns <code>True</code> if the MAC was verified, <code>false</code>
- * otherwise.
- * @throws {Error}
- * If the input data validation fails, the MAC handler was not
- * initialized or the MAC handler was not updated with any data.
- */
- this.verify = function(mac, data) {
- if (typeof keyByteBuffer_ === 'undefined') {
- throw new Error(
- 'Could not verify MAC; MAC handler was not initialized with any secret key');
- }
- validator.checkIsInstanceOf(
- mac, Uint8Array, 'Uint8Array', 'MAC provided to MAC verifier');
- if (typeof data !== 'undefined') {
- if (typeof data === 'string') {
- data = codec.utf8Encode(data);
- }
- validator.checkIsInstanceOf(
- data, Uint8Array, 'Uint8Array', 'Data provided to MAC verifier');
- } else if (!updated_) {
- throw new Error(
- 'Attempt to verify MAC without either providing data as input or having made previous call to method \'update\'');
- }
- var macFromData = this.generate(data);
- if (macFromData.length !== mac.length) {
- return false;
- }
- var verified = true;
- for (var i = 0; i < macFromData.length; i++) {
- if (macFromData[i] !== mac[i]) {
- verified = false;
- }
- }
- return verified;
- };
- /**
- * Updates the MAC handler with the provided data. The data will be
- * internally bitwise concatenated to any data provided via previous calls
- * to this method, after the last call to the method <code>generate</code>
- * or the method <code>verify</code>. Before using this method, the MAC
- * handler must have been initialized with a secret key, via the method
- * {@link MacHandler.init}.
- *
- * @function update
- * @memberof MacHandler
- * @param {Uint8Array}
- * data The data with which to update the MAC handler. <b>NOTE:</b>
- * Data of type <code>string</code> will be UTF-8 encoded.
- * @returns {MacHandler} A reference to this object, to facilitate method
- * chaining.
- * @throws {Error}
- * If the input data validation fails or the MAC could not be
- * updated.
- */
- this.update = function(data) {
- if (typeof keyByteBuffer_ === 'undefined') {
- throw new Error(
- 'Could not update MAC; MAC handler was not initialized with any secret key');
- }
- if (typeof data === 'string') {
- data = codec.utf8Encode(data);
- }
- validator.checkIsInstanceOf(
- data, Uint8Array, 'Uint8Array',
- 'Data with which to update MAC handler');
- try {
- macHandler_.update(codec.binaryEncode(data));
- updated_ = true;
- } catch (error) {
- throw new Error('MAC handler could not be updated: ' + error.message);
- }
- return this;
- };
- }
|