Swift从PEM文件创建SecKey报错-50:问题排查与解决
问题
我通过以下OpenSSL命令生成带DES3加密的RSA密钥对:
openssl genrsa -des3 -out WM_IO_my_rsa_key_pair 2048
尝试用SecKeyCreateWithData从PEM文件加载私钥创建SecKey时,出现错误:SecKeyCreate init(RSAPublicKey) failed: -50,代码实现如下:
import UIKit import Security func createKey(pem: String) -> SecKey? { let attributes: [NSObject : NSObject] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: NSNumber(value: 2048) ] let privateKey = pem .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "") .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "") .split(separator: "\n").joined() guard let privateKeyData = Data(base64Encoded: privateKey, options: .ignoreUnknownCharacters) else { return nil } var error: Unmanaged<CFError>? return SecKeyCreateWithData(privateKeyData as CFData, attributes as CFDictionary, &error) } let privateKey = """ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpySPOXAAsi1jN vxDrNfinFOUZlLk38P8BF2ukJWU7OOAXol6TG8fFrn8O+UVW4jjPTZjLT9G6385N iervmwopS5CtHS2p0ptLm1ExigZAuS/LTaIkw3yugr4b+5roEwL9nFW0Qfd4o/ds 3lKPtdwtO0rfqTfuZ6CqcQP0sTJcky7nk3mIyz6jZOZE2QLL/oF/oUKsi5Wt5uJp uluZ+gt087Ftm1oGKR8lZt5bucbD7WZnmlckNyUh7O973mqqDZ6zTwrgNuxIBmtr afNetsgZv6/We56IWenKayWW1xA9icPhmViJtzPU3Gu8HW/FMovyRZAMFD1Yzf+L eiSGC5x9AgMBAAECggEAGOrN+HEEDYV9yOQrhXlsPokQfkqXTCBwLCbVw0dBrglQ yecoXgqLrPVI7Fek13VnxPSsYdoa+4Pw8Ow2sGdefGT8nItVskCYTeZDajPJayJC Y2HHVAHkgG/rmou4VirEG5gf885ilS/rFe0izLhx0amL+XsKHFDVAW6ImBaRP4iU 82fkZtLlh4DLi6w/oNu3ePZkMeTl4aAkJH8gRy2Mzsyl0DNi5+mH0du12BVSca58 iAXEhufIweTvDqb3lx0CR5+0+dbk/MeIvoklDCkPAlK9IOXr9m0UYjWXNYTADLi8 PmQf8k7pf74ma/2bFuT8LakIA6z3HEwLO7iKm4VVOQKBgQDYVG7AJWJL3DDMCpz3 csP+fKccr72Q3VKCZ5uq0jC/Wp4jfNip/b76Rt3xb8nqzgIDntu+B6Vzz6HPB5d4 j8510lNZrRzIQj0unxOx7pJHIGHhGv2dJ00IqVa5aNL8aCNhxXhgR3vIojyoo8R9 nc4WAQu4ID+xOCsqtvNBm6T1jwKBgQDI67Obqjqt1IDWV5/7dJundWEtfGBdHYBd iuVxoyqOKAeasaWXuUxJgpzy/ukIAuI5WtzR8nP/US8MIUkRj7eXDi3E2tgpkUwZ IT9StEdXM8UznpyXfQX9oMmlHC8MZRwLJkldcbGMjsfXsVcAMbe+HBmXs+izsxqe icsEPPe/MwKBgQDU2O5HPAElJrcUa3TZux/AayF5hih8OmcOS6bMQhcYj658uD/t se6QDd4dyaHf12X/7fPDW36dHjPUoWGVi9jV8GV2HG/vUc0k6/vS3CsstF3ZwFa8 o4iV9xePQeYl1sjJUCQKhwrx8z6/prKT7gpxeAHx3jkMw3klg/CAIwYBXQKBgFIc OT+Rlv95S9nM352k7wPFrZwoKz2Ck/YmkFQbiYWlCE6I8RKLcIjOLxQDZvqWKxuj bYEDY7Jg3ChJ5hGeOTorWjsL8LE0JvRSKQ3EjS8vAhVxaa9jMbKQJjgqx3N6Uraf w/XDQ/scUsFsQRDcQKoZ07+yj5P4yxUlXOlzfRAPAoGBALri0o6PhjRRPwKzE3gO ClUJ1KTEhA55GOPs5ZDPxDckYigSC+R8nLLxeueFiFkIDrar85tiO9J4P0j7tovB Ivu6+QWQso3U3RC2Deb3uWagKHOt9m+DB8LdKsLpY/aPUXzPKKXJ4BWVIYExm418 FUzB7PCpc0Cdjg6A7Ca2cP0U -----END PRIVATE KEY----- """ createKey(pem: privateKey)
解决方案
问题根源
错误码-50表示参数无效,核心问题有两点:
- 生成的是DES3加密的PKCS#1格式私钥,但代码中使用的是PKCS#8格式的PEM头(
-----BEGIN PRIVATE KEY-----),格式不匹配;且iOS原生SecKeyCreateWithData无法直接读取加密私钥,必须先解密。 SecKeyCreateWithData要求输入的私钥数据为未加密的PKCS#8格式DER编码数据,原始PKCS#1格式不被支持。
修复步骤
1. 转换私钥格式为未加密的PKCS#8
使用OpenSSL命令转换格式,执行时需输入生成密钥时设置的密码:
openssl pkcs8 -topk8 -inform pem -in WM_IO_my_rsa_key_pair -outform pem -nocrypt -out unencrypted_pkcs8_key.pem
2. 调整代码适配格式
修改代码以正确处理PKCS#8格式私钥,并添加错误日志便于排查:
import UIKit import Security func createKey(pem: String) -> SecKey? { let attributes: [NSObject : NSObject] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: NSNumber(value: 2048) ] // 清理PEM中的所有空白字符(换行、空格等) let cleanedPem = pem .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "") .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "") .components(separatedBy: .whitespacesAndNewlines) .joined() guard let privateKeyData = Data(base64Encoded: cleanedPem) else { print("私钥Base64解码失败") return nil } var error: Unmanaged<CFError>? guard let secKey = SecKeyCreateWithData(privateKeyData as CFData, attributes as CFDictionary, &error) else { if let error = error?.takeRetainedValue() { print("SecKey创建失败: \(error.localizedDescription),错误码: \(CFErrorGetCode(error))") } return nil } return secKey } // 替换为转换后的未加密PKCS#8私钥内容 let privateKey = """ -----BEGIN PRIVATE KEY----- # 此处粘贴unencrypted_pkcs8_key.pem中的内容 -----END PRIVATE KEY----- """ if let key = createKey(pem: privateKey) { print("SecKey创建成功") } else { print("SecKey创建失败") }
额外说明
- 若需保留私钥加密状态,iOS原生Security框架无法直接读取,需借助OpenSSL库或第三方加密库先解密为PKCS#8格式数据,再调用
SecKeyCreateWithData。 - 错误码-50常见于参数不匹配场景,比如密钥格式错误、属性设置冲突、Base64解码失败等,添加错误日志可快速定位问题。
内容的提问来源于stack exchange,提问作者Berry Blue
相关产品推荐
相关产品推荐

