iOS安全API实战指南:数据加密解密与数字签名技术详解

5 阅读5分钟

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("Not supported encryption algorithm")
            return nil
        }
        var errorRef: Unmanaged<CFError>?
        guard let encryptedData = SecKeyCreateEncryptedData(publicKey, algorithm, value as CFData, &errorRef) else {
            let error = errorRef?.takeRetainedValue()
            debugPrint("error encrypting:\(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("Not supported decription algorithm")
            return nil
        }
        var errorRef: Unmanaged<CFError>?
        guard let decryptedData = SecKeyCreateDecryptedData(privateKey, algorithm, encrypted as CFData, &errorRef) as Data? else {
            let error = errorRef?.takeRetainedValue()
            debugPrint("error decrypting:\(String(describing: error))")
            return nil
        }
        return decryptedData
    }
    
    internal func signThe(data: Data, privateKey: SecKey, algorithm: SecKeyAlgorithm) -> Data? {
        guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else {
            debugPrint("Not supported decription algorithm")
            return nil
        }
        var errorRef: Unmanaged<CFError>?
        guard let signature = SecKeyCreateSignature(privateKey, algorithm, data as CFData, &errorRef) as Data? else {
            let error = errorRef?.takeRetainedValue()
            debugPrint("error signing:\(String(describing: error))")
            debugPrint("Not supported decription algorithm")
            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("Not supported encryption algorithm")
            return false
        }
        guard data.isNotEmpty else {
            debugPrint("Can not verify signature with empty signed data")
            return false
        }
        var errorRef: Unmanaged<CFError>?
        guard SecKeyVerifySignature(publicKey, algorithm, data as CFData, signature as CFData, &errorRef) else {
            debugPrint("error verifying:\(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
] as CFDictionary                                         // 12

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("待签名的消息无效。")
}

// 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 message = "AshishAwasthi"
guard let messageData = message.data(using: String.Encoding.utf8) else {
    print("ECC验证消息错误")
    return false
}

guard let signatureData = signedData else {
    print("待验证的消息无效。")
}

let verify = SecKeyVerifySignature(publicKey, 
                                  SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256, 
                                  messageData as CFData, 
                                  signatureData as CFData, 
                                  nil)

总结

在本教程中,你已经学到:

  • 对称加密与非对称加密及解密的区别
  • 如何在iOS应用中使用Swift安全API应用非对称加密
  • iOS安全元件/安全隔区
  • 数字签名与验证
  • 如何通过安全隔区对数据进行数字签名和验证

结语

如果你觉得这篇文章信息丰富,请考虑分享它并提供反馈,以便它可以触及更广泛的受众 👏👏👏👏👏 !!!!FINISHED CSD0tFqvECLokhw9aBeRqun7QRQBiR11shbIyj7WeHfnF6U3xpa+0XjfU5DHXhvAyl5l+jExjFG4yiYEgxlUn78vQpdt/iTlM7OZ+q6Yb8t99Q5GsOMP/Y5LZ6+0EoZbl1FbJH3na1nVAFh5ucwQIyIF+TLXD5Sz9UGvbCO1uQo=