美文网首页iOS Developer
Swift保存RSA密钥到Keychain

Swift保存RSA密钥到Keychain

作者: 小天枢丶 | 来源:发表于2017-08-31 12:25 被阅读0次

    最近项目的需求用到RSA的加密解密,并且需要把公钥信息保存到Keychain里面,网上很多文章都是用Keychain保存账号密码什么的,自己在实现保存的公钥过程中也踩了不少坑。现在来整理一下实现的方法。

    首先肯定是先要导入 Security

    import Security
    

    然后定义一个常量 Identifier

    // 密钥唯一标示
    fileprivate let publicKeyIdentifier = "com.hhh.publicKey"
    fileprivate let privateKeyIdentifier = "com.hhh.privateKey"
    fileprivate let publicKeyTag = publicKeyIdentifier.data(using: .utf8)!
    fileprivate let privateKeyTag = privateKeyIdentifier.data(using: .utf8)!
    

    实现一个把SecKey转换成Data的方法

    private static func getKeyDataFrom(secKey: SecKey, tag: Data) -> Data {
            var data: Data?
            
            var query = [String: Any]()
            query[kSecClass as String] = kSecClassKey
            query[kSecAttrApplicationTag as String] = tag
            query[kSecAttrKeyType as String] = kSecAttrKeyTypeRSA
            
            var attributes = query
            attributes[kSecValueRef as String] = secKey
            attributes[kSecReturnData as String] = true
            var result: CFTypeRef?
            let status = SecItemAdd(attributes as CFDictionary, &result)
            
            if status == errSecSuccess {
                data = result as? Data
                SecItemDelete(query as CFDictionary)
            }
            return data!
        }
    

    这个方法的原理其实就是先把SecKey存到Keychain里面然后再读取出Data类型的数据

    接下来就是实现存到Keychain的方法

    // keySize 就是RSA密钥的长度
    // isPrivate 判断存储的是否为私钥(true为私钥、false为公钥)
    static func saveRSAKeyToKeychain(key: SecKey, keySize: size_t, isPrivate: Bool) {
            var saveDictionary = [String: Any]()
            let keyClass = isPrivate ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic
            // 设置keychain字典
            saveDictionary[kSecClass as String] = kSecClassKey
            saveDictionary[kSecAttrKeyType as String] = kSecAttrKeyTypeRSA
            saveDictionary[kSecAttrApplicationTag as String] = isPrivate ? privateKeyTag : publicKeyTag
            saveDictionary[kSecAttrKeyClass as String] = keyClass
            saveDictionary[kSecValueData as String] = getKeyDataFrom(secKey: key, tag: isPrivate ? privateKeyTag : publicKeyTag)
            saveDictionary[kSecAttrKeySizeInBits as String] = keySize
            saveDictionary[kSecAttrEffectiveKeySize as String] = keySize
            saveDictionary[kSecAttrCanDerive as String] = kCFBooleanFalse
            saveDictionary[kSecAttrCanEncrypt as String] = kCFBooleanTrue
            saveDictionary[kSecAttrCanDecrypt as String] = kCFBooleanTrue
            saveDictionary[kSecAttrCanVerify as String] = kCFBooleanTrue
            saveDictionary[kSecAttrCanSign as String] = kCFBooleanFalse
            saveDictionary[kSecAttrCanWrap as String] = kCFBooleanTrue
            saveDictionary[kSecAttrCanUnwrap as String] = kCFBooleanFalse
            saveDictionary[kSecAttrApplicationLabel as String] = isPrivate ? privateKeyIdentifier : publicKeyIdentifier
            // 删除旧数据
            SecItemDelete(saveDictionary as CFDictionary)
            let status = SecItemAdd(saveDictionary as CFDictionary, nil)
            assert(status == errSecSuccess, "keychain存储密钥失败")
        }
    

    最后就是实现从Keychain取出密钥信息的方法

    // isPrivate 判断存储的是否为私钥(true为私钥、false为公钥)
    static func getRSAKeyFromKeychain(isPrivate: Bool) -> SecKey! {
            var queryDictionary = [String: Any]()
            let keyClass = isPrivate ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic
            
            queryDictionary[kSecClass as String] = kSecClassKey
            queryDictionary[kSecAttrKeyType as String] = kSecAttrKeyTypeRSA
            queryDictionary[kSecAttrApplicationTag as String] = isPrivate ? privateKeyTag : publicKeyTag
            queryDictionary[kSecAttrKeyClass as String] = keyClass
            queryDictionary[kSecReturnRef as String] = kCFBooleanTrue
            queryDictionary[kSecAttrApplicationLabel as String] =  isPrivate ? privateKeyIdentifier : publicKeyIdentifier
            
            var key: CFTypeRef?
            let status = SecItemCopyMatching(queryDictionary as CFDictionary, &key)
            
            if status == errSecSuccess {
                // 强转SecKey类型
                return key as! SecKey
            }
            assert(false, "keychain读取密钥失败")
        }
    

    因为在开头我们已经定义了公钥私钥的 Identifier 所有我们只需要判断存/取的是私钥还是公钥就可以将密钥信息进行读写操作。

    相关文章

      网友评论

        本文标题:Swift保存RSA密钥到Keychain

        本文链接:https://www.haomeiwen.com/subject/hyhqjxtx.html