Parcourir la source

【内嵌支付】获取订单状态接口补充RSA解密

tangchao il y a 6 mois
Parent
commit
fa76b40ae9

+ 27 - 25
PDF Office/PDF Master/Class/Purchase/DMG/KMPurchaseEmbeddedWindowController.swift

@@ -40,28 +40,27 @@ class KMPurchaseEmbeddedWindowController: NSWindowController {
     }
     
     @objc func btnAction() {
-//        self.subscriptions()
         // 升级产品
         let productCode = "com.brother.pdfreaderpro.windows.product_1"
-//        let email = "tangchao@kdanmobile.com"
-//        self._buyProduct(productCode, count: 1, discountId: "", payment: .alipay, license: "", email: email, username: "") { [weak self] info, err in
+        let email = "tangchao@kdanmobile.com"
+        self._buyProduct(productCode, count: 1, discountId: "", payment: .alipay, license: "", email: email, username: "") { [weak self] info, err in
 //            // paypal_order
 //            // page_pay_url 链接
 //            // https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-3V503434MD108282U
 //            // trade_no 订单id 用于校验订单 【22024083006591098】
-//            if let dataInfo = info {
-//                let trade_no = info?["trade_no"]
-//                let page_pay_url = info?["page_pay_url"]
-//
-//                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
-//                    self?._getOrderStatus(tradeNo: trade_no as? String ?? "", callback: { info, err in
-//
-//                    })
-//                }
-//            } else {
-//                // 数据错误
-//            }
-//        }
+            if let dataInfo = info {
+                let trade_no = info?["trade_no"]
+                let page_pay_url = info?["page_pay_url"]
+
+                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                    self?._getOrderStatus(tradeNo: trade_no as? String ?? "", callback: { info, err in
+                        KMPrint("")
+                    })
+                }
+            } else {
+                // 数据错误
+            }
+        }
 //        let discountId = "E85B-9C31-6EAB"
 //        self._getDiscount(productId: productCode, discountId: discountId) { info, err in
 //            if let dataInfo = info {
@@ -74,14 +73,14 @@ class KMPurchaseEmbeddedWindowController: NSWindowController {
 //                }
 //            }
 //        }
-        self._getProductDatas { info, err in
+//        self._getProductDatas { info, err in
             /*
              activity_cny_price 优惠价(人民币)
              activity_price 优惠价(美元)
              price 原价(美元)
              cny_price 原价(人民币)
              */
-        }
+//        }
     }
     
     // 获取价格
