Apple 在 WWDC2019 推出了一个基于 Swift 的密码框架 CryptoKit,它让生成哈希值、加/解密数据、数字签名和密钥协商变得更加容易。
哈希值
-
提供了 3 种 Hash 函数:
- SHA256
- SHA384
- SHA512
-
哈希普通的 Data 类型的数据
let str = "Hello CryptoKit" let data = str.data(using: .utf8)!
let hash256 = SHA256.hash(data: data) let hash384 = SHA384.hash(data: data) let hash512 = SHA512.hash(data: data)
print(hash256.description)复制代码
-
哈希文件
if let filePath = Bundle.main.path(forResource: "secret", ofType: "json"), let data = FileManager.default.contents(atPath: filePath) {
let hash256 = SHA256.hash(data: data) let hash384 = SHA384.hash(data: data) let hash512 = SHA512.hash(data: data) print(hash256.description)
}复制代码
HMAC
HMAC 可以理解为一种更安全的 Hash,它需要借助于前面介绍的 Hash 函数。
// 构造一个salt
let salt = "YungFan".data(using: .utf8)!
// 密钥
let key = SymmetricKey(size: .bits256)
// HMAC with SHA256
let authenticationCode = HMAC<SHA256>.authenticationCode(for: salt, using: key)
print(authenticationCode)
// 验证
if HMAC<SHA256>.isValidAuthenticationCode(Data(authenticationCode),
authenticating: salt, using: key) {
print("未被篡改")
}复制代码
加解密数据
支持 AES-GCM 和 ChaChaPoly 算法。开发中首选 ChaChaChaPoly,因为按照官方宣称它在移动设备上的速度更快。ChaChaChaPoly 中的核心概念是ChaChaChaPoly.SealedBox
,它可以理解为只有通过密钥才能访问的数据容器,加密操作时把加密后的密文放在其中,解密操作时需要从中取出密文进行解密。
-
加密
// 明文 let str = "Hello CryptoKit" let data = str.data(using: .utf8)!
// 密钥,有3种长度的密钥 let key128 = SymmetricKey(size: .bits128) let key192 = SymmetricKey(size: .bits192) let key256 = SymmetricKey(size: .bits256)
// 加密 let encryptedContent = try? ChaChaPoly.seal(data, using: key256).combined复制代码
-
解密 ps;iOS开发交流技术群:欢迎你的加入,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长
// 解密 if let encryptedContent = encryptedContent { if let sealedBox = try? ChaChaPoly.SealedBox(combined: encryptedContent) { if let decryptedContent = try? ChaChaPoly.open(sealedBox, using: key256) { print(String(data: decryptedContent, encoding: .utf8)) }
// SealedBox的3个属性 let nonce = sealedBox.nonce let ciphertext = sealedBox.ciphertext let tag = sealedBox.tag print(sealedBox.combined == nonce + ciphertext + tag) }
}复制代码
数字签名
内置了 4 种不同的椭圆曲线类型用于创建和验证加密签名,分别是 Curve25519, P521, P384 和 P256,不同的类型有不同的安全性和速度,但通常选择 Curve25519。
-
产生公/私钥
// 私钥 let privateKey = Curve25519.Signing.PrivateKey() // 公钥 let publicKey = privateKey.publicKey // 发布公钥 let publicKeyData = publicKey.rawRepresentation 复制代码
-
私钥签名
let str = "Hello CryptoKit" let data = str.data(using: .utf8)!
let signature = try? privateKey.signature(for: data)复制代码
-
公钥验证
if let signature = signature { if publicKey.isValidSignature(NSData(data: signature) , for: data) { print("签名有效") } }复制代码
密钥协商
密钥协商是一个过程,通过这个过程,通信双方可以安全地选择一个加密密钥,然后用它来进行加解密数据。
// 构造一个salt,生成密钥时需要使用
let salt = "YungFan".data(using: .utf8)!
// 用户A和用户B都会生成一对公钥和私钥
let privateKeyA = P521.KeyAgreement.PrivateKey()
let publicKeyA = privateKeyA.publicKey
let privateKeyB = P521.KeyAgreement.PrivateKey()
let publicKeyB = privateKeyB.publicKey
// 用户A用私钥和用户B的公钥产生一个共享的密钥
let sharedSecretA = try? privateKeyA.sharedSecretFromKeyAgreement(with: publicKeyB)
let symmetricKeyA = sharedSecretA?.hkdfDerivedSymmetricKey(using: SHA256.self, salt: salt, sharedInfo: Data(), outputByteCount: 32)
// 用户B用私钥和用户A的公钥产生一个共享的密钥
let sharedSecretB = try? privateKeyB.sharedSecretFromKeyAgreement(with: publicKeyA)
let symmetricKeyB = sharedSecretB?.hkdfDerivedSymmetricKey(using: SHA256.self, salt: salt, sharedInfo: Data(), outputByteCount: 32)
if symmetricKeyA == symmetricKeyB {
print("A和B经过协商产生了共享密钥")
}