Factor getting secure random bytes into Crypto interface
This commit is contained in:
parent
a77d927624
commit
39cb0c6443
3 changed files with 23 additions and 3 deletions
|
@ -13,6 +13,7 @@ import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.security.GeneralSecurityException
|
import java.security.GeneralSecurityException
|
||||||
|
import java.security.SecureRandom
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,6 +34,11 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
*/
|
*/
|
||||||
internal interface Crypto {
|
internal interface Crypto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a ByteArray with bytes retrieved from [SecureRandom].
|
||||||
|
*/
|
||||||
|
fun getRandomBytes(size: Int): ByteArray
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [AesGcmHkdfStreaming] encrypting stream
|
* Returns a [AesGcmHkdfStreaming] encrypting stream
|
||||||
* that gets encrypted and authenticated the given associated data.
|
* that gets encrypted and authenticated the given associated data.
|
||||||
|
@ -107,6 +113,11 @@ internal class CryptoImpl(
|
||||||
private val key: ByteArray by lazy {
|
private val key: ByteArray by lazy {
|
||||||
deriveStreamKey(keyManager.getMainKey(), "app data key".toByteArray())
|
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)
|
@Throws(IOException::class, GeneralSecurityException::class)
|
||||||
override fun newEncryptingStream(
|
override fun newEncryptingStream(
|
||||||
|
|
|
@ -22,7 +22,6 @@ import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.calyxos.backup.storage.api.StorageBackup
|
import org.calyxos.backup.storage.api.StorageBackup
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.SecureRandom
|
|
||||||
|
|
||||||
internal const val WORD_NUM = 12
|
internal const val WORD_NUM = 12
|
||||||
|
|
||||||
|
@ -40,8 +39,7 @@ internal class RecoveryCodeViewModel(
|
||||||
|
|
||||||
internal val wordList: List<CharArray> by lazy {
|
internal val wordList: List<CharArray> by lazy {
|
||||||
// we use our own entropy to not having to trust the library to use SecureRandom
|
// we use our own entropy to not having to trust the library to use SecureRandom
|
||||||
val entropy = ByteArray(Mnemonics.WordCount.COUNT_12.bitLength / 8)
|
val entropy = crypto.getRandomBytes(Mnemonics.WordCount.COUNT_12.bitLength / 8)
|
||||||
SecureRandom().nextBytes(entropy)
|
|
||||||
// create the words from the entropy
|
// create the words from the entropy
|
||||||
Mnemonics.MnemonicCode(entropy).words
|
Mnemonics.MnemonicCode(entropy).words
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@ package com.stevesoltys.seedvault.crypto
|
||||||
|
|
||||||
import com.stevesoltys.seedvault.assertReadEquals
|
import com.stevesoltys.seedvault.assertReadEquals
|
||||||
import com.stevesoltys.seedvault.header.HeaderReaderImpl
|
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.Assertions.assertThrows
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
|
@ -21,6 +24,14 @@ class CryptoIntegrationTest {
|
||||||
|
|
||||||
private val cleartext = Random.nextBytes(Random.nextInt(1, 422300))
|
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
|
@Test
|
||||||
fun `decrypting encrypted cleartext works`() {
|
fun `decrypting encrypted cleartext works`() {
|
||||||
val ad = Random.nextBytes(42)
|
val ad = Random.nextBytes(42)
|
||||||
|
|
Loading…
Reference in a new issue