Ejemplo n.º 1
0
    def do_start(self, config):
        '''
        this is called by the protocol when we receive a command from the TS
        to start a new collection phase
        return None if failure, otherwise the protocol will encode the result
        in json and send it back to TS
        '''
        logging.info("got command to start new collection phase")
        # keep the start config to send to the TS at the end of the collection
        # deepcopy so we can delete the (encrypted) secrets from the shares
        self.start_config = deepcopy(config)
        # discard the secrets
        # we haven't checked if any shares are present, so don't assume
        for share in self.start_config.get('shares', []):
            # this is still encrypted, so there's no need for a secure delete
            del share['secret']
            share['secret'] = "(encrypted blinding share, deleted by share keeper)"
        # sort the shares, so that their order is consistent between rounds
        self.start_config.get('shares', []).sort()

        if ('shares' not in config):
            logging.warning("start command from tally server cannot be completed due to missing shares")
            return None

        combined_counters = self.check_start_config(config)

        if combined_counters is None:
            return None
        else:
            config['counters'] = combined_counters

        self.keystore = SecureCounters(config['counters'], counter_modulus())
        share_list = config['shares']

        private_key = load_private_key_file(self.config['key'])
        for share in share_list:
            encrypted_secret = share['secret']
            secret = decrypt(private_key, encrypted_secret)
            # TODO: secure delete
            share['secret'] = secret
            blinding_result = self.keystore.import_blinding_share(share)
            if not blinding_result:
                # the structure of the imported share did not match the
                # configured counters
                # this is likely a configuration error or a programming bug,
                # but there is also no way to detect the TS modifying the data
                logging.warning("failed to import blinding share {} config {}"
                                .format(share, config))
                # TODO: secure delete
                del private_key
                return None

        logging.info("successfully started and imported {} blinding shares for {} counters ({} bins)"
                     .format(len(share_list), len(config['counters']), count_bins(config['counters'])))
        # TODO: secure delete
        del private_key
        return {}
Ejemplo n.º 2
0
# this test will exit successfully, unless the counters are more than
# MAX_DIVERGENCE from the full range or equal bin counts

from random import SystemRandom

from privcount.counter import sample, sample_randint, derive_blinding_factor, counter_modulus

# Allow this much divergence from the full range and equal bin counts
MAX_DIVERGENCE = 0.02
MAX_DIVERGENCE_PERCENT = MAX_DIVERGENCE * 100.0

# some of the privcount random functions expect additional arguments
POSITIVE = True

# the hard-coded modulus value
PRIV_COUNTER_MODULUS = counter_modulus()

# the number of random values used in each trial
N_TRIALS = 100000

# the number of partitions used to check that values are uniformly distributed
BIN_COUNT = 2

# Each of these value functions should return a uniformly distributed
# pseudo-random value in [0, modulus)

def random_value(modulus):
    '''
    call python's random.randrange(modulus)
    '''
    # random.randrange() takes one argument: a maximum value
Ejemplo n.º 3
0
from math import sqrt
from random import SystemRandom

from privcount.counter import SecureCounters, adjust_count_signed, counter_modulus, add_counter_limits_to_config, get_events_for_known_counters
SINGLE_BIN = SecureCounters.SINGLE_BIN

import logging
# DEBUG logs every check: use it on failure
# INFO logs each major counter size increase
logging.basicConfig(level=logging.INFO)
logging.root.name = ''

# When testing counter modulus values, use this range
modulus_min = 1L
# test at least 2**64, or 2**5 times our current limit
modulus_max = max(2L**64L, counter_modulus() * 2L**5L)

# A simple set of byte counters
counters = {
    'ZeroCount': {
        'bins': [
            [0.0, float('inf')],
        ],
        'sigma': 0.0
    },
    'ByteCount': {
        'bins': [
            [0.0, float('inf')],
        ],
        'sigma': 0.0
    },
Ejemplo n.º 4
0
from privcount.counter import counter_modulus
from privcount.crypto import load_public_key_file, load_private_key_file, encrypt_pk, decrypt_pk, generate_symmetric_key, encrypt_symmetric, decrypt_symmetric, encode_data, decode_data, encrypt, decrypt

import logging
# DEBUG logs every check: use it on failure
# INFO logs each check once
logging.basicConfig(level=logging.INFO)
logging.root.name = ''

# What range of random numbers should we use for ints and longs?
INT_BITS = 64 if sys.maxsize > 2**32 else 32
RAND_INT_BITS = INT_BITS - 2
# Use a maximum long that's larger than an int, the modulus, and a double's
# integer-fidelity range
RAND_LONG_BITS = max(INT_BITS,
                     counter_modulus().bit_length(),
                     sys.float_info.mant_dig) + 1

# How long should the random string be (in unencoded bytes)?
RAND_STR_BYTES = 20

# The paths to the RSA keys, based on the location of privcount/test
PRIVCOUNT_DIRECTORY = environ.get('PRIVCOUNT_DIRECTORY', getcwd())
TEST_DIRECTORY = path.join(PRIVCOUNT_DIRECTORY, 'test')
PUBLIC_KEY_PATH = path.join(TEST_DIRECTORY, 'keys/test.cert')
PRIVATE_KEY_PATH = path.join(TEST_DIRECTORY, 'keys/test.pem')

# This is the maximum number of bytes OpenSSL will encrypt with PrivCount's
# current public key size (determined by trying different values)
PK_ENCRYPTION_LENGTH_MAX = 446