按下回车或点击查看完整尺寸图片
1. 加密与解密的基础知识
进行加密和解密操作,需要公钥和私钥。这些密钥通常通过安全隔离区、随机字符串、密码生成,或者从证书中获取。
2. 什么是签名和验证?
通过对数据进行签名,可以创建出一个数字签名。通过提供原始数据和签名,可以验证数据的完整性。
数字签名是接收方验证发送方身份真实性、数据完整性的保证。简单来说,它相当于手写签名。数字签名使用的是与加密/解密不同的另一套密钥对。
数字签名广泛应用于许多电子领域,例如当你要将应用提交测试或上传至App Store时,Xcode会对你的代码进行数字签名。通常,发送方对要发送的数据进行签名的流程如下:
- 发送方使用特定的哈希算法(例如:sha256)对数据进行加密。哈希算法的输出称为"摘要"(例如:6e04f289)。
- 然后,发送方使用自己的私钥对摘要进行加密。这个加密后的摘要就是数据的"数字签名"。
- 发送方将原始数据和加密后的摘要一起发送出去。请注意,加密后的摘要仅用于验证发送方身份,而消息本身并未使用签名和验证所用的同一私钥进行加密。消息的加密是通过类似于上一节所述方式创建的私钥来完成的。
接收方验证接收到的数据的流程如下:
- 接收方收到消息及其数字签名。
- 接收方使用发送方的公钥解密数字签名 -> 得到的结果是摘要。
- 接收方使用与发送方相同的哈希算法,对收到的明文数据进行哈希运算 -> 这将输出一个摘要。
- 如果步骤2(数字签名解密后)输出的摘要 = 步骤3(对接收到的明文数据哈希后)输出的摘要 -> 接收方就可以验证数据的完整性。
在本教程中,用于数字签名的私钥将存储在安全隔离区中,而公钥则存储在安全隔离区之外,并与接收方共享。
从证书中获取公钥和私钥
class CryptoGraphicOperationViewModel {
var p12Data: Data
var password: String
init(fileName: String = "Certificate", ext: String = "p12", password: String = "1233") {
self.p12Data = Self.insertCertificate() ?? Data()
self.password = password
}
static func insertCertificate(fileName: String, ext: String, password: String) -> Data? {
return Utils.dataFromFile(name: fileName, withExtension: ext)
}
public func encrypt(data: Data, algorithm: SecKeyAlgorithm = .rsaEncryptionOAEPSHA512AESGCM) -> Data? {
guard let result = Utils.certificateDataFromP12(p12Data: self.p12Data, password: self.password) else { return nil }
guard let publicAndPrivateKey = Utils.publicAndPrivateKey(pkcs12Entry: result.pkcs12Entry) else { return nil }
return self.encrypt(value: data, publicKey: publicAndPrivateKey.publicKey, algorithm: algorithm)
}
public func decrypt(data: Data, algorithm: SecKeyAlgorithm = .rsaEncryptionOAEPSHA512AESGCM) -> Data? {
guard let result = Utils.certificateDataFromP12(p12Data: self.p12Data, password: self.password) else { return nil }
guard let publicAndPrivateKey = Utils.publicAndPrivateKey(pkcs12Entry: result.pkcs12Entry) else { return nil }
return self.decrypt(encrypted: data, privateKey: publicAndPrivateKey.privateKey, algorithm: algorithm)
}
public func sign(dataToSign: Data, algorithm: SecKeyAlgorithm = .rsaSignatureMessagePKCS1v15SHA512) -> Data? {
guard let result = Utils.certificateDataFromP12(p12Data: self.p12Data, password: self.password) else { return nil }
guard let publicAndPrivateKey = Utils.publicAndPrivateKey(pkcs12Entry: result.pkcs12Entry) else { return nil }
return self.signThe(data: dataToSign, privateKey: publicAndPrivateKey.privateKey, algorithm: algorithm)
}
public func verify(signedData: Data, signature: Data, algorithm: SecKeyAlgorithm = .rsaSignatureMessagePKCS1v15SHA512) -> Bool {
guard let result = Utils.certificateDataFromP12(p12Data: self.p12Data, password: self.password) else { return false }
guard let publicAndPrivateKey = Utils.publicAndPrivateKey(pkcs12Entry: result.pkcs12Entry) else { return false }
return self.verifySigned(data: signedData, signature: signature, publicKey: publicAndPrivateKey.publicKey, algorithm: algorithm)
}
internal func encrypt(value: Data, publicKey: SecKey, algorithm: SecKeyAlgorithm) -> Data? {
guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, algorithm) else {
debugPrint("不支持的加密算法")
return nil
}
var errorRef: Unmanaged<CFError>?
guard let encryptedData = SecKeyCreateEncryptedData(publicKey, algorithm, value as CFData, &errorRef) else {
let error = errorRef?.takeRetainedValue()
debugPrint("加密错误:\(String(describing: error))")
return nil
}
return encryptedData as Data
}
internal func decrypt(encrypted: Data, privateKey: SecKey, algorithm: SecKeyAlgorithm) -> Data? {
guard SecKeyIsAlgorithmSupported(privateKey, .decrypt, algorithm) else {
debugPrint("不支持的解密算法")
return nil
}
var errorRef: Unmanaged<CFError>?
guard let decryptedData = SecKeyCreateDecryptedData(privateKey, algorithm, encrypted as CFData, &errorRef) as Data? else {
let error = errorRef?.takeRetainedValue()
debugPrint("解密错误:\(String(describing: error))")
return nil
}
return decryptedData
}
internal func signThe(data: Data, privateKey: SecKey, algorithm: SecKeyAlgorithm) -> Data? {
guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else {
debugPrint("不支持的签名算法")
return nil
}
var errorRef: Unmanaged<CFError>?
guard let signature = SecKeyCreateSignature(privateKey, algorithm, data as CFData, &errorRef) as Data? else {
let error = errorRef?.takeRetainedValue()
debugPrint("签名错误:\(String(describing: error))")
return nil
}
return signature as Data
}
internal func verifySigned(data: Data, signature: Data, publicKey: SecKey, algorithm: SecKeyAlgorithm) -> Bool {
guard SecKeyIsAlgorithmSupported(publicKey, .verify, algorithm) else {
debugPrint("不支持的验证算法")
return false
}
guard data.isNotEmpty else {
debugPrint("无法使用空签名数据进行验证")
return false
}
var errorRef: Unmanaged<CFError>?
guard SecKeyVerifySignature(publicKey, algorithm, data as CFData, signature as CFData, &errorRef) else {
debugPrint("验证错误:\(String(describing: errorRef?.takeRetainedValue() as Error?))")
return false
}
return true
}
}
从iOS安全隔离区生成密钥
// 创建访问控制对象
let access = SecAccessControlCreateWithFlags(
kCFAllocatorDefault, // 1
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, // 2
[.privateKeyUsage, .biometryAny], // 3
nil // 4
)!
let secEnclaveTag = "YourKey".data(using: .utf8)! // 5
let privateKeyParams: [String: AnyObject] = [
kSecAttrIsPermanent as String: true as AnyObject, // 6
kSecAttrApplicationTag as String: secEnclaveTag as AnyObject, // 7
kSecAttrAccessControl as String: access // 8
]
let attributes = [
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, // 9
kSecAttrKeySizeInBits as String: 256, // 10
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, // 11
kSecPrivateKeyAttrs as String: privateKeyParams // 12
] as CFDictionary
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error
}
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
print("公钥生成错误")
return ""
}
创建签名
let message = "AshishAwasthi"
guard let messageData = message.data(using: String.Encoding.utf8) else {
print("无效的待签名消息。")
return nil
}
// 1. 创建签名
guard let signData = SecKeyCreateSignature(privateKey,
SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256,
messageData as CFData,
nil) else {
print("签名错误")
return nil
}
// 2. 获取签名数据
let signedData = signData as Data
let signedString = signedData.base64EncodedString(options: [])
print("签名字符串", signedString)
// 3. 验证签名
let messageToVerify = "AshishAwasthi"
guard let messageDataToVerify = messageToVerify.data(using: String.Encoding.utf8) else {
print("ECC 无效的待验证消息")
return false
}
guard let signatureData = signedData else {
print("无效的待验证消息。")
return false
}
let verify = SecKeyVerifySignature(publicKey,
SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256,
messageDataToVerify as CFData,
signatureData as CFData,
nil)
总结
在本教程中,您学到了:
- 对称加密与非对称加密及解密的区别。
- 如何在iOS应用中使用Swift安全API实现非对称加密。
- iOS安全元件/隔离区。
- 数字签名和验证。
- 如何通过安全隔离区对数据进行数字签名和验证。
结语
如果您觉得本文信息量大,请考虑分享并留下反馈,以便它能触达更广泛的读者 👏👏👏👏👏 !!!!FINISHED CSD0tFqvECLokhw9aBeRqun7QRQBiR11shbIyj7WeHfnF6U3xpa+0XjfU5DHXhvAyl5l+jExjFG4yiYEgxlUn78vQpdt/iTlM7OZ+q6Yb8t99Q5GsOMP/Y5LZ6+0EoZbl1FbJH3na1nVAFh5ucwQIyIF+TLXD5Sz9UGvbCO1uQo=