当前位置: 首页 > article >正文

如何加载私钥为 SecKeyRef

本文介绍如何在 iOS/macOS 下将私钥加载为 SecKeyRef,涵盖 PEM 格式的 ECC 密钥读取、X9.63 数据构建、以及与 Keychain 的集成。


1. 使用 SecKeyCreateWithData 加载私钥

Apple 提供的 SecKeyCreateWithData 方法可以直接将密钥数据加载为 SecKeyRef 对象。

SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef attributes, CFErrorRef  _Nullable *error);

文档:SecKeyCreateWithData(::_😃 | Apple Developer Documentation

attributes 必须包含如下 key

  • kSecAttrKeyType:密钥类型,如 ECC、RSA
  • kSecAttrKeyClass:密钥类(公钥/私钥)

keyData 的数据格式

  • ECC 私钥数据应采用 X9.63 格式。
  • RSA 私钥应为 PKCS #1 格式。

详见:SecKeyCopyExternalRepresentation(:😃 | Apple Developer Documentation

X9.63 格式说明

  • ECC 公钥:04 || X || Y
  • ECC 私钥:04 || X || Y || K
    其中 X、Y 为公钥坐标,K 为大端序编码的私钥值,所有字段均为定长,必要时补零。

构建 X9.63 可参考:将加密工具包密钥存储在钥匙串 | 苹果开发者文档


2. PEM 格式转换与读取

2.1 PEM 转 P256

如果你有 PEM 编码的 P256 私钥,可用 CryptoKit 直接解析为 P256 私钥对象:

文档:init(pemRepresentation:) | Apple Developer Documentation

2.2 读取 ECC PEM 密钥为 SecKey

示例代码(Swift):

/// 加载 PEM 证书为 SecKey
/// - Parameter name: PEM 文件名(不含扩展名)
/// - Returns: SecKey 类型值
class func loadECCSecKeyFromPem(_ name: String) -> SecKey? {guard let pemURL = Bundle.main.url(forResource: name, withExtension: "pem") else {return nil}do {let pemStr = try String(contentsOf: pemURL)let p256 = try P256.Signing.PrivateKey(pemRepresentation: pemStr)let attributes: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,kSecAttrKeyClass as String: kSecAttrKeyClassPrivate]// kSecAttrIsPermanent 是否需要存储,默认不存储guard let secKey = SecKeyCreateWithData(p256.x963Representation as CFData,attributes as CFDictionary,nil)else {return nil}return secKey} catch {print(error)return nil}
}

如果需要将 PEM 转换为 X9.63,可先用 CryptoKit 读取后再取其 x963Representation 字节。


3. iOS 端创建 ECC 私钥并存储到 Keychain

如需新建私钥并写入钥匙串,可参考如下 Objective-C 代码:

+ (NSDictionary *)privateKeyParams {return @{(__bridge NSString *) kSecClass : (__bridge NSString *) kSecClassKey,(__bridge NSString *) kSecAttrApplicationLabel : MTRCAKeyChainLabel,// 存入钥匙串时,按需设置属性(__bridge NSString *) kSecAttrKeyClass : (__bridge NSString *) kSecAttrKeyClassSymmetric,};
}
+ (NSDictionary *)privateKeyCreationParams {// 按需设置密钥长度const size_t keySizeInBits = 256;return @{(__bridge NSString *) kSecAttrKeyClass : (__bridge NSString *) kSecAttrKeyClassPrivate,(__bridge NSString *) kSecAttrKeyType : (__bridge NSNumber *) kSecAttrKeyTypeECSECPrimeRandom,(__bridge NSString *) kSecAttrKeySizeInBits : @(keySizeInBits),(__bridge NSString *) kSecAttrIsPermanent : @(NO), // 是否永久保存};
}
/// 创建并存储 ECC 私钥
+ (SecKeyRef)generateCAPrivateKey {NSMutableDictionary *query = [[NSMutableDictionary alloc] initWithDictionary:[MSMatterFabricKeys privateKeyParams]];// 先删除旧密钥,防止添加失败SecItemDelete((__bridge CFDictionaryRef) query);CFErrorRef error = NULL;SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)[MSMatterFabricKeys privateKeyCreationParams], &error);if (error) {NSLog(@"Could not generate private key: %@", (__bridge NSError *) error);return NULL;}NSData *keyData = (__bridge_transfer NSData *) SecKeyCopyExternalRepresentation(key, &error);if (error) {NSLog(@"Could not get key external representation: %@", (__bridge NSError *) error);CFRelease(key);return NULL;}query[(__bridge NSString *) kSecValueData] = [keyData base64EncodedDataWithOptions:0];OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL);if (status != errSecSuccess) {NSLog(@"Failed to store private key : %d", status);CFRelease(key);return NULL;}return key;
}

4. 证书直接读取

如需直接读取证书内容,可参考:证书读取方法(CSDN)


5. 相关资源

  • SecKeyCreateWithData | Apple Developer Documentation
  • SecKeyCopyExternalRepresentation | Apple Developer Documentation
  • 将加密工具包密钥存储在钥匙串 | Apple Developer Documentation
  • PEM 转 P256 | Apple Developer Documentation
  • 证书读取方法(CSDN)

http://www.lryc.cn/news/2396125.html

相关文章:

  • @Pushgateway自定义脚本推送数据
  • kubernate解决 “cni0“ already has an IP address different from 10.244.0.1/24问题
  • el-tree拖拽事件,限制同级拖拽,获取拖拽后节点的前后节点,同级拖拽合并父节点name且子节点加入目标节点里
  • day62—DFS—太平洋大西洋水流问题(LeetCode-417)
  • 《Python基础》第2期:环境搭建
  • WSL 安装 Debian 12 后,Linux 如何安装 curl , quickjs ?
  • [CSS3]vw/vh移动适配
  • Python进阶与常用库:探索高效编程的奥秘
  • nt!MiDispatchFault函数分析之nt!MiCompleteProtoPteFault函数的作用
  • YOLOX 的动态标签分类(如 SimOTA)与 Anchor-free 机制解析2025.5.29
  • 打卡day42
  • 小白的进阶之路系列之八----人工智能从初步到精通pytorch综合运用的讲解第一部分
  • 724.寻找数组的中心下标前缀和
  • 软考-系统架构设计师-第十六章 层次式架构设计理论与实践
  • 甘特图 dhtmlxGantt.js UA实例
  • Docker学习笔记:基础知识
  • 5.2 初识Spark Streaming
  • uv:一个现代化的 Python 依赖管理工具
  • Python趣学篇:交互式词云生成器(jieba + Tkinter + WordCloud等)
  • 理解解释器架构:原理、组成与运行机制全解析
  • 2025华为OD机试真题+全流程解析+备考攻略+经验分享+Java/python/JavaScript/C++/C/GO六种语言最佳实现
  • Python应用for循环临时变量作用域
  • 设计模式——桥接设计模式(结构型)
  • LLaDa——基于 Diffusion 的大语言模型 打平 LLama 3
  • Apache SeaTunnel部署技术详解:模式选择、技巧与最佳实践
  • 2. 数据结构基本概念 (2)
  • 鸿蒙5.0+ 多协议设备发现与分布式软总线技术实践
  • STM32F407寄存器操作(多通道单ADC+DMA)
  • 基于React和TypeScript的金融市场模拟器开发与模式分析
  • 剑指offer13_剪绳子