@@ -151,17 +150,20 @@ class KMPurchaseEmbeddedWindowController: NSWindowController {
         request.httpBody = postData
 
         let task = URLSession.shared.dataTask(with: request) { data, response, error in
-           guard let data = data else {
-               callback(nil, String(describing: error))
-               return
-           }
+            guard let data = data else {
+                callback(nil, String(describing: error))
+                return
+            }
             if let jsonDict = try?JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary ?? [:] {
                 let dataStr = jsonDict["data"] as? String
                 
-                // ras 解密 目前没有调通
                 let rsa = KMVerificationRSA()
-                // XJYSy+T0k9VZbH1SJlaWj3FBKmrrDQCBk6PnAT0N4syzWNjdk3u89x3oXpZ8BZ37z9Dbv799QepQgQgGspBB/AXjtfYEICYpzs1RD2juTIglOqzakrJZOl+0s9M4R+pdbsigL+P39NnqWNXHkVZGDLrbL9ZNLuH2IztxHd/EUGmkwJUyx0ZIPCuBMD80EErlZt/iMGDa5zIww6dCrzpmT1o1qAXPkEri6WkDf/IG0JqytDsmXmEtCtOegc44Q9rpbsyBdp4YYqoeQ6/88/2TtFySd06dBIZkMZzNW8eN1MxmeWEDdo4Ji5uQz32aH/qPAi7XUXAg9Y3luBLyodt24A==
-                let str = rsa.decrypt(source: dataStr as? NSString ?? "")
+                if let deData = (rsa.decrypt(source: dataStr as? NSString ?? "") as? String)?.data(using: .utf8) {
+                    if let dict = try?JSONSerialization.jsonObject(with: deData, options: []) as? NSDictionary ?? [:] {
+                        return callback(dict as? [String : Any], nil)
+                    }
+                }
+                callback([:], String(describing: error))
             } else {
                 // 数据错误
                 callback([:], String(describing: error))

+ 380 - 0
PDF Office/PDF Master/Class/Purchase/DMG/Tools/KMRSAUtils.swift

@@ -0,0 +1,380 @@
+//
+//  KMRSAUtils.swift
+//  PDF Reader Pro
+//
+//  Created by User-Tangchao on 2024/9/2.
+//
+
+import Cocoa
+
+class KMRSAUtils: NSObject {
+    // Configuration keys
+    struct Config {
+        /// Determines whether to add key hash to the keychain path when searching for a key
+        /// or when adding a key to keychain
+        static var useKeyHashes = true
+    }
+    
+    // Base64 encode a block of data
+    static fileprivate func base64Encode(_ data: Data) -> String {
+        return data.base64EncodedString(options: [])
+    }
+    
+    // Base64 decode a base64-ed string
+    static fileprivate func base64Decode(_ strBase64: String) -> Data {
+        let data = Data(base64Encoded: strBase64, options: [])
+        return data!
+    }
+
+    // Encrypts data with a RSA key
+    static public func encryptWithRSAKey(_ data: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
+        let blockSize = SecKeyGetBlockSize(rsaKeyRef)
+        let maxChunkSize = blockSize - 11
+
+        var decryptedDataAsArray = [UInt8](repeating: 0, count: data.count / MemoryLayout<UInt8>.size)
+        (data as NSData).getBytes(&decryptedDataAsArray, length: data.count)
+
+        var encryptedData = [UInt8](repeating: 0, count: 0)
+        var idx = 0
+        while (idx < decryptedDataAsArray.count ) {
+            var idxEnd = idx + maxChunkSize
+            if ( idxEnd > decryptedDataAsArray.count ) {
+                idxEnd = decryptedDataAsArray.count
+            }
+            var chunkData = [UInt8](repeating: 0, count: maxChunkSize)
+            for i in idx..<idxEnd {
+                chunkData[i-idx] = decryptedDataAsArray[i]
+            }
+
+            var encryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
+            var encryptedDataLength = blockSize
+
+//            let status = SecKeyEncrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &encryptedDataBuffer, &encryptedDataLength)
+//            if ( status != noErr ) {
+//                NSLog("Error while ecrypting: %i", status)
+                return nil
+//            }
+            //let finalData = removePadding(encryptedDataBuffer)
+            encryptedData += encryptedDataBuffer
+
+            idx += maxChunkSize
+        }
+
+        return Data(bytes: UnsafePointer<UInt8>(encryptedData), count: encryptedData.count)
+    }
+
+    // Decrypt an encrypted data with a RSA key
+    static public func decryptWithRSAKey(_ encryptedData: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
+        let blockSize = SecKeyGetBlockSize(rsaKeyRef)
+
+        var encryptedDataAsArray = [UInt8](repeating: 0, count: encryptedData.count / MemoryLayout<UInt8>.size)
+        (encryptedData as NSData).getBytes(&encryptedDataAsArray, length: encryptedData.count)
+
+        var decryptedData = [UInt8](repeating: 0, count: 0)
+        var idx = 0
+        while (idx < encryptedDataAsArray.count ) {
+            var idxEnd = idx + blockSize
+            if ( idxEnd > encryptedDataAsArray.count ) {
+                idxEnd = encryptedDataAsArray.count
+            }
+            var chunkData = [UInt8](repeating: 0, count: blockSize)
+            for i in idx..<idxEnd {
+                chunkData[i-idx] = encryptedDataAsArray[i]
+            }
+
+            var decryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
+            var decryptedDataLength = blockSize
+
+//            let status = SecKeyDecrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &decryptedDataBuffer, &decryptedDataLength)
+//            if ( status != noErr ) {
+                return nil
+//            }
+            let finalData = removePadding(decryptedDataBuffer)
+            decryptedData += finalData
+
+            idx += blockSize
+        }
+
+        return Data(bytes: UnsafePointer<UInt8>(decryptedData), count: decryptedData.count)
+    }
+
+    static fileprivate func removePadding(_ data: [UInt8]) -> [UInt8] {
+        var idxFirstZero = -1
+        var idxNextZero = data.count
+        for i in 0..<data.count {
+            if ( data[i] == 0 ) {
+                if ( idxFirstZero < 0 ) {
+                    idxFirstZero = i
+                } else {
+                    idxNextZero = i
+                    break
+                }
+            }
+        }
+        var newData = [UInt8](repeating: 0, count: idxNextZero-idxFirstZero-1)
+        for i in idxFirstZero+1..<idxNextZero {
+            newData[i-idxFirstZero-1] = data[i]
+        }
+        return newData
+    }
+
+    // Verify that the supplied key is in fact a X509 public key and strip the header
+    // On disk, a X509 public key file starts with string "-----BEGIN PUBLIC KEY-----",
+    // and ends with string "-----END PUBLIC KEY-----"
+    static fileprivate func stripPublicKeyHeader(_ pubkey: Data) -> Data? {
+        if ( pubkey.count == 0 ) {
+            return nil
+        }
+        
+        var keyAsArray = [UInt8](repeating: 0, count: pubkey.count / MemoryLayout<UInt8>.size)
+        (pubkey as NSData).getBytes(&keyAsArray, length: pubkey.count)
+        
+        var idx = 0
+        if (keyAsArray[idx] != 0x30) {
+            return nil
+        }
+        idx += 1
+        
+        if (keyAsArray[idx] > 0x80) {
+            idx += Int(keyAsArray[idx]) - 0x80 + 1
+        } else {
+            idx += 1
+        }
+        
+        let seqiod = [UInt8](arrayLiteral: 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00)
+        for i in idx..<idx+15 {
+            if ( keyAsArray[i] != seqiod[i-idx] ) {
+                return nil
+            }
+        }
+        idx += 15
+        
+        if (keyAsArray[idx] != 0x03) {
+            return nil
+        }
+        idx += 1
+        
+        if (keyAsArray[idx] > 0x80) {
+            idx += Int(keyAsArray[idx]) - 0x80 + 1;
+        } else {
+            idx += 1
+        }
+        
+        if (keyAsArray[idx] != 0x00) {
+            return nil
+        }
+        idx += 1
+        //return pubkey.subdata(in: idx..<keyAsArray.count - idx)
+        //return pubkey.subdata(in: NSMakeRange(idx, keyAsArray.count - idx))
+        return pubkey.subdata(in: NSMakeRange(idx, keyAsArray.count - idx).toRange()!)
+    }
+
+    // Verify that the supplied key is in fact a PEM RSA private key key and strip the header
+    // On disk, a PEM RSA private key file starts with string "-----BEGIN RSA PRIVATE KEY-----",
+    // and ends with string "-----END RSA PRIVATE KEY-----"
+    static fileprivate func stripPrivateKeyHeader(_ privkey: Data) -> Data? {
+        if ( privkey.count == 0 ) {
+            return nil
+        }
+
+        var keyAsArray = [UInt8](repeating: 0, count: privkey.count / MemoryLayout<UInt8>.size)
+        (privkey as NSData).getBytes(&keyAsArray, length: privkey.count)
+
+        //magic byte at offset 22, check if it's actually ASN.1
+        var idx = 22
+        if ( keyAsArray[idx] != 0x04 ) {
+            return nil
+        }
+        idx += 1
+        
+        //now we need to find out how long the key is, so we can extract the correct hunk
+        //of bytes from the buffer.
+        var len = Int(keyAsArray[idx])
+        idx += 1
+        let det = len & 0x80 //check if the high bit set
+        if (det == 0) {
+            //no? then the length of the key is a number that fits in one byte, (< 128)
+            len = len & 0x7f
+        } else {
+            //otherwise, the length of the key is a number that doesn't fit in one byte (> 127)
+            var byteCount = Int(len & 0x7f)
+            if (byteCount + idx > privkey.count) {
+                return nil
+            }
+            //so we need to snip off byteCount bytes from the front, and reverse their order
+            var accum: UInt = 0
+            var idx2 = idx
+            idx += byteCount
+            while (byteCount > 0) {
+                //after each byte, we shove it over, accumulating the value into accum
+                accum = (accum << 8) + UInt(keyAsArray[idx2])
+                idx2 += 1
+                byteCount -= 1
+            }
+            // now we have read all the bytes of the key length, and converted them to a number,
+            // which is the number of bytes in the actual key.  we use this below to extract the
+            // key bytes and operate on them
+            len = Int(accum)
+        }
+
+        //return privkey.subdata(in: idx..<len)
+        //return privkey.subdata(in: NSMakeRange(idx, len))
+        return privkey.subdata(in: NSMakeRange(idx, len).toRange()!)
+    }
+
+    // Delete any existing RSA key from keychain
+    static public func deleteRSAKeyFromKeychain(_ tagName: String) {
+        let queryFilter: [String: AnyObject] = [
+            String(kSecClass)             : kSecClassKey,
+            String(kSecAttrKeyType)       : kSecAttrKeyTypeRSA,
+            String(kSecAttrApplicationTag): tagName as AnyObject
+        ]
+        SecItemDelete(queryFilter as CFDictionary)
+    }
+
+    // Get a SecKeyRef from keychain
+    static public func getRSAKeyFromKeychain(_ tagName: String) -> SecKey? {
+        let queryFilter: [String: AnyObject] = [
+            String(kSecClass)             : kSecClassKey,
+            String(kSecAttrKeyType)       : kSecAttrKeyTypeRSA,
+            String(kSecAttrApplicationTag): tagName as AnyObject,
+            //String(kSecAttrAccessible)    : kSecAttrAccessibleWhenUnlocked,
+            String(kSecReturnRef)         : true as AnyObject
+        ]
+
+        var keyPtr: AnyObject?
+        let result = SecItemCopyMatching(queryFilter as CFDictionary, &keyPtr)
+        if ( result != noErr || keyPtr == nil ) {
+            return nil
+        }
+        return keyPtr as! SecKey?
+    }
+
+    // Add a RSA private key to keychain and return its SecKeyRef
+    // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
+    static public func addRSAPrivateKey(_ privkeyBase64: String, tagName: String) -> SecKey? {
+        return addRSAPrivateKey(privkey: base64Decode(privkeyBase64), tagName: tagName)
+    }
+
+    static fileprivate func addRSAPrivateKey(privkey: Data, tagName: String) -> SecKey? {
+        // Delete any old lingering key with the same tag
+        deleteRSAKeyFromKeychain(tagName)
+
+        let privkeyData = stripPrivateKeyHeader(privkey)
+        if ( privkeyData == nil ) {
+            return nil
+        }
+
+        // Add persistent version of the key to system keychain
+        // var prt: AnyObject?
+        let queryFilter = [
+//            String(kSecClass)              : kSecClassKey,
+//            String(kSecAttrKeyType)        : kSecAttrKeyTypeRSA,
+//            String(kSecAttrApplicationTag) : tagName,
+            //String(kSecAttrAccessible)     : kSecAttrAccessibleWhenUnlocked,
+            String(kSecValueData)          : privkeyData!,
+            String(kSecAttrKeyClass)       : kSecAttrKeyClassPrivate,
+//            String(kSecReturnPersistentRef): true
+        ] as [String : Any]
+        let result = SecItemAdd(queryFilter as CFDictionary, nil)
+        if ((result != noErr) && (result != errSecDuplicateItem)) {
+            return nil
+        }
+
+        return getRSAKeyFromKeychain(tagName)
+    }
+
+    // Add a RSA pubic key to keychain and return its SecKeyRef
+    // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
+    static public func addRSAPublicKey(_ pubkeyBase64: String, tagName: String) -> SecKey? {
+        return addRSAPublicKey(pubkey: base64Decode(pubkeyBase64), tagName: tagName)
+    }
+    
+    static fileprivate func addRSAPublicKey(pubkey: Data, tagName: String) -> SecKey? {
+        // Delete any old lingering key with the same tag
+        deleteRSAKeyFromKeychain(tagName)
+
+        let pubkeyData = stripPublicKeyHeader(pubkey)
+        if ( pubkeyData == nil ) {
+            return nil
+        }
+        
+        // Add persistent version of the key to system keychain
+        //var prt1: Unmanaged<AnyObject>?
+        let queryFilter = [
+            String(kSecClass)              : kSecClassKey,
+            String(kSecAttrKeyType)        : kSecAttrKeyTypeRSA,
+            String(kSecAttrApplicationTag) : tagName,
+            String(kSecValueData)          : pubkeyData!,
+            String(kSecAttrKeyClass)       : kSecAttrKeyClassPublic,
+            String(kSecReturnPersistentRef): true
+        ] as [String : Any]
+        let result = SecItemAdd(queryFilter as CFDictionary, nil)
+        if ((result != noErr) && (result != errSecDuplicateItem)) {
+            return nil
+        }
+        
+        return getRSAKeyFromKeychain(tagName)
+    }
+
+    // Encrypt data with a RSA private key
+    // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
+    // NOT WORKING YET!
+    static public func encryptWithRSAPrivateKey(_ data: Data, privkeyBase64: String, keychainTag: String) -> Data? {
+        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privkeyBase64.hashValue) : "")
+        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
+        if ( keyRef == nil ) {
+            keyRef = addRSAPrivateKey(privkeyBase64, tagName: myKeychainTag)
+        }
+        if ( keyRef == nil ) {
+            return nil
+        }
+
+        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
+    }
+
+    // Encrypt data with a RSA public key
+    // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
+    static public func encryptWithRSAPublicKey(_ data: Data, pubkeyBase64: String, keychainTag: String) -> Data? {
+        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(pubkeyBase64.hashValue) : "")
+        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
+        if ( keyRef == nil ) {
+            keyRef = addRSAPublicKey(pubkeyBase64, tagName: myKeychainTag)
+        }
+        if ( keyRef == nil ) {
+            return nil
+        }
+
+        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
+    }
+
+    // Decrypt an encrypted data with a RSA private key
+    // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
+    static public func decryptWithRSAPrivateKey(_ encryptedData: Data, privkeyBase64: String, keychainTag: String) -> Data? {
+        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privkeyBase64.hashValue) : "")
+        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
+        if ( keyRef == nil ) {
+            keyRef = addRSAPrivateKey(privkeyBase64, tagName: myKeychainTag)
+        }
+        if ( keyRef == nil ) {
+            return nil
+        }
+
+        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: SecPadding())
+    }
+    
+    // Decrypt an encrypted data with a RSA public key
+    // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
+    static public func decryptWithRSAPublicKey(_ encryptedData: Data, pubkeyBase64: String, keychainTag: String) -> Data? {
+        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(pubkeyBase64.hashValue) : "")
+        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
+        if ( keyRef == nil ) {
+            keyRef = addRSAPublicKey(pubkeyBase64, tagName: myKeychainTag)
+        }
+        if ( keyRef == nil ) {
+            return nil
+        }
+
+        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: SecPadding())
+    }
+}

