如何使用CryptoKit在Swift中对哈希值进行签名
将Node.js RSA签名逻辑移植到Swift
一、使用CryptoKit实现
CryptoKit本身不直接支持解析带密码的PEM私钥,需要借助Security框架先将PEM导入为SecKey,再转换为CryptoKit兼容的密钥类型。
1. 读取并解析带密码的PEM私钥
import CryptoKit import Security func loadPrivateKey(from pemPath: String, passphrase: String) throws -> RSA.Signing.PrivateKey { // 读取PEM文件内容 guard let pemData = try? Data(contentsOf: URL(fileURLWithPath: pemPath)) else { throw NSError(domain: "KeyError", code: 1, userInfo: [NSLocalizedDescriptionKey: "无法读取私钥文件"]) } // 配置密钥导入参数 let options: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: 2048, kSecReturnPersistentRef: false, kSecReturnRef: true, kSecAttrPEMPassword: passphrase.data(using: .utf8)! ] // 导入PEM私钥为SecKey var secKey: SecKey? let status = SecKeyCreateWithData(pemData as CFData, options as CFDictionary, &secKey) guard status == errSecSuccess, let key = secKey else { throw NSError(domain: "KeyError", code: 2, userInfo: [NSLocalizedDescriptionKey: "私钥导入失败,状态码:\(status)"]) } // 将SecKey转换为CryptoKit的RSA私钥 guard let cryptoKitKey = RSA.Signing.PrivateKey(secKey: key) else { throw NSError(domain: "KeyError", code: 3, userInfo: [NSLocalizedDescriptionKey: "无法转换为CryptoKit私钥"]) } return cryptoKitKey }
2. 执行签名(匹配Node.js逻辑)
Node.js的crypto.createSign('sha256')默认对输入数据做SHA256哈希后,用PKCS#1 v1.5填充签名,CryptoKit可直接通过指定算法完成对应操作:
func signHashString(_ hashString: String, with privateKey: RSA.Signing.PrivateKey) throws -> String { // 将目标字符串转为Data guard let data = hashString.data(using: .utf8) else { throw NSError(domain: "DataError", code: 1, userInfo: [NSLocalizedDescriptionKey: "字符串转Data失败"]) } // 执行RSA-SHA256签名 let signature = try privateKey.signature(for: data, signatureAlgorithm: .rsaSignatureMessagePKCS1v15SHA256) // 转换为Base64字符串 return signature.base64EncodedString() }
使用示例
do { let privateKey = try loadPrivateKey(from: "/path/to/WM_IO_my_rsa_key_pair", passphrase: "你的密码") let hashString = "需要签名的字符串" let signatureBase64 = try signHashString(hashString, with: privateKey) print("签名结果:\(signatureBase64)") } catch { print("签名失败:\(error.localizedDescription)") }
二、使用CommonCrypto/Security框架实现
若不想依赖CryptoKit,可直接用Security框架完成签名:
1. 加载带密码的PEM私钥
import Security func loadSecPrivateKey(from pemPath: String, passphrase: String) throws -> SecKey { guard let pemData = try? Data(contentsOf: URL(fileURLWithPath: pemPath)) else { throw NSError(domain: "KeyError", code: 1, userInfo: [NSLocalizedDescriptionKey: "无法读取私钥文件"]) } let options: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: 2048, kSecReturnPersistentRef: false, kSecReturnRef: true, kSecAttrPEMPassword: passphrase.data(using: .utf8)! ] var secKey: SecKey? let status = SecKeyCreateWithData(pemData as CFData, options as CFDictionary, &secKey) guard status == errSecSuccess, let key = secKey else { throw NSError(domain: "KeyError", code: 2, userInfo: [NSLocalizedDescriptionKey: "私钥导入失败,状态码:\(status)"]) } return key }
2. 执行签名
func signWithSecKey(_ hashString: String, with privateKey: SecKey) throws -> String { guard let data = hashString.data(using: .utf8) else { throw NSError(domain: "DataError", code: 1, userInfo: [NSLocalizedDescriptionKey: "字符串转Data失败"]) } // 确认私钥支持指定签名算法 let algorithm = SecKeyAlgorithm.rsaSignatureMessagePKCS1v15SHA256 guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else { throw NSError(domain: "SignError", code: 2, userInfo: [NSLocalizedDescriptionKey: "私钥不支持指定签名算法"]) } // 执行签名 var error: Unmanaged<CFError>? guard let signatureData = SecKeyCreateSignature(privateKey, algorithm, data as CFData, &error) as Data? else { throw error!.takeRetainedValue() as Error } // 转换为Base64字符串 return signatureData.base64EncodedString() }
使用示例
do { let privateKey = try loadSecPrivateKey(from: "/path/to/WM_IO_my_rsa_key_pair", passphrase: "你的密码") let hashString = "需要签名的字符串" let signatureBase64 = try signWithSecKey(hashString, with: privateKey) print("签名结果:\(signatureBase64)") } catch { print("签名失败:\(error.localizedDescription)") }
关键注意事项
- Node.js默认使用PKCS#1 v1.5填充方式,Swift中必须对应使用
.rsaSignatureMessagePKCS1v15SHA256算法,才能保证签名结果一致。 - 若私钥为PKCS#8格式,上述代码同样适用,Security框架会自动识别。
- 处理文件路径时,需确保App拥有对应文件的读取权限(比如iOS中需将文件加入项目或使用Documents目录)。
内容的提问来源于stack exchange,提问作者Berry Blue
相关产品推荐
相关产品推荐

