diff --git a/app/build.gradle b/app/build.gradle index 8b6e69c..aea8658 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { buildToolsVersion "29.0.2" defaultConfig { applicationId "im.status.keycard.connect" - minSdkVersion 21 + minSdkVersion 23 targetSdkVersion 29 versionCode 1 versionName "1.0" @@ -45,6 +45,7 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0' implementation 'androidx.navigation:navigation-ui-ktx:2.1.0' + implementation 'androidx.security:security-crypto:1.0.0-alpha02' implementation 'org.bouncycastle:bcprov-jdk15on:1.64' implementation 'com.github.status-im.status-keycard-java:android:3.0.1' implementation "com.github.walletconnect:kotlin-walletconnect-lib:0.9.3" diff --git a/app/src/main/java/im/status/keycard/connect/InitActivity.kt b/app/src/main/java/im/status/keycard/connect/InitActivity.kt index 2290c8b..64f2a1c 100644 --- a/app/src/main/java/im/status/keycard/connect/InitActivity.kt +++ b/app/src/main/java/im/status/keycard/connect/InitActivity.kt @@ -8,6 +8,7 @@ import android.util.Base64 import android.view.View import im.status.keycard.globalplatform.Crypto import android.util.Base64.NO_PADDING +import android.util.Base64.NO_WRAP import android.widget.TextView @@ -49,6 +50,6 @@ class InitActivity : AppCompatActivity() { } fun randomToken(length: Int): String { - return Base64.encodeToString(Crypto.randomBytes(length), NO_PADDING) + return Base64.encodeToString(Crypto.randomBytes(length), NO_PADDING or NO_WRAP) } } diff --git a/app/src/main/java/im/status/keycard/connect/MainActivity.kt b/app/src/main/java/im/status/keycard/connect/MainActivity.kt index a99f7a9..51744d6 100644 --- a/app/src/main/java/im/status/keycard/connect/MainActivity.kt +++ b/app/src/main/java/im/status/keycard/connect/MainActivity.kt @@ -11,6 +11,7 @@ import androidx.navigation.ui.setupWithNavController import im.status.keycard.android.NFCCardManager import android.content.Intent import im.status.keycard.connect.card.* +import im.status.keycard.connect.data.PairingManager class MainActivity : AppCompatActivity() { private lateinit var cardManager: NFCCardManager @@ -26,6 +27,8 @@ class MainActivity : AppCompatActivity() { val appBarConfiguration = AppBarConfiguration(setOf(R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)) + PairingManager.init(this) + nfcAdapter = NfcAdapter.getDefaultAdapter(this) executor = CardScriptExecutor(this) executor.setScript(listOf(SelectCommand(), InitCommand(), OpenSecureChannelCommand(), VerifyPINCommand())) diff --git a/app/src/main/java/im/status/keycard/connect/card/OpenSecureChannelCommand.kt b/app/src/main/java/im/status/keycard/connect/card/OpenSecureChannelCommand.kt index 6fbf67a..115a454 100644 --- a/app/src/main/java/im/status/keycard/connect/card/OpenSecureChannelCommand.kt +++ b/app/src/main/java/im/status/keycard/connect/card/OpenSecureChannelCommand.kt @@ -29,6 +29,8 @@ class OpenSecureChannelCommand : CardCommand { PairingManager.putPairing(cmdSet.applicationInfo.instanceUID, cmdSet.pairing) cmdSet.autoOpenSecureChannel() return CommandResult.OK + } catch(e: IOException) { + e.printStackTrace() } finally { pairingPassword = null } diff --git a/app/src/main/java/im/status/keycard/connect/data/PairingManager.kt b/app/src/main/java/im/status/keycard/connect/data/PairingManager.kt index 148f4b6..cad1b6a 100644 --- a/app/src/main/java/im/status/keycard/connect/data/PairingManager.kt +++ b/app/src/main/java/im/status/keycard/connect/data/PairingManager.kt @@ -1,21 +1,43 @@ package im.status.keycard.connect.data +import android.content.Context +import android.content.SharedPreferences +import android.util.Base64 +import android.util.Base64.NO_PADDING +import android.util.Base64.NO_WRAP import im.status.keycard.applet.Pairing +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKeys + object PairingManager { - //TODO: persistency + private lateinit var sharedPreferences: SharedPreferences - private val pairings: MutableMap = HashMap() + private fun id(instanceUID: ByteArray) : String { + return Base64.encodeToString(instanceUID, NO_PADDING or NO_WRAP) + } + + fun init(context: Context) { + val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) + sharedPreferences = EncryptedSharedPreferences.create("pairings", masterKeyAlias, context, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM) + } fun getPairing(instanceUID: ByteArray): Pairing? { - return pairings[ByteArrayKey(instanceUID)] + val p = sharedPreferences.getString(id(instanceUID), null) + return if (p != null) Pairing(p) else null } fun putPairing(instanceUID: ByteArray, pairing: Pairing) { - pairings[ByteArrayKey(instanceUID)] = pairing + sharedPreferences.edit().apply { + putString(id(instanceUID), pairing.toBase64()) + apply() + } } fun removePairing(instanceUID: ByteArray) { - pairings.remove(ByteArrayKey(instanceUID)) + sharedPreferences.edit().apply { + remove(id(instanceUID)) + apply() + } } } \ No newline at end of file