Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using a constant key alias #21

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package com.bitmark.libauk.storage

import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.security.crypto.EncryptedFile
import androidx.security.crypto.MasterKey
import io.reactivex.Completable
import io.reactivex.Single
import java.io.ByteArrayOutputStream
import java.io.File
import java.security.KeyStore
import java.util.*
import android.os.Build
import android.util.Log
import java.security.KeyStore

internal interface SecureFileStorage {

Expand All @@ -22,21 +20,15 @@ internal interface SecureFileStorage {
fun isExistingOnFilesDir(name: String): Boolean

fun deleteOnFilesDir(name: String): Boolean

fun cleanKeyStoreSharedPref()
}

internal class SecureFileStorageImpl(
private val context: Context,
private val alias: UUID
) : SecureFileStorage {

private val keyStore: KeyStore = KeyStore.getInstance(ANDROID_KEY_STORE).apply { load(null) }
private val sharedPreferences = context.getSharedPreferences("beaconsdk", Context.MODE_PRIVATE)

private var masterKeyAlias: String?
get() = sharedPreferences.getString(KEY_MASTER_KEY_ALIAS, null)
set(value) {
value?.let { sharedPreferences.edit().putString(KEY_MASTER_KEY_ALIAS, it).apply() }
}
private fun getFileName(name: String) = "$alias-${name}-default_alias"

private fun write(path: String, name: String, data: ByteArray) {
val file = getEncryptedFile("$path/$name", false)
Expand All @@ -48,7 +40,13 @@ internal class SecureFileStorageImpl(
}

override fun writeOnFilesDir(name: String, data: ByteArray) {
write(context.filesDir.absolutePath, "$alias-$name", data)
try {
write(context.filesDir.absolutePath, getFileName(name), data)
} catch (e: Exception) {
Log.e("writeOnFilesDir", "error: $e")
cleanKeyStoreSharedPref()
write(context.filesDir.absolutePath, getFileName(name), data)
}
}

private fun read(path: String): ByteArray {
Expand All @@ -64,15 +62,21 @@ internal class SecureFileStorageImpl(
return os.toByteArray()
}

override fun readOnFilesDir(name: String): ByteArray =
read(File(context.filesDir, "$alias-$name").absolutePath)
override fun readOnFilesDir(name: String): ByteArray = try {
read(File(context.filesDir, getFileName(name)).absolutePath)
} catch (e: Exception) {
Log.e("readOnFilesDir", "error: $e")
cleanKeyStoreSharedPref()
read(File(context.filesDir, getFileName(name)).absolutePath)
}

private fun isExisting(path: String): Boolean = File(path).exists()

override fun isExistingOnFilesDir(name: String): Boolean =
isExisting(File(context.filesDir, "$alias-$name").absolutePath)
isExisting(File(context.filesDir, getFileName(name)).absolutePath)

private fun delete(path: String): Boolean = File(path).let { file ->
Log.d("delete path", "path to delete: $path")
if (!file.exists()) true
else if (file.isDirectory) {
file.deleteRecursively()
Expand All @@ -82,7 +86,19 @@ internal class SecureFileStorageImpl(
}

override fun deleteOnFilesDir(name: String): Boolean =
delete(File(context.filesDir, "$alias-$name").absolutePath)
delete(File(context.filesDir, getFileName(name)).absolutePath)

override fun cleanKeyStoreSharedPref() {
val prefNames = listOf(
"__androidx_security_crypto_encrypted_file_pref__",
"beaconsdk"
) // List your shared preferences file names contains keystore alias
for (prefName in prefNames) {
val sharedPreferences =
context.getSharedPreferences(prefName, Context.MODE_PRIVATE)
sharedPreferences.edit().clear().apply()
}
}

private fun getEncryptedFile(path: String, read: Boolean) = File(path).let { f ->
if (f.isDirectory) throw IllegalArgumentException("do not support directory")
Expand All @@ -102,33 +118,16 @@ internal class SecureFileStorageImpl(
)

private fun getMasterKey(): MasterKey {
keyStore.load(null)

val keyAlias = masterKeyAlias ?: UUID.randomUUID().toString().also { masterKeyAlias = it }

val parameterSpec = KeyGenParameterSpec.Builder(
keyAlias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).apply {
setKeySize(256)
setDigests(KeyProperties.DIGEST_SHA512)
setUserAuthenticationRequired(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setUnlockedDeviceRequired(true)
}
setRandomizedEncryptionRequired(true)
setBlockModes(KeyProperties.BLOCK_MODE_GCM)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
}.build()

return MasterKey.Builder(context, keyAlias)
.setKeyGenParameterSpec(parameterSpec)
KeyStore.getInstance(ANDROID_KEY_STORE).apply { load(null) }
return MasterKey.Builder(context, DEFAULT_MASTER_KEY_ALIAS)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.setUserAuthenticationRequired(false)
.build()
}

companion object {
private const val ANDROID_KEY_STORE = "AndroidKeyStore"
private const val KEY_MASTER_KEY_ALIAS = "masterKeyAlias"
private const val DEFAULT_MASTER_KEY_ALIAS = "_default_master_key_alias_"
}
}

Expand Down
13 changes: 9 additions & 4 deletions libauk/src/main/java/com/bitmark/libauk/storage/WalletStorage.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bitmark.libauk.storage

import android.util.Log
import at.favre.lib.hkdf.HKDF
import com.bitmark.libauk.Const.ACCOUNT_DERIVATION_PATH
import com.bitmark.libauk.Const.ENCRYPT_KEY_DERIVATION_PATH
Expand Down Expand Up @@ -38,7 +39,8 @@ interface WalletStorage {
words: List<String>,
passphrase: String? = "",
name: String,
creationDate: Date?
creationDate: Date?,
override: Boolean = false
): Completable

fun isWalletCreated(): Single<Boolean>
Expand Down Expand Up @@ -120,15 +122,16 @@ internal class WalletStorageImpl(private val secureFileStorage: SecureFileStorag
words: List<String>,
passphrase: String?,
name: String,
creationDate: Date?
creationDate: Date?,
override: Boolean
): Completable =
secureFileStorage.rxSingle { storage ->
storage.isExistingOnFilesDir(SEED_FILE_NAME) && storage.isExistingOnFilesDir(
ETH_KEY_INFO_FILE_NAME
)
}
.map { isExisting ->
if (!isExisting) {
if (!isExisting || override) {
val mnemonic = words.joinToString(separator = " ")
val entropy = MnemonicUtils.generateEntropy(mnemonic)
val seed = Seed(entropy, Date(), name, passphrase ?: "")
Expand Down Expand Up @@ -404,18 +407,20 @@ internal class WalletStorageImpl(private val secureFileStorage: SecureFileStorag
}

override fun removeKeys(): Completable = secureFileStorage.rxSingle { storage ->
storage.isExistingOnFilesDir(SEED_FILE_NAME) && storage.isExistingOnFilesDir(
storage.isExistingOnFilesDir(SEED_FILE_NAME) || storage.isExistingOnFilesDir(
ETH_KEY_INFO_FILE_NAME
)
}
.map { isExisting ->
Log.d("removeKeys", "isExisting $isExisting")
if (isExisting) {
true
} else {
throw Throwable("Wallet is not created!")
}
}
.flatMapCompletable {
Log.d("removeKeys", "removing")
secureFileStorage.rxCompletable { storage ->
storage.deleteOnFilesDir(SEED_FILE_NAME)
storage.deleteOnFilesDir(ETH_KEY_INFO_FILE_NAME)
Expand Down