/* * 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 */ cryptolib.modules.symmetric = cryptolib.modules.symmetric || {}; /** * Defines the MACs of the module. * * @namespace symmetric/mac */ cryptolib.modules.symmetric.mac = function(box) { 'use strict'; box.symmetric = box.symmetric || {}; box.symmetric.mac = {}; /** * Allows a symmetric MAC factory to be obtained. * * @exports symmetric/mac/factory */ box.symmetric.mac.factory = {}; var policies = { mac: { hash: box.policies.symmetric.mac.hash, provider: box.policies.symmetric.mac.provider } }; var converters; var exceptions; cryptolib('commons', function(box) { converters = new box.commons.utils.Converters(); exceptions = box.commons.exceptions; }); /** * Factory class that allows a MAC to be obtained. * * @class */ box.symmetric.mac.factory.MacFactory = function() {}; box.symmetric.mac.factory.MacFactory.prototype = { /** * Create a new MAC. *

* The particular MAC that is returned depends on the policies. * * @function * @returns a new MAC. */ create: function() { try { if (policies.mac.provider === Config.symmetric.mac.provider.FORGE) { return this.createCryptoForgeMac(); } else { throw new exceptions.CryptoLibException( 'No suitable provider was provided.'); } } catch (error) { throw new exceptions.CryptoLibException( 'A CryptoMac could not be obtained.', error); } }, /** * Create a new CryptoForgeMac. * * @function * @returns {symmetric/mac.CryptoForgeMac} a new CryptoForgeMac. */ createCryptoForgeMac: function() { return new CryptoForgeMac(); } }; /** * Represents a MAC. * * @class * @memberof symmetric/mac */ function CryptoForgeMac() { this.hmacDigester = forge.hmac.create(); } CryptoForgeMac.prototype = { /** * Generates MAC for some data. * * @function * @param secretKeyBase64 * {String} Secret key, as string in Base64 encoded format * @param arrayDataBase64 * {String} The input data for the MAC, as an array of string * in Base64 encoded format. It is assumed that the array is * not empty. * @returns The generated MAC, in Base64 encoded format. */ generate: function(secretKeyBase64, arrayDataBase64) { var secretKey = converters.base64Decode(secretKeyBase64); var secretKeyBuffer = new forge.util.ByteBuffer(secretKey); try { this.hmacDigester.start(policies.mac.hash, secretKeyBuffer); } catch (error) { throw new exceptions.CryptoLibException( 'MAC message digester could not be initialized.', error); } try { if (arrayDataBase64.length < 1) { throw new exceptions.CryptoLibException( 'The array of data should have at least one element'); } var dataB64; for (var i = 0; i < arrayDataBase64.length; i++) { dataB64 = arrayDataBase64[i]; var data = converters.base64Decode(dataB64); this.hmacDigester.update(data); } } catch (error) { throw new exceptions.CryptoLibException( 'MAC message digester could not be updated.', error); } try { var hmacMessageDigest = this.hmacDigester.digest(); return converters.base64Encode(hmacMessageDigest.getBytes()); } catch (error) { throw new exceptions.CryptoLibException( 'MAC message digest could not be generated.', error); } }, /** * Verify that a given MAC is indeed the MAC for the given data, using * the given secret key. * * @function * @param macBase64 * {String} The MAC to be verified, as string in Base64 * encoded format. * @param secretKeyBase64 * {String} Secret key, as string in Base64 encoded format * @param arrayDataBase64 * {String} The input data for the MAC, as an array of string * in Base64 encoded format. It is assumed that the array is * not empty. * * @returns True if the MAC is the MAC of the given data and SecretKey, * false otherwise. */ verify: function(macBase64, secretKeyBase64, arrayDataBase64) { if (typeof macBase64 === 'undefined' || macBase64 === null) { return false; } var macBase64ToVerify = this.generate(secretKeyBase64, arrayDataBase64); if (macBase64.length !== macBase64ToVerify.length) { return false; } var equals = true; for (var i = 0; i < macBase64ToVerify.length; i++) { if (macBase64ToVerify.charCodeAt(i) !== macBase64.charCodeAt(i)) { equals = false; } } return equals; } }; };