Use EncryptedSharedPreferences for HMAC key storage
Replace plain-text SharedPreferences with AES256-GCM encrypted prefs via androidx.security:security-crypto. Adds PrefsHelper utility to centralize encrypted prefs access across MainActivity, SettingsActivity and UsbKeyReceiver. Reviewed in codereview.md (recommendation #2).
This commit is contained in:
parent
4a70f94a51
commit
b5d42d53ba
5 changed files with 42 additions and 10 deletions
|
|
@ -42,4 +42,5 @@ dependencies {
|
||||||
implementation 'io.github.dkaukov:esp32-flash-lib:1.1.17'
|
implementation 'io.github.dkaukov:esp32-flash-lib:1.1.17'
|
||||||
implementation 'com.eclipsesource.minimal-json:minimal-json:0.9.5'
|
implementation 'com.eclipsesource.minimal-json:minimal-json:0.9.5'
|
||||||
implementation 'org.slf4j:slf4j-nop:2.0.16'
|
implementation 'org.slf4j:slf4j-nop:2.0.16'
|
||||||
|
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
||||||
}
|
}
|
||||||
|
|
@ -164,8 +164,8 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadHmacKey() {
|
private fun loadHmacKey() {
|
||||||
val prefs = getSharedPreferences(SettingsActivity.PREFS_NAME, Context.MODE_PRIVATE)
|
val prefs = PrefsHelper.getPrefs(this)
|
||||||
val hexKey = prefs.getString(SettingsActivity.PREF_KEY, null)
|
val hexKey = prefs.getString(PrefsHelper.PREF_KEY, null)
|
||||||
hmacKey = hexKey?.let { hexStringToBytes(it) }
|
hmacKey = hexKey?.let { hexStringToBytes(it) }
|
||||||
Log.d(TAG, "HMAC key loaded: ${if (hmacKey != null) "${hmacKey!!.size} bytes" else "none"}")
|
Log.d(TAG, "HMAC key loaded: ${if (hmacKey != null) "${hmacKey!!.size} bytes" else "none"}")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
33
android/app/src/main/java/com/eddy/atomrelay/PrefsHelper.kt
Normal file
33
android/app/src/main/java/com/eddy/atomrelay/PrefsHelper.kt
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.eddy.atomrelay
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
|
import androidx.security.crypto.MasterKey
|
||||||
|
|
||||||
|
object PrefsHelper {
|
||||||
|
|
||||||
|
private const val TAG = "PrefsHelper"
|
||||||
|
const val PREFS_NAME = "relay_prefs"
|
||||||
|
const val PREF_KEY = "hmac_key"
|
||||||
|
|
||||||
|
fun getPrefs(context: Context): SharedPreferences {
|
||||||
|
return try {
|
||||||
|
val masterKey = MasterKey.Builder(context)
|
||||||
|
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
EncryptedSharedPreferences.create(
|
||||||
|
context,
|
||||||
|
PREFS_NAME,
|
||||||
|
masterKey,
|
||||||
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to create EncryptedSharedPreferences", e)
|
||||||
|
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,8 +27,6 @@ import java.security.SecureRandom
|
||||||
class SettingsActivity : AppCompatActivity() {
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PREFS_NAME = "relay_prefs"
|
|
||||||
const val PREF_KEY = "hmac_key"
|
|
||||||
const val RESULT_SCAN = 100
|
const val RESULT_SCAN = 100
|
||||||
private const val TAG = "SettingsActivity"
|
private const val TAG = "SettingsActivity"
|
||||||
private const val ESP_VENDOR_ID = 0x303a
|
private const val ESP_VENDOR_ID = 0x303a
|
||||||
|
|
@ -158,8 +156,8 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
handler.post {
|
handler.post {
|
||||||
when (result) {
|
when (result) {
|
||||||
is KeyResult.Success -> {
|
is KeyResult.Success -> {
|
||||||
val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
val prefs = PrefsHelper.getPrefs(this@SettingsActivity)
|
||||||
prefs.edit().putString(PREF_KEY, result.hexKey).apply()
|
prefs.edit().putString(PrefsHelper.PREF_KEY, result.hexKey).apply()
|
||||||
Toast.makeText(this, "Beveiligingssleutel gelezen", Toast.LENGTH_LONG).show()
|
Toast.makeText(this, "Beveiligingssleutel gelezen", Toast.LENGTH_LONG).show()
|
||||||
cleanupAction()
|
cleanupAction()
|
||||||
setResult(RESULT_SCAN)
|
setResult(RESULT_SCAN)
|
||||||
|
|
|
||||||
|
|
@ -211,8 +211,8 @@ class UsbKeyReceiver : BroadcastReceiver() {
|
||||||
val hexKey = keyLine.removePrefix("HMAC_KEY:").trim()
|
val hexKey = keyLine.removePrefix("HMAC_KEY:").trim()
|
||||||
if (hexKey.length == 64 && hexKey.all { it in "0123456789ABCDEFabcdef" }) {
|
if (hexKey.length == 64 && hexKey.all { it in "0123456789ABCDEFabcdef" }) {
|
||||||
val upperKey = hexKey.uppercase()
|
val upperKey = hexKey.uppercase()
|
||||||
val prefs = context.getSharedPreferences(SettingsActivity.PREFS_NAME, Context.MODE_PRIVATE)
|
val prefs = PrefsHelper.getPrefs(context)
|
||||||
prefs.edit().putString(SettingsActivity.PREF_KEY, upperKey).apply()
|
prefs.edit().putString(PrefsHelper.PREF_KEY, upperKey).apply()
|
||||||
Log.d(TAG, "HMAC key saved (${upperKey.length} chars)")
|
Log.d(TAG, "HMAC key saved (${upperKey.length} chars)")
|
||||||
handler.post {
|
handler.post {
|
||||||
Toast.makeText(context, "Beveiligingssleutel gelezen", Toast.LENGTH_LONG).show()
|
Toast.makeText(context, "Beveiligingssleutel gelezen", Toast.LENGTH_LONG).show()
|
||||||
|
|
@ -248,8 +248,8 @@ class UsbKeyReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
if (okSb.contains("OK")) {
|
if (okSb.contains("OK")) {
|
||||||
Log.d(TAG, "Key provisioned successfully, saving to prefs")
|
Log.d(TAG, "Key provisioned successfully, saving to prefs")
|
||||||
val prefs = context.getSharedPreferences(SettingsActivity.PREFS_NAME, Context.MODE_PRIVATE)
|
val prefs = PrefsHelper.getPrefs(context)
|
||||||
prefs.edit().putString(SettingsActivity.PREF_KEY, newKey).apply()
|
prefs.edit().putString(PrefsHelper.PREF_KEY, newKey).apply()
|
||||||
handler.post {
|
handler.post {
|
||||||
Toast.makeText(context, "Beveiligingssleutel gelezen", Toast.LENGTH_LONG).show()
|
Toast.makeText(context, "Beveiligingssleutel gelezen", Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue