Swift RSA加密封装

作者: 屈涯 | 来源:发表于2019-06-17 15:59 被阅读0次
    import Foundation
    import Security
    
    enum RSAKeySize: Int {
        case size512 = 512
        case size768 = 768
        case size1024 = 1024
        case size2048 = 2048
    }
    
    private let publicKeyIdentifier = "baseModule.publicKey"
    private let privateKeyIdentifier = "baseModule.privateKey"
    private let publicKeyTag = publicKeyIdentifier.data(using: .utf8)!
    private let privateKeyTag = privateKeyIdentifier.data(using: .utf8)!
    
    class RSAUtils {
    
        static let shared = RSAUtils()
    
        var publicSecKey: SecKey?
        var privateSecKey: SecKey?
    
        private let keySizeType: RSAKeySize = .size1024
        
        // RSA秘鍵を生成する
        // sizes for RSA keys are: 512, 768, 1024, 2048.
        func generateRSAKeyPair() {
            let keySize = keySizeType.rawValue
            publicSecKey = getRSAKeyFromKeychain(isPrivate: false, keySize: keySize)
            privateSecKey = getRSAKeyFromKeychain(isPrivate: true, keySize: keySize)
            if publicSecKey != nil {
                return
            }
            publicSecKey = nil
            privateSecKey = nil
            let parameters = [kSecAttrKeyType: kSecAttrKeyTypeRSA,
                              kSecAttrKeySizeInBits: keySize] as [CFString : Any]
            let ret = SecKeyGeneratePair(parameters as CFDictionary, &publicSecKey, &privateSecKey)
            assert(ret == errSecSuccess, "Error For SecKeyGeneratePair: \(ret)")
    
            saveRSAKeyToKeychain(key: publicSecKey!, keySize: keySize, isPrivate: false)
            saveRSAKeyToKeychain(key: privateSecKey!, keySize: keySize, isPrivate: true)
        }
    
        @objc public func encrypt(source: String) -> String {
    
            guard !source.isEmpty && self.publicSecKey != nil else {
                return ""
            }
            let data: NSData = (source.data(using: String.Encoding.utf8)! as NSData)
            var error: Unmanaged<CFError>?
            let resData =  SecKeyCreateEncryptedData(self.publicSecKey!, SecKeyAlgorithm.rsaEncryptionPKCS1, data as CFData, &error) as Data?
            if error != nil {
                DDLogError("res = \(String(describing: error?.takeUnretainedValue().localizedDescription))")
                return ""
            }
            return resData!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: NSData.Base64EncodingOptions.lineLength64Characters.rawValue))
        }
    
        @objc public func decrypt(source: String) -> String {
    
            guard !source.isEmpty && self.privateSecKey != nil else {
                return ""
            }
            //base64 decode
            guard let data: Data = NSData(base64Encoded: (source as String), options: NSData.Base64DecodingOptions.ignoreUnknownCharacters) as Data? else {
                return ""
            }
    
            var error: Unmanaged<CFError>?
            let resData =  SecKeyCreateDecryptedData(self.privateSecKey!, SecKeyAlgorithm.rsaEncryptionPKCS1, data as CFData, &error) as Data?
            if error != nil {
                DDLogError("res = \(String(describing: error?.takeUnretainedValue().localizedDescription))")
                return ""
            }
            return String(data: resData!, encoding: String.Encoding.utf8)!
        }
    
        private 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!
        }
    
        // keySize RSAキーの長さです
        // isPrivate 保管されている秘密鍵かどうかを判別します(trueは秘密鍵、falseは公開鍵)
        private 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] = SecKeyGetBlockSize(key)
            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, "SaveRSAKeyToKeychain Failure")
        }
    
        // isPrivate 保管されている秘密鍵かどうかを判別します(trueは秘密鍵、falseは公開鍵)
        // swiftlint:disable force_cast
        private func getRSAKeyFromKeychain(isPrivate: Bool, keySize: size_t) -> 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
            queryDictionary[kSecAttrKeySizeInBits as String] = keySize
    
            var key: CFTypeRef?
            let status = SecItemCopyMatching(queryDictionary as CFDictionary, &key)
    
            if status == errSecSuccess {
                let result = key as! SecKey
                return result
            }
            return nil
        }
        // swiftlint:enable force_cast
    }
    

    相关文章

      网友评论

        本文标题:Swift RSA加密封装

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