【发布时间】:2020-08-28 08:58:13
【问题描述】:
我正在尝试使用 Android 通过 RSA 加密和解密数据。这是我的加密/解密代码
fun encryptStringRSA(str: String, publicKey: PublicKey): String{
val encryptedBytes: ByteArray? = Cipher.getInstance("RSA/NONE/PKCS1Padding").run {
init(Cipher.ENCRYPT_MODE, publicKey)
doFinal(str.toByteArray(Charsets.UTF_8))
}
return Base64.encodeToString(encryptedBytes, EncryptionConstants.BASE_64_OPTIONS)
}
fun decryptStringRSA(str: String, privateKey: PrivateKey): String{
val decryptedBytes: ByteArray = Cipher.getInstance("RSA/NONE/PKCS1Padding").run {
init(Cipher.DECRYPT_MODE, privateKey)
doFinal(Base64.decode(str, EncryptionConstants.BASE_64_OPTIONS))
}
return String(decryptedBytes)
}
当我使用 Node JS 服务器生成的密钥时效果很好(这是用于同步算法参数),但是现在我需要在 Android 端生成密钥,我就是这样做的:
fun generateRSAKeyPair(keyAlias: String): KeyPair {
val startDate = GregorianCalendar()
val endDate = GregorianCalendar()
endDate.add(Calendar.YEAR, 1)
val keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE)
val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(keyAlias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY or KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT).run {
setDigests(KeyProperties.DIGEST_SHA256)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
setKeySize(2048)
setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
setCertificateNotBefore(startDate.time)
setCertificateNotAfter(endDate.time)
setUserAuthenticationRequired(true)
setUserAuthenticationValidityDurationSeconds(30)
build()
}
keyPairGenerator.initialize(parameterSpec)
val keyPair = keyPairGenerator.genKeyPair()
val publicKey = getPublicKey(
Base64.encodeToString(
keyPair.public.encoded,
EncryptionConstants.BASE_64_OPTIONS
)
)
return KeyPair(publicKey, keyPair.private)
}
然后从 Keystore 中获取:
fun initKeyPair(keyAlias: String): KeyPair{
try {
val keyStore: KeyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply {
load(null)
}
val entry: KeyStore.Entry = keyStore.getEntry(keyAlias, null)
val privateKey: PrivateKey? = (entry as KeyStore.PrivateKeyEntry).privateKey
val publicKey: PublicKey? = keyStore.getCertificate(keyAlias).publicKey
return if (privateKey == null || publicKey == null) {
KeyHolderUtils().generateRSAKeyPair(keyAlias)
} else {
val publicKey2 = getPublicKey(
Base64.encodeToString(
publicKey.encoded,
EncryptionConstants.BASE_64_OPTIONS
)
)
KeyPair(publicKey2, privateKey)
}
}catch (ex: Exception){
return KeyHolderUtils().generateRSAKeyPair(keyAlias)
}
}
加密、签名和验证工作,但是当我尝试解密时总是得到 en KeyStoreException: Unknown error
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.io.IOException: javax.crypto.IllegalBlockSizeException
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:133)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:202)
at com.test.communication.encryption.utils.EncryptionUtils.decryptStringRSA(EncryptionUtils.kt:46)
at com.test.communication.encryption.AndroidEncryptionBase.decryptMessage(AndroidEncryptionBase.kt:72)
at com.test.communication.encryption.AndroidEncryption.decryptMessage(AndroidEncryption.kt:37)
at com.test.communication.server.MessageServiceImpl.send(MessageServiceImpl.kt:97)
at com.test.app.presentation.ui.main.CommunicationActivity$initButtons$1.onClick(CommunicationActivity.kt:64)
at android.view.View.performClick(View.java:7201)
at android.view.View.performClickInternal(View.java:7170)
at android.view.View.access$3500(View.java:806)
at android.view.View$PerformClick.run(View.java:27562)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: javax.crypto.IllegalBlockSizeException
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:519)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:531)
at javax.crypto.Cipher.doFinal(Cipher.java:2002)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:130)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:202)
at com.test.communication.encryption.utils.EncryptionUtils.decryptStringRSA(EncryptionUtils.kt:46)
at com.test.communication.encryption.AndroidEncryptionBase.decryptMessage(AndroidEncryptionBase.kt:72)
at com.test.communication.encryption.AndroidEncryption.decryptMessage(AndroidEncryption.kt:37)
at com.test.communication.server.MessageServiceImpl.send(MessageServiceImpl.kt:97)
at com.test.app.presentation.ui.main.CommunicationActivity$initButtons$1.onClick(CommunicationActivity.kt:64)
at android.view.View.performClick(View.java:7201)
at android.view.View.performClickInternal(View.java:7170)
at android.view.View.access$3500(View.java:806)
at android.view.View$PerformClick.run(View.java:27562)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: android.security.KeyStoreException: Unknown error
at android.security.KeyStore.getKeyStoreException(KeyStore.java:1303)
at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:531)
at javax.crypto.Cipher.doFinal(Cipher.java:2002)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:130)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:202)
at com.test.communication.encryption.utils.EncryptionUtils.decryptStringRSA(EncryptionUtils.kt:46)
at com.test.communication.encryption.AndroidEncryptionBase.decryptMessage(AndroidEncryptionBase.kt:72)
at com.test.communication.encryption.AndroidEncryption.decryptMessage(AndroidEncryption.kt:37)
at com.test.communication.server.MessageServiceImpl.send(MessageServiceImpl.kt:97)
at com.test.app.presentation.ui.main.CommunicationActivity$initButtons$1.onClick(CommunicationActivity.kt:64)
at android.view.View.performClick(View.java:7201)
at android.view.View.performClickInternal(View.java:7170)
at android.view.View.access$3500(View.java:806)
at android.view.View$PerformClick.run(View.java:27562)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
我尝试了不同的块(ECB,NONE)和填充(NOPadding,PKCS1Padding,OAEPPadding,OAEPwithSHA-1andMGF1Padding 和 OAEPwithSHA-256andMGF1Padding)组合,并根据我看到帖子的组合更改KeyGenParameterSpec 参数setEncryptionPaddings,setBlockModes就像Android KeyStoreException Unknown Error
并尝试更改其中的代码,但总是得到相同的异常。
顺便说一句,在不同的模拟器和真实设备 OnePlus 6 上尝试结果相同 - KeyStoreException:未知错误
更新!!! 我发现一些奇怪的想法,如果我将所有这些代码复制到 Activity 一切正常,但是当我从另一个类调用它时会出错。例如:
fun fire(){
val str = "test"
val encryptionUtils = EncryptionUtils()
generateRSAKeyPair("testKeys")
val encryptStringRSA = encryptionUtils.encryptStringRSA(str, keyPair.public)
val decryptStringRSA = decryptStringRSA(encryptStringRSA, keyPair.private)
println(decryptStringRSA)
}
这段代码运行良好,但是
fun fire(){
val str = "test"
val encryptionUtils = EncryptionUtils()
generateRSAKeyPair("testKeys")
val encryptStringRSA = encryptionUtils.encryptStringRSA(str, keyPair.public)
val decryptStringRSA = encryptionUtils.decryptStringRSA(encryptStringRSA, keyPair.private)
println(decryptStringRSA)
}
此代码导致异常。 EncryptionUtils 类的代码与 Activity 中 100% 相同(我的意思是 encryptStringRSA、decryptStringRSA 等)
【问题讨论】:
-
请将您的代码填写到mcve。
getPublicKey是如何实现的,EncryptionConstants.BASE_64_OPTIONS和ANDROID_KEYSTORE的定义是什么?即使其中一些可以猜到,也存在使用不同假设的风险。特别是,发布加密和解密方法的完整调用,这最终引发异常,以便可以重现。 -
抱歉,忘了说 val publicKey2 = getPublicKey( Base64.encodeToString( publicKey.encoded, EncryptionConstants.BASE_64_OPTIONS ) ) 没有这个代码有同样的行为
-
ANDROID_KEYSTORE = "AndroidKeyStore"
-
还有一个我发现的,如果我将所有这些代码复制到活动中,一切正常,但如果我从另一个类调用它们,则会出错。
标签: android encryption keystore