移动/游戏
在 Apple 平台用 CryptoKit 做 Swift…
一句话:在 Apple 平台用 Swift 实现哈希、HMAC、AES-GCM/ChaChaPoly、签名、ECDH、HPKE、后量子与 Secure Enclave 加密功能时,按可用性和安全清单落地。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Apple 平台用 CryptoKi特定
解决思路
- 对 iOS 13+ 的哈希使用 SHA256/SHA384/SHA512;对 SHA3_256/SHA3_384/SHA3_512 仅在 iOS 26+ 使用,并让它们都遵循 HashFunction。
- 一次性哈希:import CryptoKit,调用 SHA256.hash(data: data),用 digest.compactMap { String(format: "%02x", $0) }.joined() 转十六进制。
- SHA-3 用 #available(iOS 26.0, *) 包住 SHA3_256.hash(data: data),除非部署目标是 iOS 26+。
- 大文件或流式输入用增量哈希:var hasher = SHA256(); hasher.update(data: chunk1); hasher.update(data: chunk2); let digest = hasher.finalize()。
- 安全敏感比较直接比较 CryptoKit digest 值(expected == actual),不要先把 digest 转成字符串或数组再比较。
- 协议需要带密钥的消息认证时使用 HMAC;用 isValidAuthenticationCode 验证,不要自己比较序列化值。
- 计算认证码:let key = SymmetricKey(size: .bits256); let mac = HMAC<SHA256>.authenticationCode(for: data, using: key)。
- 验证认证码:let isValid = HMAC<SHA256>.isValidAuthenticationCode(mac, authenticating: data, using: key)。
- 增量 HMAC:var hmac = HMAC<SHA256>(key: key); hmac.update(data: chunk1); hmac.update(data: chunk2); let mac = hmac.finalize()。
- 对称加密优先使用 CryptoKit 提供的 AES-GCM 或 ChaChaPoly;两者都生成包含 nonce、ciphertext、authentication tag 的 sealed box。
- AES-GCM 作为默认选择:let sealedBox = try AES.GCM.seal(plaintext, using: key); let ciphertext = sealedBox.combined!; 解密用 AES.GCM.SealedBox(combined:) 和 AES.GCM.open(box, using: key)。
- 当 AES 硬件加速不可用,或需要与要求 ChaCha20-Poly1305 的协议(如 TLS、WireGuard)互操作时,使用 ChaChaPoly:ChaChaPoly.seal、ChaChaPoly.SealedBox(combined:)、ChaChaPoly.open。
- 需要元数据保持明文但防篡改时,给两种密码都传入 AAD:AES.GCM.seal(plaintext, using: key, authenticating: header),打开时同样传 authenticating: header。
- SymmetricKey 默认用 .bits256 以生成 AES-256-GCM 或 ChaChaPoly 密钥;从已有数据创建时用 SymmetricKey(data: existingKeyData)。
- 公钥签名支持 NIST 曲线 P256/P384/P521 上的 ECDSA,以及 Curve25519 上的 Ed25519。
- NIST 曲线签名:let signingKey = P256.Signing.PrivateKey(); let signature = try signingKey.signature(for: data); 用 publicKey.isValidSignature(signature, for: data) 验证;P384/P521 替换曲线名即可。
- NIST 密钥可序列化为 DER、PEM、X9.63 和 raw;具体示例见 references/cryptokit-patterns.md。
- Curve25519/Ed25519 签名:let signingKey = Curve25519.Signing.PrivateKey(); let signature = try signingKey.signature(for: data); 用 publicKey.isValidSignature(signature, for: data) 验证。
- Curve25519 密钥只用 rawRepresentation,不支持 DER/PEM/X9.63。
- 曲线选择:默认 P256;需要更高安全要求用 P384;需要最高 NIST 安全级别用 P521;需要与 Ed25519 协议互操作或追求简单快速 API 用 Curve25519;注意 Curve25519 无 Secure Enclave 支持。
- 密钥协商:两方用 ECDH 从公私钥对派生共享对称密钥。P256 示例:aliceKey.sharedSecretFromKeyAgreement(with: bobKey.publicKey);Bob 用自己的私钥和 Alice 公钥计算同一个 sharedSecret。
- 用 HKDF 从 SharedSecret 派生对称密钥:sharedSecret.hkdfDerivedSymmetricKey(using: SHA256.self, salt: Data("salt".utf8), sharedInfo: Data("my-app-v1".utf8), outputByteCount: 32)。
- Curve25519 ECDH:Curve25519.KeyAgreement.PrivateKey() 和 sharedSecretFromKeyAgreement,再用 hkdfDerivedSymmetricKey(using: SHA256.self, salt: Data(), sharedInfo: Data("context".utf8), outputByteCount: 32)。
- SharedSecret 不能直接当 SymmetricKey;优先用 hkdfDerivedSymmetricKey(HKDF RFC 5869),需要与 X9.63 系统互操作时用 x963DerivedSymmetricKey。
- 始终提供非空且与具体协议上下文绑定的 sharedInfo 字符串。
- iOS 17+ 需要向接收方公钥加密时使用 HPKE;优先用 HPKE,而不是手写 ECDH + HKDF + AEAD。
- HPKE 发送方:定义 info = Data("my-protocol-v1".utf8),用 HPKE.Sender(recipientKey: recipientKey.publicKey, ciphersuite: .Curve25519_SHA256_ChachaPoly, info: info);取 sender.encapsulatedKey;用 sender.seal(plaintext, authenticating: Data("metadata".utf8)) 加密。
- HPKE 接收方:用 HPKE.Recipient(privateKey: recipientKey, ciphersuite: .Curve25519_SHA256_ChachaPoly, info: info, encapsulatedKey: encapsulatedKey) 解密。
- HPKE.Sender 和 HPKE.Recipient 是有状态的;保持为 var,把 encapsulatedKey 随密文发送,并按 seal 的相同顺序 open 消息;ciphersuite 选择和后量子 HPKE 见 references/cryptokit-patterns.md。
- iOS 26+ 使用后量子 API:密钥封装用 MLKEM768、MLKEM1024;混合 HPKE 用 XWingMLKEM768X25519 和 .XWingMLKEM768X25519_SHA256_AES_GCM_256;数字签名用 MLDSA65、MLDSA87。
- iOS 26+ 支持 Secure Enclave 变体:SecureEnclave.MLKEM768、SecureEnclave.MLKEM1024、SecureEnclave.MLDSA65、SecureEnclave.MLDSA87。
- 迁移时若同时需要经典和抗量子安全性,使用混合机制;并为比 P256/Curve25519 大得多的公钥、密文和签名预留空间。
- Secure Enclave 提供硬件支持密钥存储,私钥永不离开硬件;经典椭圆曲线 CryptoKit 支持 P256 签名和密钥协商;iOS 26+ 支持硬件上暴露 Secure Enclave ML-KEM 密钥封装和 ML-DSA 签名类型。
- 使用 Secure Enclave 前检查:guard SecureEnclave.isAvailable else { /* 回退到软件密钥 */ return }。
- 创建 Secure Enclave 签名密钥:let privateKey = try SecureEnclave.P256.Signing.PrivateKey(); 其 publicKey 是标准 P256.Signing.PublicKey;用 privateKey.signature(for: data) 签名,用 publicKey.isValidSignature(signature, for: data) 验证。
- 需要生物识别或密码门控时,用 SecAccessControl 配合 .privateKeyUsage;详细 Keychain 策略留在 swift-security 领域处理。
- 持久化 Secure Enclave 密钥:导出 privateKey.dataRepresentation 得到仅同一设备 Secure Enclave 可恢复的加密 blob,存入 Keychain;用 SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: blob) 恢复。
- Secure Enclave 密钥协商:let seKey = try SecureEnclave.P256.KeyAgreement.PrivateKey(); let sharedSecret = try seKey.sharedSecretFromKeyAgreement(with: peerPublicKey)。
- 不要把 SharedSecret 直接当密钥用;必须用 HKDF 派生:sharedSecret.hkdfDerivedSymmetricKey(using: SHA256.self, salt: salt, sharedInfo: info, outputByteCount: 32)。
- 不要复用 nonce 或硬编码 nonce;不要手动构造 AES.GCM.Nonce(data: Data(repeating: 0, count: 12));让 CryptoKit 默认生成随机 nonce:try AES.GCM.seal(data, using: key)。
- 不要忽略认证标签验证;不要手动剥离 tag 再解密;始终用 AES.GCM.open() 或 ChaChaPoly.open(),它们会自动验证 tag。
- 不要用 MD5/SHA1 做安全用途;Insecure.MD5 和 Insecure.SHA1 只用于遗留兼容(校验和验证、协议互操作);新安全敏感操作用 SHA256 或更强。
- 不要把对称密钥存 UserDefaults;应存 Keychain;Keychain 存储模式见 references/cryptokit-patterns.md。
- 不要不检查 Secure Enclave 可用性就创建 SecureEnclave.P256.Signing.PrivateKey(),否则模拟器或不支持硬件会崩溃;先 guard SecureEnclave.isAvailable。
- 审查时确认使用 CryptoKit,而不是 CommonCrypto 或原始 Security framework。
- 审查时确认哈希使用 SHA256+,安全用途无 MD5/SHA1。
- 审查时确认 HMAC 验证用 isValidAuthenticationCode(常量时间)。
- 审查时确认对称加密用 AES-GCM 或 ChaChaPoly,密钥 256-bit。
- 审查时确认 nonce 随机(默认),没有硬编码或复用。
- 审查时确认需要完整性保护的元数据使用 AAD。
- 审查时确认 SharedSecret 通过 HKDF 派生,不直接使用。
- 审查时确认 sharedInfo 非空且上下文特定。
- 审查时确认 iOS 17+ 对接收方公钥加密使用 HPKE,而非自定义 ECDH+HKDF+AEAD。
- 审查时确认 SHA-3 和后量子 API 用 iOS 26+ 可用性保护。
- 审查时确认使用 Secure Enclave 前检查可用性。
- 审查时确认 Secure Enclave 密钥 dataRepresentation 存在 Keychain。
- 审查时确认私钥不必要地不记录、不打印、不序列化。
- 审查时确认对称密钥存 Keychain,不存 UserDefaults 或文件。
- 审查时确认考虑加密出口合规(ITSAppUsesNonExemptEncryption)。
- 扩展模式(密钥序列化、Insecure 模块、Keychain 集成、AES 密钥包装、HPKE)见 references/cryptokit-patterns.md;Apple 文档 CryptoKit、HPKE、量子安全工作流、常见加密操作示例、Storing CryptoKit Keys in the Keychain。
适用边界 · 注意事项
- 非 Apple 平台或非 Swift 项目,或不能引入 CryptoKit 的环境不适用。
- 部署目标低于 iOS 13,或必须支持低于 iOS 17 的 HPKE / 低于 iOS 26 的 SHA-3 和后量子 API 且无法做可用性回退时,不要直接使用这些新 API。
- 需要 FIPS 认证、CryptoKit 不支持的算法,或必须与 CommonCrypto/Security 旧实现保持完全相同序列化时,不宜强行只用本文模式。