Factor getting secure random bytes into Crypto interface
diff --git a/app/src/main/java/com/stevesoltys/seedvault/crypto/Crypto.kt b/app/src/main/java/com/stevesoltys/seedvault/crypto/Crypto.kt
index ebe74c0..ada5b75 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/crypto/Crypto.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/crypto/Crypto.kt
@@ -13,6 +13,7 @@
 import java.io.InputStream
 import java.io.OutputStream
 import java.security.GeneralSecurityException
+import java.security.SecureRandom
 import javax.crypto.spec.SecretKeySpec
 
 /**
@@ -34,6 +35,11 @@
 internal interface Crypto {
 
     /**
+     * Returns a ByteArray with bytes retrieved from [SecureRandom].
+     */
+    fun getRandomBytes(size: Int): ByteArray
+
+    /**
      * Returns a [AesGcmHkdfStreaming] encrypting stream
      * that gets encrypted and authenticated the given associated data.
      */
@@ -107,6 +113,11 @@
     private val key: ByteArray by lazy {
         deriveStreamKey(keyManager.getMainKey(), "app data key".toByteArray())
     }
+    private val secureRandom: SecureRandom by lazy { SecureRandom() }
+
+    override fun getRandomBytes(size: Int) = ByteArray(size).apply {
+        secureRandom.nextBytes(this)
+    }
 
     @Throws(IOException::class, GeneralSecurityException::class)
     override fun newEncryptingStream(
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeViewModel.kt
index ff649ee..c1bf6e3 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeViewModel.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeViewModel.kt
@@ -22,7 +22,6 @@
 import kotlinx.coroutines.launch
 import org.calyxos.backup.storage.api.StorageBackup
 import java.io.IOException
-import java.security.SecureRandom
 
 internal const val WORD_NUM = 12
 
@@ -40,8 +39,7 @@
 
     internal val wordList: List<CharArray> by lazy {
         // we use our own entropy to not having to trust the library to use SecureRandom
-        val entropy = ByteArray(Mnemonics.WordCount.COUNT_12.bitLength / 8)
-        SecureRandom().nextBytes(entropy)
+        val entropy = crypto.getRandomBytes(Mnemonics.WordCount.COUNT_12.bitLength / 8)
         // create the words from the entropy
         Mnemonics.MnemonicCode(entropy).words
     }
diff --git a/app/src/test/java/com/stevesoltys/seedvault/crypto/CryptoIntegrationTest.kt b/app/src/test/java/com/stevesoltys/seedvault/crypto/CryptoIntegrationTest.kt
index bf09d0d..7eedba1 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/crypto/CryptoIntegrationTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/crypto/CryptoIntegrationTest.kt
@@ -2,6 +2,9 @@
 
 import com.stevesoltys.seedvault.assertReadEquals
 import com.stevesoltys.seedvault.header.HeaderReaderImpl
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.hamcrest.Matchers.not
 import org.junit.jupiter.api.Assertions.assertThrows
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.TestInstance
@@ -22,6 +25,14 @@
     private val cleartext = Random.nextBytes(Random.nextInt(1, 422300))
 
     @Test
+    fun `sanity check for getRandomBytes()`() {
+        assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
+        assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
+        assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
+        assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
+    }
+
+    @Test
     fun `decrypting encrypted cleartext works`() {
         val ad = Random.nextBytes(42)
         val outputStream = ByteArrayOutputStream()