如何在Swift中用RSA私钥生成签名?Java转Swift实现遇阻
问题根源与修复方案
导致SecKeyCreateWithData失败的核心原因
你的Swift代码在密钥导入步骤失败,主要源于以下三个关键问题:
- 私钥格式不兼容:
openssl genrsa -des3生成的是PKCS#1格式私钥,但SecKeyCreateWithData要求导入PKCS#8格式密钥,而Java代码明确使用PKCS#8解析逻辑。 - 哈希计算错误:
createHash函数直接传入字符串而非UTF-8字节数据,且用字符数代替字节数作为哈希长度,导致哈希结果完全错误。 - 签名算法不匹配:Swift使用的PSS填充算法与Java的
SHA256WithRSA(PKCS#1 v1.5填充)不兼容,即使密钥导入成功也会生成无效签名。
修复步骤与完整代码
第一步:转换私钥格式
执行以下openssl命令将PKCS#1格式私钥转为PKCS#8格式:
openssl pkcs8 -topk8 -inform PEM -in WM_IO_my_rsa_key_pair -outform PEM -out WM_IO_private_key.pem -nocrypt
(需保留密码则移除-nocrypt参数)
第二步:修正Swift代码
import CommonCrypto import Security func computeSHA256Hash(for string: String) -> Data { guard let data = string.data(using: .utf8) else { return Data() } var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) data.withUnsafeBytes { buffer in CC_SHA256(buffer.baseAddress, CC_LONG(data.count), &hash) } return Data(hash) } func createSignature(stringToSign: String) throws -> String? { guard let url = Bundle.module.url(forResource: "WM_IO_private_key", withExtension: "pem") else { return nil } let privateKeyPEM = try String(contentsOf: url, encoding: .utf8) .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "") .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "") .components(separatedBy: .whitespacesAndNewlines).joined() guard let privateKeyData = Data(base64Encoded: privateKeyPEM, options: .ignoreUnknownCharacters) else { return nil } let attributes: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: 2048 ] var error: Unmanaged<CFError>? guard let secKey = SecKeyCreateWithData(privateKeyData as CFData, attributes as CFDictionary, &error) else { throw error?.takeRetainedValue() as Error ?? NSError(domain: "KeyImportError", code: -1, userInfo: nil) } let hash = computeSHA256Hash(for: stringToSign) let algorithm: SecKeyAlgorithm = .rsaSignatureMessagePKCS1v15SHA256 guard let signatureData = SecKeyCreateSignature(secKey, algorithm, hash as CFData, &error) as Data? else { throw error?.takeRetainedValue() as Error ?? NSError(domain: "SignatureError", code: -1, userInfo: nil) } return signatureData.base64EncodedString() }
关键修复说明
- 格式对齐:通过openssl转换后,私钥格式与Java代码的PKCS#8解析逻辑保持一致,解决密钥导入失败问题。
- 哈希修正:正确处理字符串的UTF-8字节数据,生成标准的256位哈希值。
- 算法匹配:使用
.rsaSignatureMessagePKCS1v15SHA256替代PSS算法,确保签名格式与Java实现完全兼容。 - 错误处理优化:完善错误抛出逻辑,便于排查后续问题。
内容的提问来源于stack exchange,提问作者Berry Blue
相关产品推荐
相关产品推荐