Fichier diff supprimé car celui-ci est trop grand
+ 67 - 63
PDF Office/PDF Master/Class/Purchase/DMG/Tools/KMVerificationRSA.swift


+ 8 - 0
PDF Office/PDF Reader Pro.xcodeproj/project.pbxproj

@@ -31,6 +31,9 @@
 		65D6840C2C6A3669003A532E /* KMEraserAnnotationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6840B2C6A3669003A532E /* KMEraserAnnotationController.swift */; };
 		65D6840D2C6A3669003A532E /* KMEraserAnnotationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6840B2C6A3669003A532E /* KMEraserAnnotationController.swift */; };
 		65D6840E2C6A3669003A532E /* KMEraserAnnotationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6840B2C6A3669003A532E /* KMEraserAnnotationController.swift */; };
+		65D88ED22C85826A00DD06E0 /* KMRSAUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D88ED12C85826A00DD06E0 /* KMRSAUtils.swift */; };
+		65D88ED32C85826A00DD06E0 /* KMRSAUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D88ED12C85826A00DD06E0 /* KMRSAUtils.swift */; };
+		65D88ED42C85826A00DD06E0 /* KMRSAUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D88ED12C85826A00DD06E0 /* KMRSAUtils.swift */; };
 		65EF3A7D2C81C1F500CCFC8F /* KMVerificationRSA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65EF3A7C2C81C1F500CCFC8F /* KMVerificationRSA.swift */; };
 		65EF3A7E2C81C1F500CCFC8F /* KMVerificationRSA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65EF3A7C2C81C1F500CCFC8F /* KMVerificationRSA.swift */; };
 		65EF3A7F2C81C1F500CCFC8F /* KMVerificationRSA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65EF3A7C2C81C1F500CCFC8F /* KMVerificationRSA.swift */; };
