英文:
Retrieve Xamarin secured storage data from native Kotlin Android
问题
在Android中检索数据的步骤如下:首先,您需要找到与Xamarin中存储的数据对应的密钥。然后,您需要手动解密数据。
英文:
I have an application written in Xamarin that saves data using SecureStorage.SetAsync. Now I need to convert the application into native Kotlin and Swift projects. Xamarin stores the data in the iOS keychain which is relatively simple to retrieve. However I am struggling to retrieve the data in Kotlin Android as I believe I need to find the key and decrypt the data manually.
How do I go about retrieving the data in Android?
答案1
得分: 1
根据官方文件关于SecureStorage API的平台实现细节,它使用Android本机API Shared Preferences来存储数据。
Android KeyStore用于存储用于在将值保存到Shared Preferences之前加密值的密码密钥,文件名为[YOUR-APP-PACKAGE-ID].xamarinessentials。在共享首选项文件中使用的密钥(不是加密密钥,而是值的密钥)是传递给SecureStorage API的密钥的MD5哈希。
所以我尝试了这个SecureStorage.SetAsync("test", "hahaha");
。然后我搜索了有关共享首选项文件的Android默认位置,它位于/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME.xamarinessentials.xml
。
我使用Android Studio的设备文件浏览器检查了文件:
该值已加密,您可以查看有关加密字符串的源代码。此外,您可以查看有关如何使用共享首选项的源代码var sharedPreferences = GetSharedPreferences(sharedName)
。而sharedName是SecureStorage类中的string Alias = $"{AppInfo.PackageName}.xamarinessentials"
。
因此,我使用Android本机API读取了共享首选项文件:
val name = this.PackageName + ".xamarinessentials"
val sp = GetSharedPreferences(name, FileCreationMode.Private)
val value = sp.GetString("test",null)
调试结果:
该值已加密,您需要根据有关加密字符串的源代码进行解密。因此,您只需将这三行C#代码转换为Kotlin代码以获取该值。
此外,如果您想将Xamarin应用程序转换为Android Kotlin应用程序,您可以直接使用本机SharedPreferences API。我无法理解为什么您需要从本机Kotlin Android中检索Xamarin安全存储的数据。
英文:
According to the official document about the Platform Implementation Specifics of the SecureStorage API, it used the android native api Shared Preferences to store the data.
> The Android KeyStore is used to store the cipher key used to encrypt the value before it is saved into a Shared Preferences with a filename of [YOUR-APP-PACKAGE-ID].xamarinessentials. The key (not a cryptographic key, the key to the value) used in the shared preferences file is a MD5 Hash of the key passed into the SecureStorage APIs.
So I have tried this SecureStorage.SetAsync("test", "hahaha");
. Then I searched about the android default location of the shared preferences file, it is in the /data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME.xamarinessentials.xml
.
I checked the file with the Android Studio's Device File Explorer:
The value has been encrypted, you can check the source code about encrypting the string. In addition, you can check the source code about how did it use the shared preferences var sharedPreferences = GetSharedPreferences(sharedName)
. And the sharedName is the string Alias = $"{AppInfo.PackageName}.xamarinessentials"
in the SecureStorage class.
So I used the android native api to read the shared preferences file:
var name = this.PackageName + ".xamarinessentials";
var sp = GetSharedPreferences(name, FileCreationMode.Private);
var value = sp.GetString("test",null);
And the debug result:
The value is encrypted and you need to decrypt it according to the source code about encrypting the string. So you can just convert the three line c# code to kotlin code to get the value.
In addition, if you want to convert the xamarin app to Android Kotlin app, you can use the native SharedPreferences api directly. I can't understand why you need to Retrieve Xamarin secured storage data from native Kotlin Android.
答案2
得分: 0
以下是Kotlin代码的翻译部分:
fun decryptPrefData(preferenceKey: String): String? {
val alias = "${context.packageName}.xamarinessentials"
val sharedPref = context.getSharedPreferences(alias, Context.MODE_PRIVATE)
return sharedPref.getString(preferenceKey, null)?.let { encryptedFullString ->
val encryptedFullBytes = Base64.decode(encryptedFullString, Base64.DEFAULT)
val iv = encryptedFullBytes.copyOfRange(0, 12)
val encryptedData = encryptedFullBytes.copyOfRange(12, encryptedFullBytes.size)
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val secretKey = keyStore.getKey(alias, null) as SecretKey
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, iv))
cipher.doFinal(encryptedData).toString(Charsets.UTF_8)
}
}
希望这对您有所帮助。
英文:
To complete @Liyun Zhang - MSFT's answer, here is the Kotlin code:
fun decryptPrefData(preferenceKey: String): String? {
val alias = "${context.packageName}.xamarinessentials"
val sharedPref = context.getSharedPreferences(alias, Context.MODE_PRIVATE)
return sharedPref.getString(preferenceKey, null)?.let { encryptedFullString ->
val encryptedFullBytes = Base64.decode(encryptedFullString, Base64.DEFAULT)
val iv = encryptedFullBytes.copyOfRange(0, 12)
val encryptedData = encryptedFullBytes.copyOfRange(12, encryptedFullBytes.size)
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val secretKey = keyStore.getKey(alias, null) as SecretKey
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, iv))
cipher.doFinal(encryptedData).toString(Charsets.UTF_8)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论