~gagbo/diceware.py

5e095495691260b4f8f6a5183cf73a85d4e1dc48 — Gerry Agbobada 2 years ago 294519b
Ensure unique random_generator in DicewareResult

This was the issue with the tests running non-system random for
deterministic passphrases.

Signed-off-by: Gerry Agbobada <gagbobada+git@gmail.com>
2 files changed, 28 insertions(+), 24 deletions(-)

M dice_rolls/diceware_result.py
M tests/test_dice_rolls.py
M dice_rolls/diceware_result.py => dice_rolls/diceware_result.py +24 -22
@@ 29,20 29,36 @@ class DicewareResult:
        These 'rolls' which are really 5-uples are the basis for generating
        the true passphrase using a dictionary
        """
        self.rolls = generate_rolls(rolls=self.wordsCount,
                                    systemRand=self.systemRand)
        if self.systemRand:
            random_machine = random.SystemRandom()
        else:
            random_machine = random.Random()
        self.rolls = self.generate_rolls()
        self.ensure_random_generator()

        if self.bonusRoll:
            self.salt = roll_5_dice(random_machine)
            self.salt = roll_5_dice(self.random_generator)
            while self.salt[0] > self.wordsCount:
                self.salt = roll_5_dice(random_machine)
                self.salt = roll_5_dice(self.random_generator)
        else:
            self.salt = None

    def generate_rolls(self):
        """ generate_rolls generates a rolls-uple of 5-uple of [1,6] integers
        """
        self.ensure_random_generator()

        result = []
        for i in range(self.wordsCount):
            result.append(roll_5_dice(self.random_generator))
        return tuple(result)

    def ensure_random_generator(self):
        """ Create a random generator attribute if not created yet."""
        if hasattr(self, "random_generator"):
            return

        if self.systemRand:
            self.random_generator = random.SystemRandom()
        else:
            self.random_generator = random.Random()

    def __str__(self):
        """ Method called for str(self) and print(self)
        Useful for debugging purposes


@@ 102,20 118,6 @@ def roll_5_dice(gen):
            gen.randint(1, 6))


def generate_rolls(rolls=5, systemRand=True):
    """ generate_rolls generates a rolls-uple of 5-uple of [1,6] integers
    """
    if systemRand:
        random_machine = random.SystemRandom()
    else:
        random_machine = random.Random()

    result = []
    for i in range(rolls):
        result.append(roll_5_dice(random_machine))
    return tuple(result)


def get_salt_char(digitThree=0, digitFour=0):
    """ get_salt_char returns a char to use as additional char from salt
    It takes 2 digits in the range [1,6] as parameters digitThree digitFour.

M tests/test_dice_rolls.py => tests/test_dice_rolls.py +4 -2
@@ 53,7 53,8 @@ def test_non_system_rand():
    stored_results = []
    result = dw.DicewareResult(wordsCount=5, systemRand=False, bonusRoll=True)

    random.seed("Whatever")
    result.ensure_random_generator()
    result.random_generator.seed(15)
    state = random.getstate()

    result.make_rolls()


@@ 61,7 62,8 @@ def test_non_system_rand():
    result.make_rolls()
    stored_results.append(copy.deepcopy(result))

    random.setstate(state)
    #result.random_generator.setstate(state)
    result.random_generator.seed(15)
    result.make_rolls()
    stored_results.append(copy.deepcopy(result))
    assert stored_results[0].rolls != stored_results[1].rolls