@@ -5528,6 +5531,7 @@
 		65341C7B2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSearchReplaceHanddler.swift; sourceTree = "<group>"; };
 		65D684052C6A250C003A532E /* KMWavyLineAnnotationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMWavyLineAnnotationController.swift; sourceTree = "<group>"; };
 		65D6840B2C6A3669003A532E /* KMEraserAnnotationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMEraserAnnotationController.swift; sourceTree = "<group>"; };
+		65D88ED12C85826A00DD06E0 /* KMRSAUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMRSAUtils.swift; sourceTree = "<group>"; };
 		65EF3A7C2C81C1F500CCFC8F /* KMVerificationRSA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KMVerificationRSA.swift; sourceTree = "<group>"; };
 		8931681F296D73CC0073EA59 /* KMSignatureAnnotationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMSignatureAnnotationViewController.h; sourceTree = "<group>"; };
 		89316820296D73CC0073EA59 /* KMSignatureAnnotationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMSignatureAnnotationViewController.m; sourceTree = "<group>"; };
@@ -7914,6 +7918,7 @@
 			isa = PBXGroup;
 			children = (
 				65EF3A7C2C81C1F500CCFC8F /* KMVerificationRSA.swift */,
+				65D88ED12C85826A00DD06E0 /* KMRSAUtils.swift */,
 			);
 			path = Tools;
 			sourceTree = "<group>";
