aboutsummaryrefslogtreecommitdiff
path: root/passgen/diceware/src/main/kotlin/app
diff options
context:
space:
mode:
Diffstat (limited to 'passgen/diceware/src/main/kotlin/app')
-rw-r--r--passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/DicewarePassphraseGenerator.kt39
-rw-r--r--passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/Die.kt30
-rw-r--r--passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/RandomIntGenerator.kt15
-rw-r--r--passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/WordListParser.kt21
4 files changed, 105 insertions, 0 deletions
diff --git a/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/DicewarePassphraseGenerator.kt b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/DicewarePassphraseGenerator.kt
new file mode 100644
index 00000000..841eb31b
--- /dev/null
+++ b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/DicewarePassphraseGenerator.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.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 buildString {
+ repeat(wordCount) { idx ->
+ append(wordMap[die.rollMultiple(DIGITS)])
+ if (idx < wordCount - 1) append(separator)
+ }
+ }
+ }
+
+ private companion object {
+
+ /** Number of digits used by indices in the default wordlist. */
+ const val DIGITS: Int = 5
+ }
+}
diff --git a/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/Die.kt b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/Die.kt
new file mode 100644
index 00000000..e3db4b80
--- /dev/null
+++ b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/Die.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.passgen.diceware
+
+import javax.inject.Inject
+
+/** Basic implementation of a die with configurable number of sides. */
+public class Die
+@Inject
+constructor(
+ private val sides: Int,
+ private val random: RandomIntGenerator,
+) {
+
+ /** Roll the die to return a single number. */
+ public fun roll(): Int {
+ return random.get(1..sides)
+ }
+
+ /**
+ * Roll the die multiple times, concatenating each result to obtain a number with [iterations]
+ * digits.
+ */
+ public fun rollMultiple(iterations: Int): Int {
+ return StringBuilder().apply { repeat(iterations) { append(roll()) } }.toString().toInt()
+ }
+}
diff --git a/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/RandomIntGenerator.kt b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/RandomIntGenerator.kt
new file mode 100644
index 00000000..18a828a6
--- /dev/null
+++ b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/RandomIntGenerator.kt
@@ -0,0 +1,15 @@
+/*
+ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.passgen.diceware
+
+/**
+ * SAM interface that takes in an [IntRange] and returns a randomly chosen [Int] within its bounds.
+ * This is used as a replacement for [kotlin.random.Random] since there is no CSPRNG-backed
+ * implementation of it in the Kotlin stdlib.
+ */
+public fun interface RandomIntGenerator {
+ public fun get(range: IntRange): Int
+}
diff --git a/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/WordListParser.kt b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/WordListParser.kt
new file mode 100644
index 00000000..6c7f5310
--- /dev/null
+++ b/passgen/diceware/src/main/kotlin/app/passwordstore/passgen/diceware/WordListParser.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.passgen.diceware
+
+import java.io.InputStream
+
+internal object WordListParser {
+ fun parse(wordlistStream: InputStream) =
+ wordlistStream
+ .bufferedReader()
+ .lineSequence()
+ .map { line -> line.split(DELIMITER) }
+ .filter { items -> items.size == 2 && items[0].toIntOrNull() != null }
+ .map { items -> items[0].toInt() to items[1] }
+ .toMap()
+
+ private const val DELIMITER = "\t"
+}