From c5436b543df466657a1d0dc3af40d4707fca9b9d Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Fri, 10 Dec 2021 13:59:32 +0530 Subject: [PATCH] diceware: add passphrase generator --- passgen/diceware/api/diceware.api | 6 +++ .../diceware/DicewarePassphraseGenerator.kt | 42 +++++++++++++++++++ .../DicewarePassphraseGeneratorTest.kt | 29 +++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 passgen/diceware/src/main/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGenerator.kt create mode 100644 passgen/diceware/src/test/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGeneratorTest.kt diff --git a/passgen/diceware/api/diceware.api b/passgen/diceware/api/diceware.api index 8d16ae8f..925d6739 100644 --- a/passgen/diceware/api/diceware.api +++ b/passgen/diceware/api/diceware.api @@ -1,3 +1,9 @@ +public final class dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGenerator { + public static final field DIGITS I + public fun (Ldev/msfjarvis/aps/passgen/diceware/Die;Ljava/io/InputStream;)V + public final fun generatePassphrase (IC)Ljava/lang/String; +} + public final class dev/msfjarvis/aps/passgen/diceware/Die { public fun (ILdev/msfjarvis/aps/passgen/diceware/RandomIntGenerator;)V public final fun roll ()I diff --git a/passgen/diceware/src/main/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGenerator.kt b/passgen/diceware/src/main/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGenerator.kt new file mode 100644 index 00000000..ee18352e --- /dev/null +++ b/passgen/diceware/src/main/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGenerator.kt @@ -0,0 +1,42 @@ +/* + * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.passgen.diceware + +import java.io.InputStream +import javax.inject.Inject + +/** + * Password generator implementing the Diceware passphrase generation mechanism. For detailed + * information on how this works, see https://theworld.com/~reinhold/diceware.html. + */ +public class DicewarePassphraseGenerator +@Inject +constructor( + private val die: Die, + wordList: InputStream, +) { + + private val wordMap = WordListParser.parse(wordList) + + /** Generates a passphrase with [wordCount] words. */ + public fun generatePassphrase(wordCount: Int, separator: Char): String { + return StringBuilder() + .apply { + repeat(wordCount) { idx -> + append(wordMap[die.rollMultiple(DIGITS)]) + if (idx < wordCount - 1) append(separator) + } + } + .toString() + .trimEnd() + } + + private companion object { + + /** Number of digits used by indices in the default wordlist. */ + const val DIGITS: Int = 5 + } +} diff --git a/passgen/diceware/src/test/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGeneratorTest.kt b/passgen/diceware/src/test/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGeneratorTest.kt new file mode 100644 index 00000000..7f22fdcc --- /dev/null +++ b/passgen/diceware/src/test/kotlin/dev/msfjarvis/aps/passgen/diceware/DicewarePassphraseGeneratorTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.passgen.diceware + +import kotlin.random.Random +import kotlin.test.assertEquals +import org.junit.Test + +class DicewarePassphraseGeneratorTest { + /** Pre-seeded [Random] instance to ensure tests are deterministic. */ + private val random = Random(1_00_000) + + private val intGenerator = RandomIntGenerator { it.random(random) } + @Test + fun generate_passphrase() { + val die = Die(6, intGenerator) + + val generator = + DicewarePassphraseGenerator( + die, + WordListParserTest.getDefaultWordList(), + ) + + assertEquals("salvation_cozily_croon_trustee_fidgety", generator.generatePassphrase(5, '_')) + } +}