简单地将您的密码保存在应用级build.graldle
文件中,例如:
android {
compileSdkVersion 30
buildToolsVersion = '29.0.3'
defaultConfig {
buildConfigField 'String', 'prefPass', '"YourPasswordHere"'
// rest of the code goes here..
并像这样使用它:
BuildConfig.prefPass
由于build.gradle
文件不是 APK 源代码的一部分,因此没有人可以窃取它。
为什么要将密码保存在共享首选项中?为什么不能直接从 BuildConfig 使用它?如果您真的想保存它,请使用此类加密并保存它:
import android.util.Log
import java.security.MessageDigest
import java.util.*
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
object CryptographyUtil {
private const val TAG: String = "CryptographyUtil"
private const val CIPHER_TRANSFORMATION = "AES/CBC/PKCS5PADDING"
private const val KEY_ALGORITHM = "AES"
// https://developer.android.com/guide/topics/security/cryptography#encrypt-message
fun encryptData(key: String, data: String): String {
try {
val secretKeySpec = generateSecretKey(key)
val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION)
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, getIVSpecification(key))
val encryptValue = cipher.doFinal(data.toByteArray())
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Base64.getEncoder().encodeToString(encryptValue)
} else {
android.util.Base64.encodeToString(encryptValue, android.util.Base64.DEFAULT)
}
} catch (e: Exception) {
Log.d(TAG, "Error while encrypt ${e.message}")
}
return data
}
fun decryptData(key: String, encryptedData: String): String {
try {
val secretKeySpec = generateSecretKey(key)
val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION)
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, getIVSpecification(key))
val decodeValue = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Base64.getDecoder().decode(encryptedData)
} else {
android.util.Base64.decode(encryptedData, android.util.Base64.DEFAULT)
}
return String(cipher.doFinal(decodeValue))
} catch (e: Exception) {
Log.d(TAG, "Error while decrypt ${e.message}")
}
return encryptedData
}
private fun generateSecretKey(key: String): SecretKeySpec {
val messageDigest = MessageDigest.getInstance("SHA-256")
val bytes = key.toByteArray(Charsets.UTF_8)
messageDigest.update(bytes, 0, bytes.size)
return SecretKeySpec(messageDigest.digest(), KEY_ALGORITHM)
}
private fun getIVSpecification(key: String): IvParameterSpec {
// concat string so that key has always size greater than 16 bytes & we can
// get first 16 character for generating IV specification.
// As documentation suggest that IV specification key can't be less or greater than 16 bytes
val concatKey = key + key
return IvParameterSpec(concatKey.substring(0, 16).toByteArray())
}
}
在您的课程中使用上述EncryptedSharedPreferences
课程:
val encryptData = encryptData(BuildConfig.prefPass,
BuildConfig.prefPass)
encryptedSharedPreferences.edit().apply {
putString("MY_KEY", encryptData)
}.apply()
注意:要完成这项工作,您需要启用 minify 以隐藏BuildConfig
文件。
buildTypes {
release {
debuggable false
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
在这里检查这个答案
缩小步骤的另一个特点是常量的内联。这可以解释为什么 BuildConfig 消失了,但值仍然存在于需要的地方。一旦值被内联,就不再有对 BuildConfig 类的引用,并且 minifier 可以完全删除它
加密部分只是为了防止 Key 从应用程序中被读取,根据定义,这是不可能的。如果您的应用程序可以使用密钥,那么您的应用程序的修改版本可以使用它,该版本将密钥转储到 LogCat 或其他东西。ProGuard、DexGuard 和 kin 等工具使访问变得更加困难,但它们无法阻止它。防止密钥被访问的唯一方法是首先不在应用程序中拥有它。参考:https ://stackoverflow.com/a/30238695/2462531