123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- /*
- * 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
- */
- /**
- * Scytl Key Store. It is a custom keystore.
- */
- cryptolib.modules.stores.sks = function(box) {
- 'use strict';
- box.stores = box.stores || {};
- box.stores.sks = {};
- var converters;
- var secretKeyGeneratorFactory;
- var cipher;
- var pkcs12Module;
- var exceptions;
- var homomorphicKeyFactory;
- var f = function(box) {
- converters = new box.commons.utils.Converters();
- cipher = (new box.symmetric.cipher.factory.SymmetricCipherFactory())
- .getCryptoSymmetricCipher();
- secretKeyGeneratorFactory =
- new box.primitives.derivation.factory.SecretKeyGeneratorFactory();
- pkcs12Module = box.stores.pkcs12;
- exceptions = box.commons.exceptions;
- homomorphicKeyFactory = new box.homomorphic.keypair.factory.KeyFactory();
- };
- f.policies = {
- symmetric: {
- secretkey: {
- encryption:
- {length: box.policies.symmetric.secretkey.encryption.length},
- mac: {length: box.policies.symmetric.secretkey.mac.length},
- secureRandom:
- {provider: box.policies.symmetric.secretkey.secureRandom.provider}
- },
- cipher: {
- provider: box.policies.symmetric.cipher.provider,
- algorithm: box.policies.symmetric.cipher.algorithm,
- initializationVectorLengthBytes:
- box.policies.symmetric.cipher.initializationVectorLengthBytes,
- secureRandom:
- {provider: box.policies.symmetric.cipher.secureRandom.provider}
- }
- },
- primitives: {
- derivation: {
- pbkdf: {
- provider: box.policies.primitives.derivation.pbkdf.provider,
- hash: box.policies.primitives.derivation.pbkdf.hash,
- saltLengthBytes:
- box.policies.primitives.derivation.pbkdf.saltLengthBytes,
- keyLengthBytes:
- box.policies.primitives.derivation.pbkdf.keyLengthBytes,
- iterations: box.policies.primitives.derivation.pbkdf.iterations
- }
- }
- }
- };
- cryptolib(
- 'commons', 'primitives.derivation', 'symmetric.cipher', 'stores.pkcs12',
- 'homomorphic.keypair', f);
- /**
- * Defines a SksReader.
- *
- * @param data.
- */
- box.stores.sks.SksReader = function(data) {
- // A cache of keys derived from store passwords, to prevent consecutive
- // operations on a keystore to derive keys each time.
- var bigintKeys = {};
- var derivedKeys = {};
- // Create the PBKDF generator.
- var cryptoPbkdfSecretKeyGenerator = secretKeyGeneratorFactory.createPBKDF();
- try {
- var loadKeyStore = function(data) {
- var keyStore;
- if (data) {
- if (typeof data === 'string') {
- keyStore = JSON.parse(data);
- } else if (typeof data === 'object') {
- keyStore = data;
- }
- }
- return keyStore;
- };
- var validateKeyStoreStructure = function(keyStore) {
- if (typeof keyStore.salt === 'undefined') {
- throw new Error('Missing salt');
- }
- if (typeof keyStore.store === 'undefined') {
- throw new Error('Missing store');
- }
- };
- this.keyStore = loadKeyStore(data);
- validateKeyStoreStructure(this.keyStore);
- this.store = new pkcs12Module.Pkcs12(this.keyStore.store);
- } catch (error) {
- throw new Error('Invalid keyStore: ' + error.message);
- }
- function validateEncryptedKey(encryptedKey, keyType) {
- if (!encryptedKey) {
- throw new exceptions.CryptoLibException(
- 'The keyStore does not contain a key of type ' + keyType);
- }
- }
- /**
- * Derive a key from the keystore password.
- *
- * @param {string} passwordB64 the Base64-encoded keystore password
- * @returns the Base64-encoded key derived from the password
- */
- this._deriveKey = function(passwordB64) {
- return cryptoPbkdfSecretKeyGenerator.generateSecret(
- passwordB64, this.keyStore.salt);
- };
- /**
- * Get the Base64-encoded key derived from the store password.
- *
- * @param {string} passwordB64 the Base64-encoded store password
- * @return the Base64-encoded key derived from the store password
- */
- this._getDerivedKey = function(passwordB64) {
- if (!derivedKeys.hasOwnProperty(passwordB64)) {
- derivedKeys[passwordB64] = this._deriveKey(passwordB64);
- }
- return derivedKeys[passwordB64];
- };
- /**
- * Get the Base64-encoded BigInteger representation of the key derived from
- * the store password.
- *
- * @param {string} passwordB64 the Base64-encoded store password
- * @returns the Base64-encoded BigInteger representation of the key derived
- * from the store password
- */
- this._getBigIntKey = function(passwordB64) {
- if (!bigintKeys.hasOwnProperty(passwordB64)) {
- var derivedPasswordBase64 = this._getDerivedKey(passwordB64);
- var derivedPassword = converters.bytesFromString(
- converters.base64Decode(derivedPasswordBase64));
- var derivedPasswordString =
- new box.forge.jsbn.BigInteger(derivedPassword);
- var longPasswordB64 =
- converters.base64Encode(derivedPasswordString.toString(36));
- bigintKeys[passwordB64] = longPasswordB64;
- }
- return bigintKeys[passwordB64];
- };
- this._getKey = function(alias, encryptedKey, passwordB64, keyType) {
- validateEncryptedKey(encryptedKey, keyType);
- var aliasAndKeyBase64 = this.decryptKey(encryptedKey, passwordB64);
- var aliasAndKey = converters.base64Decode(aliasAndKeyBase64);
- var decryptedAlias = aliasAndKey.slice(0, alias.length);
- if (decryptedAlias !== alias) {
- throw new exceptions.CryptoLibException(
- 'The decrypted ' + keyType +
- ' key does not correspond to the given alias.');
- }
- var key = aliasAndKey.slice(alias.length, aliasAndKey.length);
- var keyBase64 = converters.base64Encode(key);
- return keyBase64;
- };
- };
- box.stores.sks.SksReader.prototype = {
- getPrivateKeys: function(passwordB64) {
- var updateArguments = function(bigIntKey, args) {
- var argumentsCopy = Array.prototype.slice.call(args, 1);
- argumentsCopy.unshift(bigIntKey);
- return argumentsCopy;
- };
- return this.store.getPrivateKey.apply(
- this.store,
- updateArguments(this._getBigIntKey(passwordB64), arguments));
- },
- getSecretKey: function(alias, passwordB64) {
- var encryptedKey = this.keyStore.secrets[alias];
- return this._getKey(alias, encryptedKey, passwordB64, 'secret');
- },
- getElGamalPrivateKey: function(alias, passwordB64) {
- var encryptedKey = this.keyStore.egPrivKeys[alias];
- var keyBase64 =
- this._getKey(alias, encryptedKey, passwordB64, 'ElGamal private');
- return homomorphicKeyFactory.createPrivateKey(keyBase64);
- },
- decryptKey: function(encryptedKey, passwordB64) {
- return cipher.decrypt(this._getDerivedKey(passwordB64), encryptedKey);
- },
- /**
- * Retrieves the private key chain
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @return Private key chain of as PrivateKeyChain object, which
- * contains aliases and their related private keys in PEM
- * format.
- */
- getPrivateKeyChain: function(passwordB64) {
- return this.store.getPrivateKeyChain(this._getBigIntKey(passwordB64));
- },
- /**
- * Retrieves the full certificate chain.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @return Certificate chain as array of strings in PEM format.
- */
- getCertificateChain: function(passwordB64) {
- return this.store.getCertificateChain(this._getBigIntKey(passwordB64));
- },
- /**
- * Retrieves a certificate chain by private key alias
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @param alias
- * Alias to filter
- * @return Certificate chain as array of strings in PEM format.
- */
- getCertificateChainByAlias: function(passwordB64, alias) {
- return this.store.getCertificateChainByAlias(
- this._getBigIntKey(passwordB64), alias);
- },
- /**
- * Retrieves a certificate by subject common name.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @param subjectCn
- * Subject common name of certificate to retrieve, as string.
- * @return Certificate with given subject common name, as string in PEM
- * format.
- */
- getCertificateBySubject: function(passwordB64, subjectCn) {
- return this.store.getCertificateBySubject(
- this._getBigIntKey(passwordB64), subjectCn);
- }
- };
- };
|