@@ -16745,6 +16750,7 @@
 				BBBF68842A3C3AF10058E14E /* NSDocumentController+KMExtension.swift in Sources */,
 				ADA9102A2A272CE2003352F0 /* KMEditPDFTextManager.swift in Sources */,
 				BB24FFE62B2863EF00A59054 /* KMTTSManager.swift in Sources */,
+				65D88ED22C85826A00DD06E0 /* KMRSAUtils.swift in Sources */,
 				BB67EE202B54FFEF00573BF0 /* ASIDataDecompressor.m in Sources */,
 				65341C7C2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift in Sources */,
 				BB897229294B08720045787C /* KMWatermarkAdjectiveTopBarItemModel.swift in Sources */,
@@ -17722,6 +17728,7 @@
 				9F3D819429A33A290087B5AD /* KMDesignDropdown.swift in Sources */,
 				9F0CB4802967F64D00007028 /* KMPropertiesPanelReadOnlySubVC.swift in Sources */,
 				BB8810862B4F7C2200AFA63E /* KMVerificationAlertViewController.m in Sources */,
+				65D88ED32C85826A00DD06E0 /* KMRSAUtils.swift in Sources */,
 				BB2EDF77296ECE17003BCF58 /* KMPageEditInsertPageSizeItemView.swift in Sources */,
 				9F1F82DB292F84D60092C4B4 /* KMHomeInsertActionViewController.swift in Sources */,
 				BB35732E2AF50066004CDA92 /* KMBatchOperateConvertViewController.swift in Sources */,
@@ -19237,6 +19244,7 @@
 				BBBE208D2B21649100509C4E /* KMPDFEditWindowController.swift in Sources */,
 				BBA8B7B1293600D70097D183 /* KMPasswordInputWindow.swift in Sources */,
 				BB14701F299DC0D100784A6A /* OIDIDToken.m in Sources */,
+				65D88ED42C85826A00DD06E0 /* KMRSAUtils.swift in Sources */,
 				89D2D30A295A83B500BFF5FE /* KMEditPDFTextPropertyViewController.swift in Sources */,
 				BB03D69A2B0221FF008C9976 /* NSImage+KMExtension.swift in Sources */,
 				ADBC2CFC299CA6B9006280C8 /* KMPrintDuplexPrintingSetView.swift in Sources */,