1
0
Fork 0
seedvault/app/src/main/java/com/stevesoltys/backup/settings/RecoveryCodeViewModel.kt
Torsten Grote 2ce625ac87
Huge refactoring of backup transport
* to get rid of global state
* to have a testable architecture
* to allow for authenticated encryption
* to have a backup format version
* to potentially allow for other storage plugins
2019-09-02 09:47:49 -03:00

59 lines
2.3 KiB
Kotlin

package com.stevesoltys.backup.settings
import android.app.Application
import android.util.ByteStringUtils.toHexString
import androidx.lifecycle.AndroidViewModel
import com.stevesoltys.backup.Backup
import com.stevesoltys.backup.LiveEvent
import com.stevesoltys.backup.MutableLiveEvent
import io.github.novacrypto.bip39.*
import io.github.novacrypto.bip39.Validation.InvalidChecksumException
import io.github.novacrypto.bip39.Validation.InvalidWordCountException
import io.github.novacrypto.bip39.Validation.UnexpectedWhiteSpaceException
import io.github.novacrypto.bip39.Validation.WordNotFoundException
import io.github.novacrypto.bip39.wordlists.English
import java.security.SecureRandom
import java.util.*
internal const val WORD_NUM = 12
class RecoveryCodeViewModel(application: Application) : AndroidViewModel(application) {
internal val wordList: List<CharSequence> by lazy {
val items: ArrayList<CharSequence> = ArrayList(WORD_NUM)
// TODO factor out entropy generation
val entropy = ByteArray(Words.TWELVE.byteLength())
SecureRandom().nextBytes(entropy)
MnemonicGenerator(English.INSTANCE).createMnemonic(entropy) {
if (it != " ") items.add(it)
}
items
}
private val mConfirmButtonClicked = MutableLiveEvent<Boolean>()
internal val confirmButtonClicked: LiveEvent<Boolean> = mConfirmButtonClicked
internal fun onConfirmButtonClicked() = mConfirmButtonClicked.setEvent(true)
private val mRecoveryCodeSaved = MutableLiveEvent<Boolean>()
internal val recoveryCodeSaved: LiveEvent<Boolean> = mRecoveryCodeSaved
@Throws(WordNotFoundException::class, InvalidChecksumException::class)
fun validateAndContinue(input: List<CharSequence>) {
try {
MnemonicValidator.ofWordList(English.INSTANCE).validate(input)
} catch (e: UnexpectedWhiteSpaceException) {
throw AssertionError(e)
} catch (e: InvalidWordCountException) {
throw AssertionError(e)
}
val mnemonic = input.joinToString(" ")
val seed = SeedCalculator(JavaxPBKDF2WithHmacSHA512.INSTANCE).calculateSeed(mnemonic, "")
Backup.keyManager.storeBackupKey(seed)
// TODO remove once encryption/decryption uses key from KeyStore
setBackupPassword(getApplication(), toHexString(seed))
mRecoveryCodeSaved.setEvent(true)
}
}