/*
* 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
*/
/**
* @global
* @description This object describes the configuration scheme for this
* cryptographic library. The following modules are considered:
*
* - Asymmetric
*
- Primitives
*
- Stores
*
- Symmetric
*
- Digital Envelope
*
* @readonly
* @property {object} asymmetric.keypair - Policies for generating keypairs.
* @property {object} asymmetric.keypair.encryption - Policies for generating
* encryption keypairs.
* @property {object} asymmetric.keypair.encryption.algorithm - Algorithm.
* @property {string} asymmetric.keypair.encryption.algorithm.RSA - RSA
* algorithm.
* @property {object} asymmetric.keypair.encryption.provider - Provider.
* @property {string} asymmetric.keypair.encryption.provider.FORGE - Forge
* provider.
* @property {object} asymmetric.keypair.encryption.keyLength - Key length.
* @property {number} asymmetric.keypair.encryption.keyLength.KL_2048 - 2048
* bits.
* @property {number} asymmetric.keypair.encryption.keyLength.KL_3072 - 3072
* bits.
* @property {number} asymmetric.keypair.encryption.keyLength.KL_4096 - 4096
* bits.
* @property {object} asymmetric.keypair.encryption.publicExponent - Public
* exponent for generating encryption keypairs.
* @property {number} asymmetric.keypair.encryption.publicExponent.F4 - 65537.
*
* @property {object} asymmetric.signer - Policies for signing and verifying
* data.
* @property {object} asymmetric.signer.algorithm - Algorithm.
* @property {string} asymmetric.signer.algorithm.RSA - RSA algorithm.
* @property {object} asymmetric.signer.provider - Provider.
* @property {string} asymmetric.signer.provider.FORGE - Forge provider.
* @property {object} asymmetric.signer.hash - Hash algorithm.
* @property {string} asymmetric.signer.hash.SHA256 - SHA-256 algorithm.
* @property {object} asymmetric.signer.padding - Padding scheme.
* @property {object} asymmetric.signer.padding.PSS - PSS padding scheme.
* @property {string} asymmetric.signer.padding.PSS.name - PSS.
* @property {object} asymmetric.signer.padding.PSS.hash - Hash for the PSS
* padding scheme.
* @property {string} asymmetric.signer.padding.PSS.hash.SHA256 - SHA-256
* algorithm.
* @property {object} asymmetric.signer.padding.PSS.mask - Mask generating
* function for the PSS padding scheme.
* @property {object} asymmetric.signer.padding.PSS.mask.MGF1 - MGF1 for the PSS
* padding scheme.
* @property {string} asymmetric.signer.padding.PSS.mask.MGF1.name - MGF1.
* @property {object} asymmetric.signer.padding.PSS.mask.MGF1.hash - Hash
* algorithm for the MGF1 for the PSS padding scheme.
* @property {string} asymmetric.signer.padding.PSS.mask.MGF1.hash.SHA256 -
* SHA-256 algorithm.
* @property {object} asymmetric.signer.padding.PSS.saltLengthBytes - Salt
* length for the PSS padding scheme.
* @property {number} asymmetric.signer.padding.PSS.saltLengthBytes.SL_32 - 32
* bytes.
* @property {object} asymmetric.signer.publicExponent - Public exponent.
* @property {number} asymmetric.signer.publicExponent.F4 - 65537.
* @property {object} primitives.securerandom - Policies for generating
* securerandom.
* @property {object} primitives.securerandom.provider - Provider.
* @property {string} primitives.securerandom.provider.SCYTL - Scytl provider.
* @property {object} primitives.messagedigest - Policies for generating message
* digests.
* @property {object} primitives.messagedigest.algorithm - Algorithm.
* @property {string} primitives.messagedigest.algorithm.SHA256 - SHA-256
* algorithm.
* @property {object} primitives.messagedigest.provider - Provider.
* @property {string} primitives.messagedigest.provider.FORGE - Forge provider.
* @property {object} symmetric.secretkey - Policies to generate secret keys.
* @property {number} symmetric.secretkey.length - 128 bits.
* @property {object} symmetric.cipher - Policies to encrypt and decrypt
* symmetrically.
* @property {object} symmetric.cipher.algorithm - Algorithm.
* @property {object} symmetric.cipher.algorithm.AES128_GCM - AES128-GCM
* algorithm.
* @property {string} symmetric.cipher.algorithm.AES128_GCM.name - AES128-GCM.
* @property {number} symmetric.cipher.algorithm.AES128_GCM.keyLengthBytes - 16
* bytes.
* @property {number} symmetric.cipher.algorithm.AES128_GCM.tagLengthBytes - 16
* bytes.
* @property {object} symmetric.cipher.provider - Provider.
* @property {object} symmetric.cipher.provider.FORGE - Forge provider.
* @property {object} symmetric.cipher.initializationVectorLengthBytes -
* Initialization vector length.
* @property {number} symmetric.cipher.initializationVectorLengthBytes.IV_12 -
* 12 bytes.
*/
var Config = {
homomorphic: {cipher: {secureRandom: {provider: {SCYTL: 'Scytl'}}}},
asymmetric: {
keypair: {
encryption: {
algorithm: {RSA: 'RSA'},
provider: {FORGE: 'Forge'},
keyLength: {KL_2048: 2048, KL_3072: 3072, KL_4096: 4096},
publicExponent: {F4: 65537}
},
secureRandom: {provider: {SCYTL: 'Scytl'}}
},
signer: {
algorithm: {RSA: 'RSA'},
provider: {FORGE: 'Forge'},
hash: {SHA256: 'SHA256'},
padding: {
PSS: {
name: 'PSS',
hash: {SHA256: 'SHA256'},
mask: {MGF1: {name: 'MGF1', hash: {SHA256: 'SHA256'}}},
saltLengthBytes: {SL_32: 32}
}
},
publicExponent: {F4: 65537},
secureRandom: {provider: {SCYTL: 'Scytl'}}
},
cipher: {
algorithm: {
RSA_OAEP: {
name: 'RSA-OAEP',
hash: 'SHA256',
mask: {MGF1: {name: 'MGF1', hash: 'SHA1'}}
},
RSA_KEM: {
name: 'RSA-KEM',
secretKeyLengthBytes: {KL_16: 16, KL_24: 24, KL_32: 32},
ivLengthBytes: {IVL_12: 12, IVL_16: 16, IVL_32: 32, IVL_64: 64},
tagLengthBytes: {TL_12: 12, TL_16: 16, TL_32: 32, TL_64: 64},
deriver: {
name: {KDF1: 'kdf1', KDF2: 'kdf2', MGF1: 'mgf1'},
messagedigest: {algorithm: {SHA256: 'SHA256'}}
},
cipher: {AESGCM: 'AES-GCM'}
}
},
provider: {FORGE: 'Forge'},
secureRandom: {provider: {SCYTL: 'Scytl'}}
}
},
primitives: {
secureRandom: {provider: {SCYTL: 'Scytl'}},
messagedigest: {
algorithm: {SHA256: 'SHA256', SHA512_224: 'SHA512/224'},
provider: {FORGE: 'Forge'}
},
derivation: {
pbkdf: {
provider: {FORGE: 'Forge'},
hash: {SHA256: 'SHA256'},
saltLengthBytes: {SL_20: 20, SL_32: 32},
keyLengthBytes: {KL_16: 16, KL_32: 32},
iterations: {
I_1: 1,
I_8000: 8000,
I_16000: 16000,
I_32000: 32000,
I_64000: 64000
}
}
}
},
stores: {},
symmetric: {
secretkey: {
encryption: {lengthBytes: {SK_16: 16}},
mac: {lengthBytes: {SK_32: 32}},
secureRandom: {provider: {SCYTL: 'Scytl'}}
},
cipher: {
provider: {FORGE: 'Forge'},
algorithm: {
AES128_GCM: {name: 'AES-GCM', keyLengthBytes: 16, tagLengthBytes: 16}
},
initializationVectorLengthBytes: {IV_12: 12},
secureRandom: {provider: {SCYTL: 'Scytl'}}
},
mac: {hash: {SHA256: 'SHA256'}, provider: {FORGE: 'Forge'}}
},
proofs: {
secureRandom: {provider: {SCYTL: 'Scytl'}},
messagedigest: {
algorithm: {SHA256: 'SHA256', SHA512_224: 'SHA512/224'},
provider: {FORGE: 'Forge'}
},
charset: {UTF8: 'UTF-8'}
},
digitalenvelope: {
symmetric: {
secretkey: {
encryption: {lengthBytes: {SK_16: 16}},
mac: {lengthBytes: {SK_32: 32}},
secureRandom: {provider: {SCYTL: 'Scytl'}}
},
cipher: {
provider: {FORGE: 'Forge'},
algorithm: {
AES128_GCM:
{name: 'AES-GCM', keyLengthBytes: 16, tagLengthBytes: 16}
},
initializationVectorLengthBytes: {IV_12: 12},
secureRandom: {provider: {SCYTL: 'Scytl'}}
},
mac: {hash: {SHA256: 'SHA256'}, provider: {FORGE: 'Forge'}}
},
asymmetric: {
cipher: {
algorithm: {
RSA_OAEP: {
name: 'RSA-OAEP',
hash: 'SHA256',
mask: {MGF1: {name: 'MGF1', hash: 'SHA1'}}
},
RSA_KEM: {
name: 'RSA-KEM',
secretKeyLengthBytes: {KL_16: 16, KL_24: 24, KL_32: 32},
ivLengthBytes: {IVL_12: 12, IVL_16: 16, IVL_32: 32, IVL_64: 64},
tagLengthBytes: {TL_12: 12, TL_16: 16, TL_32: 32, TL_64: 64},
deriver: {
name: {KDF1: 'kdf1', KDF2: 'kdf2', MGF1: 'mgf1'},
messagedigest: {algorithm: {SHA256: 'SHA256'}}
},
cipher: {AESGCM: 'AES-GCM'}
}
},
provider: {FORGE: 'Forge'},
secureRandom: {provider: {SCYTL: 'Scytl'}}
}
}
}
};
if (Object.freeze) {
/**
* Freezes an object and all its contents.
* @param {Object} target the object to freeze.
*/
var recursiveFreeze = function(target) {
'use strict';
// Get all property names
var propNames = Object.getOwnPropertyNames(target);
// Freeze the object's properties.
propNames.forEach(function(name) {
var property = target[name];
// Freeze the properties' properties.
if (typeof property === 'object' && property !== null) {
recursiveFreeze(property);
}
});
// Freeze the object itself.
return Object.freeze(target);
};
// Lock down the configuration
recursiveFreeze(Config);
}
var cryptolibPolicies;
/**
* @global
* @function cryptolib
*
* @description Core of the library, this module is used to sandbox the
* requested modules.
*
* @example // how to load all modules cryptolib('*', function(box) { // any
* module can be used from here. //
* box.examplemodule.service.getExample(); });
*
*
* @param modules
* {...modules} modules to be loaded. '*' or none to load all the
* modules.
* @param function
* {cryptolibSandbox} a closure for the cryptolib object.
* @tutorial workers
*/
function cryptolib() {
'use strict';
/* Class to keep the references to polices and prng. */
function Cryptolib(modules, callback) {
function getAllModules(parent) {
var modules = [];
for (var module in parent) {
if (parent.hasOwnProperty(module)) {
modules.push(module);
}
}
return modules;
}
function loadModules(box, modules, parentModule) {
if (!modules || modules.toString() === '*'.toString()) {
modules = getAllModules(parentModule);
}
for (var i = 0; i < modules.length; i += 1) {
var firstDotIndex = modules[i].indexOf('.');
if (firstDotIndex > -1) {
var subModule = modules[i].substr(firstDotIndex + 1);
var root = modules[i].substr(0, firstDotIndex);
loadModules(box, [subModule], parentModule[root]);
} else if (typeof parentModule[modules[i]] === 'function') {
parentModule[modules[i]](box);
} else if (typeof parentModule[modules[i]] === 'object') {
loadModules(box, '*', parentModule[modules[i]]);
}
}
}
this.policies = callback.policies || cryptolibPolicies;
cryptolibPolicies = cryptolibPolicies || this.policies;
this.prng = callback.prng || cryptoPRNG.getPRNG();
loadModules(this, modules, cryptolib.modules);
callback(this);
}
Cryptolib.prototype = {
getKeys: function(obj) {
var keys = [];
for (var key in obj) {
if (typeof key !== 'undefined') {
keys.push(key);
}
}
return keys;
},
getModuleNames: function() {
var moduleNames = '';
for (var module in cryptolib.modules) {
if (typeof module !== 'undefined') {
if (moduleNames.length > 0) {
moduleNames += ', ';
}
moduleNames += module;
}
}
return '[' + moduleNames + ']';
},
forge: forge, // redefines forge global variable
sjcl: sjcl, // redefines sjcl global variable
// Constants.
/** @constant */
NUMBER_OF_BITS_PER_BYTE: 8,
/** @constant */
MAXIMUM_LENGTH_TO_GENERATE_DATA: 512,
/** @constant */
BASE_2_RADIX: 2,
/** @constant */
BASE_10_RADIX: 10,
/** @constant */
BASE_16_RADIX: 16,
/** @constant */
EPOCH_TIME_LENGTH: 10,
/** @constant */
RSA_LINE_LENGTH: 64,
/** @constant */
SHA_256_LENGTH: 32,
/** @constant */
HMAC_SHA256_KEY_LENGTH: 32,
/** @constant */
AES_KEY_LENGTH: 16,
/** @constant */
AES_CBC_IV_LENGTH: 16,
/** @constant */
DES3_KEY_LENGTH: 24,
/** @constant */
DES3_CBC_IV_LENGTH: 8,
EQUALS: ' = ',
NEWLINE: '\n',
CRYPTO_SPEC_DELIM: '/',
/** @constant */
SHA_256: 'SHA256',
/** @constant */
RSA_ECB_PKCS1PADDING: 'RSA/ECB/PKCS1PADDING',
/** @constant */
RSA_ECB_OAEP_WITH_SHA256_AND_MGF1PADDING:
'RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING',
/** @constant */
FORGE_RSA_OAEP: 'RSA-OAEP',
/** @constant */
FORGE_RSAES_PKCS1_V1_5: 'RSAES-PKCS1-V1_5',
/** @constant */
MINIMUM_PRIME_CERTAINTY_LEVEL: 80,
/** @constant */
SHORT_EXPONENT_BIT_LENGTH: 256,
/** @constant */
EXPONENTIATION_PROOF_AUXILIARY_DATA: 'ExponentiationProof',
/** @constant */
PLAINTEXT_PROOF_AUXILIARY_DATA: 'PlaintextProof',
/** @constant */
SIMPLE_PLAINTEXT_EQUALITY_PROOF_AUXILIARY_DATA:
'SimplePlaintextEqualityProof',
/** @constant */
PLAINTEXT_EQUALITY_PROOF_AUXILIARY_DATA: 'PlaintextEqualityProof',
/** @constant */
PLAINTEXT_EXPONENT_EQUALITY_PROOF_AUXILIARY_DATA:
'PlaintextExponentEqualityProof'
};
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var modules = (args[0] && typeof args[0] === 'string') ? args : args[0];
return new Cryptolib(modules, callback);
}
cryptolib.modules = {};