123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*
- * 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.asymmetric = cryptolib.modules.asymmetric || {};
- /** @namespace asymmetric/signer */
- cryptolib.modules.asymmetric.signer = function(box) {
- 'use strict';
- box.asymmetric = box.asymmetric || {};
- box.asymmetric.signer = {};
- /**
- * A module that holds asymmetric signature functionalities.
- *
- * @exports asymmetric/signer/factory
- */
- box.asymmetric.signer.factory = {};
- var policies = {
- algorithm: box.policies.asymmetric.signer.algorithm,
- provider: box.policies.asymmetric.signer.provider,
- hash: box.policies.asymmetric.signer.hash,
- padding: box.policies.asymmetric.signer.padding,
- publicExponent: box.policies.asymmetric.signer.publicExponent
- };
- var converters, exceptions, randomFactory;
- var f = function(box) {
- converters = new box.commons.utils.Converters();
- exceptions = box.commons.exceptions;
- randomFactory =
- new box.primitives.securerandom.factory.SecureRandomFactory();
- };
- f.policies = {
- primitives: {
- secureRandom:
- {provider: box.policies.asymmetric.signer.secureRandom.provider}
- }
- };
- cryptolib('commons', 'primitives.securerandom', f);
- /**
- * A factory class for creating a digital signer.
- *
- * @class
- */
- box.asymmetric.signer.factory.SignerFactory = function() {};
- box.asymmetric.signer.factory.SignerFactory.prototype = {
- getCryptoSigner: function() {
- try {
- if (policies.provider === Config.asymmetric.signer.provider.FORGE) {
- var secureRandom = randomFactory.getCryptoRandomBytes();
- return this.getCryptoForgeSigner(secureRandom);
- } else {
- throw new exceptions.CryptoLibException(
- 'No suitable provider for the signer was provided.');
- }
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'A CryptoSigner could not be obtained.', error);
- }
- },
- /**
- * @function
- * @return {asymmetric/signer.CryptoForgeSigner}
- */
- getCryptoForgeSigner: function(secureRandom) {
- return new CryptoForgeSigner(secureRandom);
- }
- };
- /**
- * A digital signer.
- *
- * @class
- * @memberof asymmetric/signer
- * @param secureRandom
- */
- function CryptoForgeSigner(secureRandom) {
- this.digester = null;
- this.secureRandom = secureRandom;
- try {
- if (policies.algorithm !== Config.asymmetric.signer.algorithm.RSA) {
- throw new exceptions.CryptoLibException(
- 'The given algorithm is not supported');
- }
- if (policies.hash === Config.asymmetric.signer.hash.SHA256) {
- this.digester = forge.md.sha256.create();
- } else {
- var errorMessage = 'Message digester type \'' + policies.hash +
- '\' not recognized by signer.';
- throw new exceptions.CryptoLibException(errorMessage);
- }
- if (typeof(policies.padding) !== 'undefined' &&
- policies.padding.PSS.name === Config.asymmetric.signer.padding.PSS.name) {
- var paddingHash;
- if (policies.padding.PSS.hash ===
- Config.asymmetric.signer.padding.PSS.hash.SHA256) {
- paddingHash = forge.md.sha256.create();
- }
- var paddingMgf;
- if (policies.padding.PSS.mask.MGF1.name ===
- Config.asymmetric.signer.padding.PSS.mask.MGF1.name &&
- policies.padding.PSS.mask.MGF1.hash ===
- Config.asymmetric.signer.padding.PSS.mask.MGF1.hash.SHA256) {
- var mgfHash = forge.md.sha256.create();
- paddingMgf = forge.mgf.mgf1.create(mgfHash);
- }
- this.padding = forge.pss.create({
- md: paddingHash,
- mgf: paddingMgf,
- saltLength: policies.padding.PSS.saltLengthBytes,
- prng: this.secureRandom
- });
- }
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'CryptoForgeSigner could not be created.', error);
- }
- }
- CryptoForgeSigner.prototype = {
- /**
- * Digitally signs some data.
- *
- * @function
- * @param privateKeyPem
- * Private key, as string in PEM format.
- * @param arrayDataBase64
- * Data to sign, as an array of string in Base64 encoded
- * format.
- * @returns signature, in Base64 encoded format.
- */
- sign: function(privateKeyPem, arrayDataBase64) {
- try {
- var privateKey = forge.pki.privateKeyFromPem(privateKeyPem);
- if (privateKey.e.toString() !== policies.publicExponent.toString()) {
- throw new exceptions.CryptoLibException(
- 'Private key has not been generated with the required exponent : ' +
- policies.publicExponent);
- }
- if (!arrayDataBase64 || arrayDataBase64.length < 1) {
- throw new exceptions.CryptoLibException(
- 'The array of data in Base64 should contain at least one element.');
- }
- this.digester.start();
- var dataB64;
- var data;
- for (var i = 0; i < arrayDataBase64.length; i++) {
- dataB64 = arrayDataBase64[i];
- if (dataB64 === undefined || dataB64 === null) {
- throw new exceptions.CryptoLibException(
- 'The input data contained an element that was not defined or empty.');
- }
- data = converters.base64Decode(dataB64);
- this.digester.update(data);
- }
- var signature = privateKey.sign(this.digester, this.padding);
- return converters.base64Encode(signature);
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Signature could not be generated.', error);
- }
- },
- /**
- * Verifies the digital signature of some data.
- *
- * @function
- *
- * @param signatureB64
- * Signature, as string in Base64 encoded format.
- * @param publicKeyPem
- * Public key, as string in PEM format.
- * @param arrayDataBase64
- * Data that was signed, as an array of string in Base64
- * encoded format.
- *
- * @returns boolean indicating whether signature verification was
- * successful.
- */
- verify: function(signatureB64, publicKeyPem, arrayDataBase64) {
- try {
- var publicKey = forge.pki.publicKeyFromPem(publicKeyPem);
- if (publicKey.e.toString() !== policies.publicExponent.toString()) {
- throw new exceptions.CryptoLibException(
- 'Public key has not been generated with the required exponent : ' +
- policies.publicExponent);
- }
- if (!arrayDataBase64 || arrayDataBase64.length < 1) {
- throw new exceptions.CryptoLibException(
- 'The array of data in Base64 should contain at least one element.');
- }
- this.digester.start();
- var dataB64;
- for (var i = 0; i < arrayDataBase64.length; i++) {
- dataB64 = arrayDataBase64[i];
- if (dataB64 === undefined || dataB64 === null) {
- throw new exceptions.CryptoLibException(
- 'The input data contained an element that was not defined or empty.');
- }
- var data = converters.base64Decode(dataB64);
- this.digester.update(data);
- }
- var signature = converters.base64Decode(signatureB64);
- return publicKey.verify(
- this.digester.digest().getBytes(), signature, this.padding);
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Signature could not be verified.', error);
- }
- }
- };
- };
|