第一章:密码学基础与iOS安全概述

做iOS密码SDK,首先要明白两件事:密码学能干什么,iOS给我们提供了哪些安全基础。说白了,这块没搞懂,后面编译出来的SDK就跟纸糊的差不多。我刚开始接触iOS安全时,也踩过不少坑,今天把这些经验掰开揉碎讲给你。

1.1 密码学核心概念——你每天都在用,但未必真懂

密码学不是什么玄学。它就是你手机里那把看不见的锁。我举个例子:你用微信发一条消息,对方看到的是明文,中间任何人截获的是一堆乱码——这就是加密。

咱们做SDK,常用的密码学技术其实就这几种:

技术分类 典型算法 用途举例 我心里它的地位
对称加密 AES-256, ChaCha20 本地数据加密、网络传输加密 主力,速度快
非对称加密 RSA, ECDH, Ed25519 密钥协商、数字签名 安全但慢,只用在关键节点
哈希函数 SHA-256, SHA-512 数据完整性校验、密码存储 不可逆,用来“核验”不是“保密”
密钥派生 PBKDF2, HKDF, Argon2 从密码生成加密密钥 防暴力破解的命根子

这里有个关键点:不要自己发明算法。永远使用标准库实现。我在项目里见过有人自己写了个“魔改AES”,结果安全审计直接被判死刑——连我们自己都不知道那算不算真AES。

核心原则:密码学里最难的不是算法实现,而是如何组合它们(比如“加密+MAC”到底谁先谁后?)。组合错了,整套方案等于没做。

1.2 iOS安全机制——苹果给你铺好的路

iOS不是裸奔的Linux。它从硬件到软件建了一整套安全墙。咱们做密码SDK,必须知道哪些墙可以靠,哪些墙不能碰。

1.2.1 硬件安全模块:Secure Enclave

从iPhone 5s开始,苹果给每台设备装了一个独立的协处理器——Secure Enclave。说白了就是一个专属安全芯片,有自己的ROM、RAM、真随机数发生器。它跟主CPU之间只通过一个隔离邮箱通信。我做过一个项目,需要生成一个永远不出芯片的私钥,就得用Secure Enclave。注意:它只支持特定的算法(如EC keys 256 bit,RSA 2048 bit),不支持AES。

1.2.2 数据保护:Data Protection API

苹果的Data Protection是基于文件级的加密。每个文件有独立的加密密钥,密钥又受设备锁屏密码保护。这个机制非常成熟,但有个大坑:如果你用NSFileManager直接写文件,默认可能只获得“直到设备解锁”级别的保护,重启后文件无法读取。我曾经写SDK时忘了设置completeUntilFirstUserAuthentication,结果用户重启后SDK启动报错,调试到崩溃才发现。

1.2.3 Keychain服务

Keychain是iOS上存储敏感数据的官方方案(密码、证书、私钥)。它会把数据加密后存到SQLite数据库里,该数据库的加密密钥受硬件保护。Keychain本身很稳定,但你得懂它的Access Group和Access Control。举个例子:你设置kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,那备份、迁移时这笔数据就没了——用户换手机怎么也恢复不了。我有个客户因为没有正确设置Accessibility,导致十多万用户的所有密钥在系统升级后全部丢失……那场面,唉。

避坑提醒:Keychain的kSecMatchLimit选项默认是kSecMatchLimitOne,如果你要查询多条记录,记得改成kSecMatchLimitAll。否则只会返回第一条,剩下的石沉大海——我曾在内部审计时发现SDK只存用到了第一条密钥,后面的全被忽略了,吓出一身冷汗。

1.2.4 应用沙箱与代码签名

每个iOS应用跑在独立的沙箱里,不能访问其他App的文件。但Keychain通过同一Team ID可以共享。这个特性对SDK很重要:如果你的密码SDK需要多个业务模块共享一个主密钥,可以用Keychain Access Group。但注意,一旦别人拿到你的Team ID,理论上也可以共享——所以权限要收得紧。

1.3 为什么要在SDK里封装密码学?

你可能想问:“苹果不是已经提供CommonCrypto和CryptoKit了吗?为什么还要自己编译SDK?”

说实话,我刚入行时也是一样的疑问。但做多了就发现三个理由:

  1. 统一接口——团队里有人用ObjC,有人用Swift,有人还要兼容C++。你提供一个统一的C/ObjC接口SDK,省去每个人学习不同API的功夫。
  2. 规避API歧义——CommonCrypto的一些老接口文档不全,不同iOS版本行为有细微差异。比如CCCryptorCreate在iOS 10上遇到无效密钥长度会返回错误,在iOS 13上却直接崩溃(我记得这是个已知bug)。你在SDK里封装好,上层调用就不怕踩坑。
  3. 性能优化和算法固化——有些业务需要高性能的GCM或ChaCha20,CommonCrypto不一定是最优的。你可以用libsodium或BoringSSL自己编译,把加速指令集(ARMv8.3的SHA扩展)踩满。

我的经验:如果项目需求只是简单的AES-CBC,直接用CryptoKit或CommonCrypto就好,别自己编译。只有当你需要跨平台、定制算法或极致性能时,才启动SDK编译。一句话:不要造轮子,除非轮子已经变形了。

1.4 本章知识结构一览

我把第一章的核心逻辑画成了一张图。你琢磨琢磨,密码SDK的根基就在这里。

第1章知识结构图:密码学基础与iOS安全 iOS密码SDK编译 · 第一章知识体系 对称加密 AES-256 / ChaCha20 适合大量数据加密 非对称加密 RSA / ECDH / Ed25519 密钥协商与签名 哈希 & 密钥派生 SHA-256 / PBKDF2 完整性 + 防暴力破解 iOS安全机制层 Secure Enclave · Keychain · Data Protection · 沙箱隔离 提供硬件背书、密钥存储、文件加密、进程隔离 密码SDK编译目标 统一接口 · 规避坑 · 性能极致 SDK要同时利用 密码学原语 + iOS安全 编译前先理清 算法组合 + 硬件访问

1.5 一点私货——我过去犯过的三个错误

好,基础讲完了,说点我自己的血泪史,你记下来以后少走弯路。

  • 第一个坑:信任用户输入当密钥——早期我做SDK时,让App直接传一段字符串给我当AES密钥。结果有人传了"123456"……后来加上了PBKDF2迭代,还把最小密钥熵检查做到SDK内部,再不给上层乱来。
  • 第二个坑:忽视随机数质量——SecRandomCopyBytes确实比rand()强,但Secure Enclave的随机数发生器在设备刚启动时、熵池未填充状态会有短暂的低熵窗口。我在低版本iOS 11上遇到过重启后第一次调用返回的随机数有规律,后来加了“预搅拌”才解决。
  • 第三个坑:Keychain同步问题——在真机上测试正常,但iCloud同步后,另一台设备的Keychain数据竟然拿不到正确的访问权限。排查了一天,原来是AccessGroup设置错了——我用了通配符,苹果在同步时认为不符合同一Team ID。