0

我正在尝试为 JWToken 的加密和解密实现生物特征认证。用户在服务器上进行身份验证后,将接收并加密令牌。令牌的加密应该允许在设备上没有生物特征用户授权的情况下进行。只有解密操作需要生物识别设备授权。这就是我为此使用非对称密钥的原因。然而,我收到的令牌大约是 1000 字节,因此不能用非对称密钥加密。这就是为什么我为解密和加密操作创建一个对称密钥,并使用授权保护的非对称密钥包装和解包这个密钥。但是,尝试使用非对称公钥包装对称密钥会引发 InvalidKeyException,并显示消息:javax.crypto.BadPaddingException。尝试用非对称私钥包装对称密钥这次也会抛出 InvalidKeyException 并显示简短消息:无法解开密钥。当我 setUserAuthenticationRequired 为 false 时,非对称私钥可以很好地用于包装。我在这里做错了什么?

class EncryptionService(
    private val wrappedKeyStoreSource: WrappedKeyStore2
) {

    companion object {
        const val MASTER_KEY = "master_key"
        const val ALGORITHM_AES = "AES"
        const val ENCRYPTION_KEY = "encryption_key"
        const val TRANSFORMATION_ASYMMETRIC = "RSA/ECB/PKCS1Padding"
        const val TRANSFORMATION_SYMMETRIC = "AES/CBC/PKCS7Padding"
    }

    private val keyStore: KeyStore = createAndroidKeyStore()

    init {
        createDefaultSymmetricKey()
    }

    fun encrypt(data: String): String =
        encryptWithSymmetricKey(data)

    private fun createDefaultSymmetricKey() {
        val symmetricKey = generateSymmetricKey()
        val masterKey = createAsymmetricKey(MASTER_KEY)
        val cipher: Cipher = Cipher.getInstance(TRANSFORMATION_ASYMMETRIC)
        cipher.init(Cipher.WRAP_MODE, masterKey.public)
        val encryptedSymmetricKey = cipher.wrap(symmetricKey)
        wrappedKeyStoreSource.saveKey(ENCRYPTION_KEY, Base64.encodeToString(encryptedSymmetricKey, Base64.DEFAULT) )
    }

    //encrypt without user authorization
    private fun encryptWithSymmetricKey(data: String): String {
        val masterKey = getAsymmetricKeyPair(MASTER_KEY)
        val encryptionKey = wrappedKeyStoreSource.getKey(ENCRYPTION_KEY)
        val unwrapCipher: Cipher = Cipher.getInstance(TRANSFORMATION_ASYMMETRIC)
        unwrapCipher.init(Cipher.UNWRAP_MODE, masterKey?.public)
        val encryptedKeyData = Base64.decode(encryptionKey, Base64.DEFAULT)

       //this line throws InvalidKeyException 
        //unwrap with public key throws InvalidKeyException with message: javax.crypto.BadPaddingException.
        //unwrap with private key throws InvalidKeyException if setUserAuthenticationRequired on this
        // key is set to true with message: Failed to unwrap key (maybe due to UserNotAuthenticatedException?)
        val symmetricKey = unwrapCipher.unwrap(encryptedKeyData, ALGORITHM_AES, Cipher.PUBLIC_KEY) as SecretKey

        val encryptCipher: Cipher = Cipher.getInstance(TRANSFORMATION_SYMMETRIC)
        encryptCipher.init(Cipher.ENCRYPT_MODE, symmetricKey)
        val encryptedString = encryptCipher.doFinal(data.toByteArray())
        return Base64.encodeToString(encryptedString, Base64.DEFAULT)
    }

    private fun createAsymmetricKey(alias: String): KeyPair {
        val generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore")
        val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
            .setUserAuthenticationRequired(true)
        generator.initialize(builder.build())
        return generator.generateKeyPair()
    }

    private fun generateSymmetricKey(): SecretKey {
        val keyGenerator = KeyGenerator.getInstance("AES")
        return keyGenerator.generateKey()
    }

    private fun getAsymmetricKeyPair(alias: String): KeyPair? {
        val privateKey = keyStore.getKey(alias, null) as PrivateKey?
        val publicKey = keyStore.getCertificate(alias)?.publicKey
        return if (privateKey != null && publicKey != null) {
            KeyPair(publicKey, privateKey)
        } else {
            null
        }
    }

    private fun createAndroidKeyStore(): KeyStore {
        val keyStore = KeyStore.getInstance("AndroidKeyStore")
        keyStore.load(null)
        return keyStore
    }

}
stackTrace: java.security.InvalidKeyException: javax.crypto.BadPaddingException: 
error:0400006b:RSA routines:OPENSSL_internal:BLOCK_TYPE_IS_NOT_01
        at com.android.org.conscrypt.OpenSSLCipherRSA.engineUnwrap(OpenSSLCipherRSA.java:373)
        at javax.crypto.Cipher.unwrap(Cipher.java:2440)
        at com.libencryption.data.EncryptionService.encryptWithSymmetricKey(EncryptionService.kt:58)
        at com.libencryption.data.EncryptionService.encrypt(EncryptionService.kt:37)

当我切换到使用私钥解包时,如下所示

unwrapCipher.init(Cipher.UNWRAP_MODE, masterKey?.private)
val encryptedKeyData = Base64.decode(encryptionKey, Base64.DEFAULT)
val symmetricKey = unwrapCipher.unwrap(encryptedKeyData, ALGORITHM_AES, Cipher.SECRET_KEY) as SecretKey

我得到以下堆栈跟踪

stackTrace: java.security.InvalidKeyException: Failed to unwrap key
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineUnwrap(AndroidKeyStoreCipherSpiBase.java:682)
        at javax.crypto.Cipher.unwrap(Cipher.java:2440)
        at com.libencryption.data.EncryptionService.encryptWithSymmetricKey(EncryptionService.kt:58)
        at com.libencryption.data.EncryptionService.encrypt(EncryptionService.kt:37)

我认为这是因为我 setUserAuthenticationRequired 为 true ,因为当我将其设置为 false 时,一切都加密得很好。但是,正如您从 stackstrace 中看到的那样,没有记录异常。是否有任何其他原因导致 setUserAuthenticationRequired 为 true 时会失败?

4

0 回答 0