2

我通过使用 JavaX 库在 Kotlin 中找到了 AES 加密逻辑。由于它特定于 java (Android),因此它不适用于 iOS。

import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.SecretKeySpec

object Crypto {

    fun calculateHash(data: ByteArray, key: ByteArray): ByteArray {
        val cipher: Cipher
        var encrypted = ByteArray(16)

        try {
            val secretKeyEcb: SecretKey = SecretKeySpec(key, "AES")
            cipher = Cipher.getInstance("AES")
            cipher.init(Cipher.ENCRYPT_MODE, secretKeyEcb)
            encrypted = cipher.doFinal(data, 0, 16)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return encrypted.copyOf(8)
    }
}

有什么方法可以在 iOS 或 KMM 中实现上述代码?

4

1 回答 1

3

Kotlin 多平台是一项新技术,它缺少许多库。

您将无法在 iOS 上运行 java 代码,因此Cipher无法在通用代码中使用。

在编写应用程序时,您经常会遇到类似的问题,解决方案始终相同:创建一个接口类并为每个平台实现它。

commomMain/Crypto.kt

expect object Crypto {
    fun calculateHash(data: ByteArray, key: ByteArray): ByteArray
}

在 android 部分,您可以Cipher轻松使用:

androidMain/Crypto.kt

actual object Crypto {
    fun calculateHash(data: ByteArray, key: ByteArray): ByteArray {
        val cipher: Cipher
        var encrypted = ByteArray(16)

        try {
            val secretKeyEcb: SecretKey = SecretKeySpec(key, "AES")
            cipher = Cipher.getInstance("AES")
            cipher.init(Cipher.ENCRYPT_MODE, secretKeyEcb)
            encrypted = cipher.doFinal(data, 0, 16)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return encrypted.copyOf(8)
    }
}

而要实现这iosCommon部分,您需要为您的问题寻找 iOS 解决方案。我建议你寻找一个 Objective C 解决方案,因为 kotlin 会根据该语言的标头生成它的文件,所以这样的解决方案将比 Swift 解决方案更容易实现。

我遇到的第一个是这个答案,我开始使用它。

您可以尝试在 github 上搜索,看看是否有人已经实现了它。我尝试了 iOS 和 kotlin 过滤的关键类,通常结果数量很少,如果幸运的话,你会找到你需要的。

就您而言,我很幸运能找到此代码CCCrypt这是+ kotlin language=)的唯一搜索结果。我将它与obj-c answer结合起来。这看起来与您的Cipher代码不完全一样,由于某种原因,您也只占用了前 8 个字节。但你应该明白:

actual object Crypto {
    @Throws(Throwable::class)
    fun calculateHash(data: ByteArray, key: ByteArray): ByteArray {
        if (!listOf(
                kCCKeySizeAES128,
                kCCKeySizeAES192,
                kCCKeySizeAES256,
            ).contains(key.count().toUInt())
        ) {
            throw IllegalStateException("Invalid key length ${key.count()}")
        }
        val ivLength = kCCBlockSizeAES128
        val output = ByteArray(
            size = ivLength.toInt() * 2 + data.size
        ) { 0.toByte() }
        val outputSize = ULongArray(1) { 0u }
        key.usePinned { keyPinned ->
            data.usePinned { inputPinned ->
                output.usePinned { outputPinned ->
                    outputSize.usePinned { outputSizePinned ->
                        val rcbStatus = SecRandomCopyBytes(
                            kSecRandomDefault,
                            ivLength.toULong(),
                            outputPinned.addressOf(0)
                        )
                        if (rcbStatus != kCCSuccess) {
                            throw IllegalStateException("calculateHash rcbStatus $rcbStatus")
                        }
                        val ccStatus = CCCrypt(
                            op = kCCEncrypt,
                            alg = kCCAlgorithmAES,
                            options = kCCOptionPKCS7Padding,
                            key = keyPinned.addressOf(0),
                            keyLength = key.size.toULong(),
                            iv = outputPinned.addressOf(0),
                            dataIn = inputPinned.addressOf(0),
                            dataInLength = data.size.toULong(),
                            dataOut = outputPinned.addressOf(ivLength.toInt()),
                            dataOutAvailable = output.size.toULong() - ivLength,
                            dataOutMoved = outputSizePinned.addressOf(0),
                        )
                        if (ccStatus != kCCSuccess) {
                            throw IllegalStateException("calculateHash ccStatus $ccStatus")
                        }
                    }
                }
            }
        }
        return output.copyOf((outputSize.first() + ivLength).toInt())
    }
}
于 2021-08-31T18:50:35.407 回答