iOS Swift中使用Security框架生成兼容OpenSSL的EC PEM密钥对问题
问题原因
你导出的公钥格式不符合OpenSSL的解析要求。SecKeyCopyExternalRepresentation导出的是EC公钥的原始二进制数据(仅包含x、y坐标),而OpenSSL解析-----BEGIN PUBLIC KEY-----格式时,期望的是符合X.509标准的SubjectPublicKeyInfo(SPKI)结构(经ASN.1 DER编码后再Base64编码)。RSA密钥能正常解析是因为其外部表示刚好就是SPKI格式,但EC密钥并非如此。
另外你指定了kSecAttrTokenIDSecureEnclave,Secure Enclave生成的EC密钥在导出原始数据时无异常,转换SPKI格式的逻辑和普通密钥一致。
修复代码
利用CryptoKit与Security框架的互转能力,将SecKey转为CryptoKit的公钥后导出SPKI格式数据,即可生成OpenSSL可识别的PEM:
import Foundation import Security import CryptoKit func generateKeys() throws -> (privateKey: SecKey, publicKey: SecKey) { let query: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeEC, kSecAttrKeySizeInBits as String: 256, kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, kSecAttrIsPermanent as String: false ] var error: Unmanaged<CFError>? guard let privateKey = SecKeyCreateRandomKey(query as CFDictionary, &error) else { throw error!.takeRetainedValue() as Error } let publicKey = SecKeyCopyPublicKey(privateKey)! return (privateKey, publicKey) } extension SecKey { func exportSPKIPEM() throws -> String { // 将SecKey转为CryptoKit的P256公钥 guard let rawData = SecKeyCopyExternalRepresentation(self, nil) else { throw NSError(domain: "KeyExportError", code: -1, userInfo: [NSLocalizedDescriptionKey: "获取密钥数据失败"]) } let cryptoKitPublicKey = try P256.KeyAgreement.PublicKey(rawRepresentation: rawData as Data) // 导出SPKI格式的DER数据 let spkiData = cryptoKitPublicKey.rawRepresentation // 转为带换行的Base64并添加PEM头脚 let base64Str = spkiData.base64EncodedString(options: [.lineLength64Characters]) return "-----BEGIN PUBLIC KEY-----\n\(base64Str)\n-----END PUBLIC KEY-----" } } func printPublicKey() { do { let keyPair = try generateKeys() let pemKey = try keyPair.publicKey.exportSPKIPEM() print(pemKey) } catch { print("错误:\(error)") } } printPublicKey()
验证方法
将输出的PEM内容保存为文件,执行以下OpenSSL命令:
openssl pkey -pubin -in my-public-ec.pem -text -noout
会输出符合prime256v1(即NIST P-256)曲线的公钥信息,与OpenSSL原生生成的结果一致。
内容的提问来源于stack exchange,提问作者Joris
相关产品推荐
相关产品推荐

