You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin Android中获取Xamarin SecureStorage存储的数据?

在Android Kotlin中读取Xamarin SecureStorage存储的数据

核心原理

Xamarin.Essentials的SecureStorage在Android端的存储逻辑如下:

  • 密钥:使用Android KeyStore生成AES密钥,默认别名为xamarin_essentials_secure_storage(API 23+);API 23以下使用RSA密钥(当前设备占比极低)
  • 数据:明文经密钥加密后,以Base64格式存储在名为Xamarin.Essentials.Preferences的SharedPreferences中,键名与调用SecureStorage.SetAsync时传入的一致

实现步骤(Kotlin代码)

1. 读取加密数据

从对应SharedPreferences中取出Base64编码的加密字符串:

val sharedPrefs = context.getSharedPreferences("Xamarin.Essentials.Preferences", Context.MODE_PRIVATE)
val encryptedValue = sharedPrefs.getString("你的存储键名", null) ?: return null

2. 获取KeyStore中的解密密钥

从Android KeyStore中读取Xamarin生成的默认密钥:

private fun getXamarinSecureStorageKey(): SecretKey? {
    return try {
        val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
        val entry = keyStore.getEntry("xamarin_essentials_secure_storage", null) as? KeyStore.SecretKeyEntry
        entry?.secretKey
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

3. 解密数据

Xamarin采用AES/GCM加密,加密后的数据格式为[IV(16字节)][密文][GCM Tag(16字节)],解密时需拆分并处理:

private fun decryptData(encryptedBase64: String, key: SecretKey): String? {
    return try {
        val decodedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT)
        // 拆分IV、密文、Tag
        val iv = decodedBytes.copyOfRange(0, 16)
        val ciphertext = decodedBytes.copyOfRange(16, decodedBytes.size - 16)
        val tag = decodedBytes.copyOfRange(decodedBytes.size - 16, decodedBytes.size)

        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        val spec = GCMParameterSpec(128, iv)
        cipher.init(Cipher.DECRYPT_MODE, key, spec)

        // 合并密文与Tag,执行解密
        val combined = ByteArray(ciphertext.size + tag.size)
        System.arraycopy(ciphertext, 0, combined, 0, ciphertext.size)
        System.arraycopy(tag, 0, combined, ciphertext.size, tag.size)

        val decryptedBytes = cipher.doFinal(combined)
        String(decryptedBytes, Charsets.UTF_8)
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

4. 整合调用

将上述逻辑封装为可直接调用的方法:

fun getXamarinSecureStorageValue(context: Context, key: String): String? {
    // 读取加密数据
    val sharedPrefs = context.getSharedPreferences("Xamarin.Essentials.Preferences", Context.MODE_PRIVATE)
    val encryptedBase64 = sharedPrefs.getString(key, null) ?: return null

    // 获取密钥
    val secretKey = getXamarinSecureStorageKey() ?: return null

    // 解密并返回明文
    return decryptData(encryptedBase64, secretKey)
}

关键注意事项

  • 包名一致性:你的Kotlin应用必须与原Xamarin应用的包名完全相同,否则无法访问沙箱内的SharedPreferences和KeyStore密钥
  • API兼容:如果需要兼容API 23以下设备,需调整为RSA解密逻辑(密钥为RSA私钥,加密算法为RSA/ECB/PKCS1Padding)
  • 无额外权限:访问自身应用的SharedPreferences和KeyStore无需申请特殊权限

内容的提问来源于stack exchange,提问作者Fried Rice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:03:12