【问题标题】:Is AES 128 Crypto (Cipher) logic is there in Kotlin Multi Platform (KMM)?Kotlin Multi Platform (KMM) 中是否有 AES 128 加密(密码)逻辑?
【发布时间】:2021-10-30 04:05:03
【问题描述】:

我通过使用 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中实现上面的代码?

【问题讨论】:

  • 关于 iOS 上的 AES 加密有很多问题。究竟是什么给你带来了问题?
  • 上面提到的代码,当我在 KMM 项目(compileKotlinIosArm64)中运行时,它说“Unresolved reference: javax”所以,我需要在 iOS 或 KMM 中使用上述逻辑
  • @Sulthan 问题似乎是要找到一种在多平台 Kotlin 代码中编写这种加密(或至少是适配器)的方法。坦率地说,到目前为止我还没有看到任何重复
  • @Joffrey 与每个多平台框架一样,有时您需要特定于平台的代码。
  • @Sulthan 询问是否有人为它编写了 KMM 库仍然没有什么坏处,这就是为什么我认为这个问题没有任何问题

标签: ios kotlin kotlin-multiplatform kmm


【解决方案1】:

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

您将无法在 iOS 上运行 java 代码,因此在公共代码中使用 Cipher 将不起作用。

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

commomMain/Crypto.kt

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

在安卓部分你可以轻松使用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 的解决方案更容易实现。

我遇到的第一个是this answer,我开始使用它。

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

在你的情况下,我很幸运找到了this code。这是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())
    }
}

【讨论】:

  • 使用CryptoKit框架中的模式AES会容易得多,但是它只支持GCM模式。理想情况下,GCM 应该在两个平台上都使用,因为它更安全。
  • @Sulthan 如果我没记错的话,CryptoKit 是纯粹的 swift,这使得无法从 KMM 使用
  • 非常感谢@PhilipDukhov 和 Sulthan 分享您的意见。我们的代码库不在 Objective C 中。我会找到类似的 swift 逻辑。
  • @mittapallihareesh 如果你想从通用主目录中使用它,你需要将它翻译成 kotlin。这就是我所做的。无论您在项目中使用哪种语言,在科林部分,您只能与从 ObjC(系统库或外部框架)翻译的代码进行交互
猜你喜欢
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 2013-08-24
  • 2016-05-26
  • 1970-01-01
相关资源
最近更新 更多