You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KMM跨平台开发:iOS端如何实现DSA密钥对生成与签名?

KMM iOS端纯Kotlin实现2048位DSA密钥对生成与签名

1. 先确认Common层统一接口

你已经规划的Common层接口可以这么写,保证两端实现对齐:

// commonMain/SignatureService.kt
interface SignatureService {
    data class SignatureResult(val signature: ByteArray, val publicKey: ByteArray)
    suspend fun generateAndSign(data: ByteArray): SignatureResult
}

2. iOS端依赖配置

iOS没有java.security包,需要通过Kotlin/Native调用系统的Security.framework来实现加密操作。首先配置cinterop:

  • 在iosMain目录下创建cinterop/Security.def文件,内容如下:
framework = Security
header = <Security/Security.h>
compilerOpts = -ObjC
  • 在KMM模块的build.gradle.kts中添加cinterop配置:
kotlin {
    ios {
        binaries {
            framework { baseName = "YourKMMFramework" }
        }
        cinterop {
            val security by creating {
                defFile(file("src/iosMain/cinterop/Security.def"))
            }
        }
    }
    // 其他平台配置...
}

3. iOS端具体实现

在iosMain下编写实现类,调用iOS Security框架API完成密钥生成与签名:

// iosMain/SignatureServiceImpl.kt
import platform.Security.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class SignatureServiceImpl : SignatureService {
    override suspend fun generateAndSign(data: ByteArray): SignatureService.SignatureResult = withContext(Dispatchers.Default) {
        // 构建DSA密钥生成参数
        val attrDict = CFDictionaryCreateMutable(
            null,
            3,
            kCFTypeDictionaryKeyCallBacks,
            kCFTypeDictionaryValueCallBacks
        ).apply {
            CFDictionaryAddValue(this, kSecAttrKeyType, kSecAttrKeyTypeDSA)
            CFDictionaryAddValue(this, kSecAttrKeySizeInBits, 2048.toLong())
            CFDictionaryAddValue(this, kSecAttrIsPermanent, kCFBooleanFalse)
        }

        // 生成密钥对
        val pubKeyPtr = alloc<CFTypeVar>()
        val privKeyPtr = alloc<CFTypeVar>()
        check(SecKeyGeneratePair(attrDict, pubKeyPtr, privKeyPtr) == errSecSuccess) {
            "DSA密钥对生成失败"
        }
        val privateKey = privKeyPtr.value
        val publicKey = pubKeyPtr.value

        // 提取DER格式公钥(和Java端PublicKey.getEncoded()输出兼容)
        val pubDataPtr = alloc<CFTypeVar>()
        val pubAttrs = CFDictionaryCreateMutable(
            null,
            1,
            kCFTypeDictionaryKeyCallBacks,
            kCFTypeDictionaryValueCallBacks
        ).apply {
            CFDictionaryAddValue(this, kSecAttrKeyType, kSecAttrKeyTypeDSA)
        }
        check(SecKeyCopyExternalRepresentation(publicKey, pubAttrs, pubDataPtr) == errSecSuccess) {
            "公钥提取失败"
        }
        val publicKeyBytes = (pubDataPtr.value as CFData).toByteArray()

        // 对数据签名(算法和Java端SHA256withDSA对应)
        val signDataPtr = alloc<CFTypeVar>()
        check(SecKeySign(
            privateKey,
            kSecPaddingPKCS1SHA256,
            data.toCFData(),
            signDataPtr
        ) == errSecSuccess) {
            "签名失败"
        }
        val signatureBytes = (signDataPtr.value as CFData).toByteArray()

        // 释放CF对象资源
        CFRelease(privateKey)
        CFRelease(publicKey)
        CFRelease(attrDict)
        CFRelease(pubAttrs)
        CFRelease(pubDataPtr.value)
        CFRelease(signDataPtr.value)

        SignatureService.SignatureResult(signatureBytes, publicKeyBytes)
    }

    // ByteArray与CFData互转扩展
    private fun ByteArray.toCFData(): CFData = CFDataCreate(null, this, size.toLong())
    private fun CFData.toByteArray(): ByteArray {
        val len = CFDataGetLength(this).toInt()
        val byteArr = ByteArray(len)
        CFDataGetBytes(this, CFRangeMake(0, len.toLong()), byteArr.refTo(0))
        return byteArr
    }
}

关键注意点

  • 签名算法要和Java端严格匹配:如果Java用SHA256withDSA,iOS对应kSecPaddingPKCS1SHA256,其他哈希算法需同步调整
  • 公钥导出格式为DER,确保Java服务器能直接用KeyFactory.generatePublic()解析
  • 加密操作放在Dispatchers.Default避免阻塞主线程
  • 显式释放CF对象,避免Kotlin/Native内存泄漏

内容的提问来源于stack exchange,提问作者mbauer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 22:50:23