11package cn.lc6464.fileencryptor
22
33import android.content.Context
4- import androidx .security.crypto.EncryptedSharedPreferences
5- import androidx .security.crypto.MasterKey
4+ import android .security.keystore.KeyGenParameterSpec
5+ import android .security.keystore.KeyProperties
66import androidx.core.content.edit
7+ import java.nio.charset.StandardCharsets
8+ import java.security.KeyStore
9+ import javax.crypto.Cipher
10+ import javax.crypto.KeyGenerator
11+ import javax.crypto.SecretKey
12+ import javax.crypto.spec.GCMParameterSpec
713
14+ /* *
15+ * 这是一个辅助类,负责所有与 Android Keystore 交互的加密和解密操作。
16+ * 它将密钥安全地存储在硬件支持的 Keystore 中。
17+ */
18+ private class CryptoHelper {
19+
20+ private val keyStore = KeyStore .getInstance(" AndroidKeyStore" ).apply {
21+ load(null )
22+ }
23+
24+ private fun getSecretKey (alias : String ): SecretKey {
25+ return (keyStore.getEntry(alias, null ) as ? KeyStore .SecretKeyEntry )?.secretKey
26+ ? : generateSecretKey(alias)
27+ }
28+
29+ private fun generateSecretKey (alias : String ): SecretKey {
30+ val keyGenerator = KeyGenerator .getInstance(
31+ KeyProperties .KEY_ALGORITHM_AES , " AndroidKeyStore"
32+ )
33+ val parameterSpec = KeyGenParameterSpec .Builder (
34+ alias,
35+ KeyProperties .PURPOSE_ENCRYPT or KeyProperties .PURPOSE_DECRYPT
36+ )
37+ .setBlockModes(KeyProperties .BLOCK_MODE_GCM )
38+ .setEncryptionPaddings(KeyProperties .ENCRYPTION_PADDING_NONE )
39+ .setKeySize(256 )
40+ .build()
41+ keyGenerator.init (parameterSpec)
42+ return keyGenerator.generateKey()
43+ }
44+
45+ fun encrypt (data : String , keyAlias : String ): Pair <ByteArray , ByteArray > {
46+ val key = getSecretKey(keyAlias)
47+ val cipher = Cipher .getInstance(" AES/GCM/NoPadding" )
48+ cipher.init (Cipher .ENCRYPT_MODE , key)
49+ val encryptedData = cipher.doFinal(data.toByteArray(StandardCharsets .UTF_8 ))
50+ return Pair (cipher.iv, encryptedData)
51+ }
52+
53+ fun decrypt (iv : ByteArray , encryptedData : ByteArray , keyAlias : String ): String {
54+ val key = getSecretKey(keyAlias)
55+ val cipher = Cipher .getInstance(" AES/GCM/NoPadding" )
56+ val spec = GCMParameterSpec (128 , iv) // GCM 认证标签长度为 128 位
57+ cipher.init (Cipher .DECRYPT_MODE , key, spec)
58+ val decryptedData = cipher.doFinal(encryptedData)
59+ return String (decryptedData, StandardCharsets .UTF_8 )
60+ }
61+ }
62+
63+
64+ /* *
65+ * 使用平台原生 API (AndroidKeyStore 和 SharedPreferences) 来安全地存储密码。
66+ * 这取代了已弃用的 EncryptedSharedPreferences。
67+ */
868class PasswordStorageManager (context : Context ) {
969
10- // 使用 MasterKey.Builder 替换已弃用的 MasterKeys.getOrCreate
11- // 这是 Android Security 库推荐的现代方法。
12- private val masterKey = MasterKey .Builder (context)
13- .setKeyScheme(MasterKey .KeyScheme .AES256_GCM )
14- .build()
15-
16- // 使用接受 MasterKey 对象的 create 方法重载
17- // 注意参数顺序也发生了变化 (context 现在是第一个参数)。
18- private val sharedPreferences = EncryptedSharedPreferences .create(
19- context, // 第一个参数是 Context
20- " secret_shared_prefs" , // 第二个参数是文件名
21- masterKey, // 第三个参数是 MasterKey 对象
22- EncryptedSharedPreferences .PrefKeyEncryptionScheme .AES256_SIV ,
23- EncryptedSharedPreferences .PrefValueEncryptionScheme .AES256_GCM
24- )
70+ private val cryptoHelper = CryptoHelper ()
71+ private val sharedPreferences =
72+ context.getSharedPreferences(" secure_prefs" , Context .MODE_PRIVATE )
2573
2674 companion object {
27- private const val KEY_PASSWORD = " password"
75+ private const val KEY_ALIAS_PASSWORD = " password_key_alias"
76+ private const val PREF_KEY_ENCRYPTED_PASSWORD = " encrypted_password"
77+ private const val PREF_KEY_PASSWORD_IV = " password_iv"
2878 }
2979
3080 fun savePassword (password : String ) {
31- sharedPreferences.edit { putString(KEY_PASSWORD , password) }
81+ try {
82+ val (iv, encryptedPassword) = cryptoHelper.encrypt(password, KEY_ALIAS_PASSWORD )
83+ sharedPreferences.edit {
84+ putString(
85+ PREF_KEY_PASSWORD_IV ,
86+ android.util.Base64 .encodeToString(iv, android.util.Base64 .NO_WRAP )
87+ )
88+ putString(
89+ PREF_KEY_ENCRYPTED_PASSWORD ,
90+ android.util.Base64 .encodeToString(
91+ encryptedPassword,
92+ android.util.Base64 .NO_WRAP
93+ )
94+ )
95+ }
96+ } catch (e: Exception ) {
97+ // 在这里处理加密失败的异常,例如记录日志
98+ e.printStackTrace()
99+ }
32100 }
33101
34102 fun getPassword (): String? {
35- return sharedPreferences.getString(KEY_PASSWORD , null )
103+ return try {
104+ val ivString = sharedPreferences.getString(PREF_KEY_PASSWORD_IV , null )
105+ val encryptedPasswordString =
106+ sharedPreferences.getString(PREF_KEY_ENCRYPTED_PASSWORD , null )
107+
108+ if (ivString != null && encryptedPasswordString != null ) {
109+ val iv = android.util.Base64 .decode(ivString, android.util.Base64 .NO_WRAP )
110+ val encryptedPassword =
111+ android.util.Base64 .decode(encryptedPasswordString, android.util.Base64 .NO_WRAP )
112+ cryptoHelper.decrypt(iv, encryptedPassword, KEY_ALIAS_PASSWORD )
113+ } else {
114+ null
115+ }
116+ } catch (e: Exception ) {
117+ // 在这里处理解密失败的异常
118+ e.printStackTrace()
119+ // 如果解密失败(例如密钥已更改或数据损坏),最好清除旧数据
120+ sharedPreferences.edit {
121+ remove(PREF_KEY_PASSWORD_IV )
122+ remove(PREF_KEY_ENCRYPTED_PASSWORD )
123+ }
124+ null
125+ }
36126 }
37127}
0 commit comments