将密钥库密码的明文存储改为 AES 加密存储
This commit is contained in:
@@ -12,6 +12,7 @@ import com.mcal.apksigner.ApkSigner
|
|||||||
import com.reandroid.arsc.chunk.TableBlock
|
import com.reandroid.arsc.chunk.TableBlock
|
||||||
import org.apache.commons.io.FileUtils.copyFile
|
import org.apache.commons.io.FileUtils.copyFile
|
||||||
import org.apache.commons.io.FileUtils.copyInputStreamToFile
|
import org.apache.commons.io.FileUtils.copyInputStreamToFile
|
||||||
|
import org.autojs.autojs.apkbuilder.keystore.AESUtils
|
||||||
import org.autojs.autojs.app.GlobalAppContext
|
import org.autojs.autojs.app.GlobalAppContext
|
||||||
import org.autojs.autojs.engine.encryption.AdvancedEncryptionStandard
|
import org.autojs.autojs.engine.encryption.AdvancedEncryptionStandard
|
||||||
import org.autojs.autojs.pio.PFiles
|
import org.autojs.autojs.pio.PFiles
|
||||||
@@ -292,9 +293,9 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
|||||||
|
|
||||||
mAppConfig.keyStore?.let {
|
mAppConfig.keyStore?.let {
|
||||||
keyStoreFile = File(it.absolutePath)
|
keyStoreFile = File(it.absolutePath)
|
||||||
password = it.password
|
password = AESUtils.decrypt(it.password)
|
||||||
alias = it.alias
|
alias = it.alias
|
||||||
aliasPassword = it.aliasPassword
|
aliasPassword = AESUtils.decrypt(it.aliasPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 ApkSigner 重新签名
|
// 使用 ApkSigner 重新签名
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.autojs.autojs.apkbuilder.keystore
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import javax.crypto.spec.GCMParameterSpec
|
||||||
|
import android.security.keystore.KeyGenParameterSpec
|
||||||
|
import android.security.keystore.KeyProperties
|
||||||
|
import java.security.KeyStore
|
||||||
|
import javax.crypto.KeyGenerator
|
||||||
|
|
||||||
|
object AESUtils {
|
||||||
|
|
||||||
|
private const val TRANSFORMATION = "AES/GCM/NoPadding"
|
||||||
|
private const val TAG_LENGTH = 128
|
||||||
|
|
||||||
|
private const val KEY_ALIAS = "autojs6_key_store_aes_key"
|
||||||
|
|
||||||
|
private fun getKey(): SecretKey {
|
||||||
|
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
||||||
|
keyStore.load(null)
|
||||||
|
|
||||||
|
val key = keyStore.getKey(KEY_ALIAS, null)
|
||||||
|
if (key != null) {
|
||||||
|
return key as SecretKey
|
||||||
|
}
|
||||||
|
|
||||||
|
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
|
||||||
|
val keyGenParameterSpec = KeyGenParameterSpec.Builder(KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
|
||||||
|
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||||
|
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
keyGenerator.init(keyGenParameterSpec)
|
||||||
|
return keyGenerator.generateKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
fun encrypt(data: String): String {
|
||||||
|
val secretKey: SecretKey = getKey()
|
||||||
|
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||||
|
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
|
||||||
|
|
||||||
|
val encryptedData = cipher.doFinal(data.toByteArray())
|
||||||
|
val encryptedBase64 = Base64.encodeToString(encryptedData, Base64.NO_WRAP)
|
||||||
|
val ivBase64 = Base64.encodeToString(cipher.iv, Base64.NO_WRAP)
|
||||||
|
|
||||||
|
return "$ivBase64:$encryptedBase64"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
fun decrypt(encryptedData: String): String {
|
||||||
|
val parts = encryptedData.split(":")
|
||||||
|
val ivBase64 = parts[0]
|
||||||
|
val encryptedBase64 = parts[1]
|
||||||
|
|
||||||
|
val iv = Base64.decode(ivBase64, Base64.NO_WRAP)
|
||||||
|
val encrypted = Base64.decode(encryptedBase64, Base64.NO_WRAP)
|
||||||
|
|
||||||
|
val secretKey: SecretKey = getKey()
|
||||||
|
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||||
|
|
||||||
|
val gcmSpec = GCMParameterSpec(TAG_LENGTH, iv)
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec)
|
||||||
|
|
||||||
|
val decryptedData = cipher.doFinal(encrypted)
|
||||||
|
|
||||||
|
return String(decryptedData)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import com.afollestad.materialdialogs.MaterialDialog
|
|||||||
import com.mcal.apksigner.CertCreator
|
import com.mcal.apksigner.CertCreator
|
||||||
import com.mcal.apksigner.utils.DistinguishedNameValues
|
import com.mcal.apksigner.utils.DistinguishedNameValues
|
||||||
import com.mcal.apksigner.utils.KeyStoreHelper
|
import com.mcal.apksigner.utils.KeyStoreHelper
|
||||||
|
import org.autojs.autojs.apkbuilder.keystore.AESUtils
|
||||||
import org.autojs.autojs.apkbuilder.keystore.KeyStore
|
import org.autojs.autojs.apkbuilder.keystore.KeyStore
|
||||||
import org.autojs.autojs.core.pref.Pref
|
import org.autojs.autojs.core.pref.Pref
|
||||||
import org.autojs.autojs6.R
|
import org.autojs.autojs6.R
|
||||||
@@ -174,9 +175,9 @@ class ManageKeyStoreActivity : BaseActivity() {
|
|||||||
val newKeyStore = KeyStore(
|
val newKeyStore = KeyStore(
|
||||||
absolutePath = file.absolutePath,
|
absolutePath = file.absolutePath,
|
||||||
filename = file.name,
|
filename = file.name,
|
||||||
password = configs.password,
|
password = AESUtils.encrypt(configs.password),
|
||||||
alias = configs.alias,
|
alias = configs.alias,
|
||||||
aliasPassword = configs.aliasPassword,
|
aliasPassword = AESUtils.encrypt(configs.aliasPassword),
|
||||||
verified = true
|
verified = true
|
||||||
)
|
)
|
||||||
keyStoreViewModel.upsertKeyStore(newKeyStore)
|
keyStoreViewModel.upsertKeyStore(newKeyStore)
|
||||||
@@ -247,9 +248,9 @@ class ManageKeyStoreActivity : BaseActivity() {
|
|||||||
val verifiedKeyStore = KeyStore(
|
val verifiedKeyStore = KeyStore(
|
||||||
absolutePath = keyStore.absolutePath,
|
absolutePath = keyStore.absolutePath,
|
||||||
filename = keyStore.filename,
|
filename = keyStore.filename,
|
||||||
password = configs.password,
|
password = AESUtils.encrypt(configs.password),
|
||||||
alias = configs.alias,
|
alias = configs.alias,
|
||||||
aliasPassword = configs.aliasPassword,
|
aliasPassword = AESUtils.encrypt(configs.aliasPassword),
|
||||||
verified = true
|
verified = true
|
||||||
)
|
)
|
||||||
keyStoreViewModel.upsertKeyStore(verifiedKeyStore)
|
keyStoreViewModel.upsertKeyStore(verifiedKeyStore)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import android.view.ViewGroup
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import org.autojs.autojs.apkbuilder.keystore.AESUtils
|
||||||
import org.autojs.autojs.apkbuilder.keystore.KeyStore
|
import org.autojs.autojs.apkbuilder.keystore.KeyStore
|
||||||
import org.autojs.autojs6.R
|
import org.autojs.autojs6.R
|
||||||
import org.autojs.autojs6.databinding.DialogVerifyKeyStoreBinding
|
import org.autojs.autojs6.databinding.DialogVerifyKeyStoreBinding
|
||||||
@@ -43,9 +44,9 @@ open class VerifyKeyStoreDialog(
|
|||||||
if (keyStore.verified) {
|
if (keyStore.verified) {
|
||||||
binding.imgVerifyState.setImageResource(R.drawable.ic_key_store_verified)
|
binding.imgVerifyState.setImageResource(R.drawable.ic_key_store_verified)
|
||||||
binding.textVerifyState.text = getString(R.string.text_verified)
|
binding.textVerifyState.text = getString(R.string.text_verified)
|
||||||
binding.password.setText(keyStore.password)
|
binding.password.setText(AESUtils.decrypt(keyStore.password))
|
||||||
binding.alias.setText(keyStore.alias)
|
binding.alias.setText(keyStore.alias)
|
||||||
binding.aliasPassword.setText(keyStore.aliasPassword)
|
binding.aliasPassword.setText(AESUtils.decrypt(keyStore.aliasPassword))
|
||||||
} else {
|
} else {
|
||||||
binding.imgVerifyState.setImageResource(R.drawable.ic_key_store_unverified)
|
binding.imgVerifyState.setImageResource(R.drawable.ic_key_store_unverified)
|
||||||
binding.textVerifyState.text = getString(R.string.text_unverified)
|
binding.textVerifyState.text = getString(R.string.text_unverified)
|
||||||
|
|||||||
Reference in New Issue
Block a user