123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- //
- // KMVerificationRSA.swift
- // PDF Reader Pro
- //
- // Created by Niehaoyu on 2024/8/9.
- //
- import Cocoa
- import CryptoKit
- import Security
- import CommonCrypto
- import Foundation
- @objc class KMVerificationRSA: NSObject {
- @objc func active(uniquesn: String, cdkey: String, model: String, os: String, language: String, appversion: String) -> String? {
- let dictionary: [String: Any] = ["subscription": ["app_code":"com.imyfone.pdf",
- "cdkey":cdkey],
- "device": ["unique_sn":uniquesn,
- "os":os,
- "platform":"DMG",
- "time_zone":"UTC",
- "language":language,
- "app_version":appversion]]
- if let jsonData = try? JSONSerialization.data(withJSONObject: dictionary, options:[]),
- let jsonString = String(data: jsonData, encoding: .utf8) {
- print(jsonString)
- if let publicKey = loadPublicKey() {
- let encryptedData = encrypt(plainText: jsonString, publicKey: publicKey)
- print("Encrypted data: \(encryptedData?.base64EncodedString() ?? "nil")")
- let encryptedString = encryptedData?.base64EncodedString();
- return encryptedString
-
- //Test
- // let dataToEncrypt = jsonString.data(using: .utf8)!
- //
- // if let encryptedDataChunks = encryptDataInChunks(data: dataToEncrypt, publicKey: publicKey) {
- // print("Encrypted data chunks:")
- // for chunk in encryptedDataChunks {
- // print(chunk.base64EncodedString()) // 输出每个加密块
- // }
- // print("111")
- // }
- //
- //
- // let message = jsonString
- // if let messageData = message.data(using: .utf8) {
- // if let publicKey = loadPublicKey() {
- // if let encryptedChunks = encrypt(data: messageData, publicKey: publicKey) {
- // let encryptedString = encryptedChunks.map { $0.base64EncodedString() }
- // print("Encrypted data: \(encryptedString)")
- // return encryptedString.first
- // }
- // }
- // }
- }
- }
- return nil
- }
-
- @objc func verify(uniquesn: String, model: String, os: String, language: String, appversion: String) -> String? {
- let dictionary: [String: Any] = ["subscription": ["app_code":"com.imyfone.pdf"],
- "device": ["unique_sn":uniquesn,
- "os":os,
- "platform":"DMG",
- "time_zone":"UTC",
- "language":language,
- "app_version":appversion]]
- if let jsonData = try? JSONSerialization.data(withJSONObject: dictionary, options:[]),
- let jsonString = String(data: jsonData, encoding: .utf8) {
- print(jsonString)
- if let publicKey = loadPublicKey() {
- let encryptedData = encrypt(plainText: jsonString, publicKey: publicKey)
- print("Encrypted data: \(encryptedData?.base64EncodedString() ?? "nil")")
- let encryptedString = encryptedData?.base64EncodedString();
- return encryptedString
- }
-
- //Test
- let message = jsonString
- if let messageData = message.data(using: .utf8) {
- if let publicKey = loadPublicKey() {
- if let encryptedChunks = encrypt(data: messageData, publicKey: publicKey) {
- let encryptedString = encryptedChunks.map { $0.base64EncodedString() }
- print("Encrypted data: \(encryptedString)")
- return encryptedString.first
- }
- }
- }
-
- }
-
-
- return nil
- }
-
- func encrypt(plainText: String, publicKey: SecKey) -> Data? {
- guard let data = plainText.data(using: .utf8) else {
- return nil
- }
-
- var error: Unmanaged<CFError>?
- let encryptedData = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, data as CFData, &error)
-
- if let error = error?.takeRetainedValue() {
- print("Error encrypting data: \(error)")
- return nil
- }
-
- return encryptedData as Data?
- }
-
- func encrypt(data: Data, publicKey: SecKey) -> [Data]? {
- let maxChunkSize = 214 // 对于 RSA-2048,214 是最大加密长度
- var chunks = [Data]()
- var offset = 0
- while offset < data.count {
- let chunkSize = min(maxChunkSize, data.count - offset)
- let chunk = data.subdata(in: offset..<offset + chunkSize)
- if let encryptedData = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, chunk as CFData, nil) {
- chunks.append(encryptedData as Data)
- } else {
- return nil // 加密失败
- }
- offset += chunkSize
- }
-
- return chunks
- }
-
-
- func loadPublicKey() -> SecKey? {
- // let publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqYKtu5pbT3bhbOfZ7XFhw1IEiqGvx/z3YwvcrLvG6I+EBbim/YuDfSTqpcTZSjbMeLz8nCzkAsMakoimzI6XpNQOZN35cDCFkjn0vicpnfla2JPMxREwddblAz7u/EMdx71ElcY+UYfSu1QM0Lepc2QPWw9oaD/cNktH6xE6eogLEH0k8ZYP8YIzTW02og7mNtLVO1ssKQYUCIQ5LkKA7zypQul5upajE51rq49vdCoA98y2zBRTMXGM7tpa2rbXQ9fDMn5heCLVCXCHNXDwBMxNhURm7fEfxZPwq7DUmH8EWKXCKKhu+GP0c/eom50FzMxfN2wpQSgNfyNQ7bBgwIDAQAB"
-
- let publicKeyString = Self.RsaPublic
-
- guard let data = Data(base64Encoded: publicKeyString) else {
- return nil
- }
-
- let options: [String: Any] = [
- kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
- kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
- kSecAttrKeySizeInBits as String: 4096
- ]
-
- var error: Unmanaged<CFError>?
- let publicKey = SecKeyCreateWithData(data as CFData, options as CFDictionary, &error)
-
- if let error = error?.takeRetainedValue() {
- print("Error loading public key: \(error)")
- return nil
- }
-
- return publicKey
- }
-
- func base64Encode(string: String) -> String? {
- // 将字符串转换为 Data
- guard let data = string.data(using: .utf8) else {
- print("Error converting string to Data.")
- return nil
- }
-
- // 使用 Data 的 base64EncodedString() 方法进行编码
- let base64String = data.base64EncodedString()
- return base64String
- }
-
- // RSA 分块加密
- func encryptDataInChunks(data: Data, publicKey: SecKey) -> [Data]? {
- let blockSize = SecKeyGetBlockSize(publicKey) - 11 // PKCS#1 v1.5 填充需要额外字节
- var encryptedChunks: [Data] = []
-
- var offset = 0
- while offset < data.count {
- let size = min(data.count - offset, blockSize) // 计算当前块大小
- let chunk = data.subdata(in: offset..<offset+size)
-
- var error: Unmanaged<CFError>?
- let encryptedData = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, data as CFData, &error)
-
- guard let successData = encryptedData else {
- if let error = error?.takeRetainedValue() {
- print("Encryption failed: \(error)")
- }
- return nil
- }
-
- encryptedChunks.append(successData as Data)
- offset += size
- }
-
- return encryptedChunks
- }
-
- func encrypt22(data: Data, publicKey: SecKey) -> [Data]? {
- let keySizeInBytes = 256 // 对于 RSA-2048,密钥大小为 256 字节
- let paddingSize = 11 // PKCS#1 填充大小
- let maxChunkSize = keySizeInBytes - paddingSize // 最大可加密数据大小
- var chunks = [Data]()
- var offset = 0
- while offset < data.count {
- let chunkSize = min(maxChunkSize, data.count - offset)
- let chunk = data.subdata(in: offset..<offset + chunkSize)
-
- var error: Unmanaged<CFError>?
- guard let encryptedData = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, chunk as CFData, &error) else {
- print("Encryption error: \(error!.takeRetainedValue() as Error)")
- return nil
- }
- chunks.append(encryptedData as Data)
- offset += chunkSize
- }
-
- return chunks
- }
-
- //https://www.bejson.com/enc/rsa/网站生成的密钥要保留\r\n,去除前缀后缀
- //pem格式公钥 用途加密
- // public static let RsaPublic = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh3U54ETmA3anGcL3D4uAa5vNI0S6rVoM\r\nCe9MhhP3MLRSW1gMaEHJE+vsVLN8ChFytkiI60CInYC91bk2x2FaurIIGEwowGz4lifDNsQFeWEd\r\nxs33U3fGM3+wGXC7sfYJrtmriqqmmM9eTqxvVWARD1EvnSUWseBRquCuSJ3rkQHxm0E9n88SAaM4\r\nopogLrAyz82NlWQSE55Yf0wiNNNh+HdiQOpTBIes5blBcxbai9KVQU5dqlkKNceg7rdDxANFlm49\r\nTn4yNkrS80w75IQL1xLzYfvWSlWn/falJR4jNBfBg7aTyJduGvWytTgphYVTPheJN/fEDRMR0XTV\r\nlnkHZQIDAQAB";
- public static let RsaPublic = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh3U54ETmA3anGcL3D4uAa5vNI0S6rVoMCe9MhhP3MLRSW1gMaEHJE+vsVLN8ChFytkiI60CInYC91bk2x2FaurIIGEwowGz4lifDNsQFeWEdxs33U3fGM3+wGXC7sfYJrtmriqqmmM9eTqxvVWARD1EvnSUWseBRquCuSJ3rkQHxm0E9n88SAaM4opogLrAyz82NlWQSE55Yf0wiNNNh+HdiQOpTBIes5blBcxbai9KVQU5dqlkKNceg7rdDxANFlm49Tn4yNkrS80w75IQL1xLzYfvWSlWn/falJR4jNBfBg7aTyJduGvWytTgphYVTPheJN/fEDRMR0XTVlnkHZQIDAQAB";
- //pem格式私钥 用途解密
- // public static let RsaPrivate = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCHdTngROYDdqcZwvcPi4Brm80j\r\nRLqtWgwJ70yGE/cwtFJbWAxoQckT6+xUs3wKEXK2SIjrQIidgL3VuTbHYVq6sggYTCjAbPiWJ8M2\r\nxAV5YR3GzfdTd8Yzf7AZcLux9gmu2auKqqaYz15OrG9VYBEPUS+dJRax4FGq4K5IneuRAfGbQT2f\r\nzxIBoziimiAusDLPzY2VZBITnlh/TCI002H4d2JA6lMEh6zluUFzFtqL0pVBTl2qWQo1x6Dut0PE\r\nA0WWbj1OfjI2StLzTDvkhAvXEvNh+9ZKVaf99qUlHiM0F8GDtpPIl24a9bK1OCmFhVM+F4k398QN\r\nExHRdNWWeQdlAgMBAAECggEAA7uZQrLjW8kTRcR3pngDq/N5LbWhJ1HJ7yQnCbLXJwJxGo9MmDrn\r\n3aKsupDPpD9i198b1s/Kc/yuPouCFPB73ZU2X+UJYnQeTZT+7i1ssTGZ7naSkDxGu/iS08Cli3vq\r\nPGVHMuUM/j0IrkZWMxYYokFsfHofK/uwhHL4mouviClpCUoSy/OId0epVo81auFZLuAEK3/n9nG0\r\n9zRstRqOIxe4iRFEN45uj4+FZFBR5nDSRqztbVvdPJJip58IyN6ZRPbFJI9RUwzBl/WWvBJ6sXg1\r\n3SJAkvnJoO4q1ECbUL1kFELIEjWhsqM7QdGAaAYfUSYklVq6agwI9LL2Jk00wQKBgQDoPTW5hwqf\r\nlyA56hjZuHSgjOd3Tw8F3FrDanREc1GhZKrzVFmjC8s6o+dmKoRPnzjAJXtLtcJwEItJkkebZYA+\r\nWuY+y4c+oS+fp69UtgneqLn6knJHqZHhVG4wVzSUuLU0vnAeywHQZ7wE41V6coGwp0kb07N8kAWQ\r\nxTI64IafOQKBgQCVUSFVUNqAMToMTCF0qN7bp/AlFdfRMsZb+ANBDCv1pEL9IQpo+umBkTAgexOB\r\nLWuFO7B3+YIbE23HoDyR/IIodsbqemT3N0GqQ4HfSqe2Hlfuspqbx0T3UocSp2+2jEt4aHLrWlS1\r\nMUA24oEg0ybh6aotZF1CjyIOsY1T8Lj9jQKBgQDP/loKgjZyfgA/vjhpbfkN/YQkZ6r1vceQMtxU\r\nnc9jM2yjp0zsaNin+Tl6V+POB7Tk6ezF/tBYW4jT6G23cC1uKy0A2nmTDvs/CwhNXwfx4b1G/Dfb\r\nlLPxUhOpucB+3fp0dYanHXvPcciDvDLHCpy6YOhqQq0Ch15krSfycTpAiQKBgGmrnNdv/PIz5EzH\r\no/WXfQAefYkBSFa4hECZ6FOkdYfF09KoC2H4EECtq02RTGBi8HC9qUl+vmDDAzH/aF44QTS5ulQ+\r\ngi2iYUpJtCN+BeqQ1tIKe/g6scgGE6lT7W9XIiH4aTu+FayVSkiNS60bQa0nXFP7bzSnbwbPCKGa\r\n/pARAoGBAMbpl+vPULiJ4IrGbNQgA1hKNKhSerwBBKRsiM4MlcDVkjlpLd+bQ9POQy2y0r7GZQjW\r\nmt0XF3tb3Fp20U/ETUxKI4BktTX2A9hrmj5R3Uq+40KocQonjmIMEHF9GxnWF1YfzKtUD2DrDVp/\r\n1YMHv7Is7IVCtyIbLXVuMVXvGeab";
- public static let RsaPrivate = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCHdTngROYDdqcZwvcPi4Brm80jRLqtWgwJ70yGE/cwtFJbWAxoQckT6+xUs3wKEXK2SIjrQIidgL3VuTbHYVq6sggYTCjAbPiWJ8M2xAV5YR3GzfdTd8Yzf7AZcLux9gmu2auKqqaYz15OrG9VYBEPUS+dJRax4FGq4K5IneuRAfGbQT2fzxIBoziimiAusDLPzY2VZBITnlh/TCI002H4d2JA6lMEh6zluUFzFtqL0pVBTl2qWQo1x6Dut0PEA0WWbj1OfjI2StLzTDvkhAvXEvNh+9ZKVaf99qUlHiM0F8GDtpPIl24a9bK1OCmFhVM+F4k398QNExHRdNWWeQdlAgMBAAECggEAA7uZQrLjW8kTRcR3pngDq/N5LbWhJ1HJ7yQnCbLXJwJxGo9MmDrn3aKsupDPpD9i198b1s/Kc/yuPouCFPB73ZU2X+UJYnQeTZT+7i1ssTGZ7naSkDxGu/iS08Cli3vqPGVHMuUM/j0IrkZWMxYYokFsfHofK/uwhHL4mouviClpCUoSy/OId0epVo81auFZLuAEK3/n9nG09zRstRqOIxe4iRFEN45uj4+FZFBR5nDSRqztbVvdPJJip58IyN6ZRPbFJI9RUwzBl/WWvBJ6sXg13SJAkvnJoO4q1ECbUL1kFELIEjWhsqM7QdGAaAYfUSYklVq6agwI9LL2Jk00wQKBgQDoPTW5hwqflyA56hjZuHSgjOd3Tw8F3FrDanREc1GhZKrzVFmjC8s6o+dmKoRPnzjAJXtLtcJwEItJkkebZYA+WuY+y4c+oS+fp69UtgneqLn6knJHqZHhVG4wVzSUuLU0vnAeywHQZ7wE41V6coGwp0kb07N8kAWQxTI64IafOQKBgQCVUSFVUNqAMToMTCF0qN7bp/AlFdfRMsZb+ANBDCv1pEL9IQpo+umBkTAgexOBLWuFO7B3+YIbE23HoDyR/IIodsbqemT3N0GqQ4HfSqe2Hlfuspqbx0T3UocSp2+2jEt4aHLrWlS1MUA24oEg0ybh6aotZF1CjyIOsY1T8Lj9jQKBgQDP/loKgjZyfgA/vjhpbfkN/YQkZ6r1vceQMtxUnc9jM2yjp0zsaNin+Tl6V+POB7Tk6ezF/tBYW4jT6G23cC1uKy0A2nmTDvs/CwhNXwfx4b1G/DfblLPxUhOpucB+3fp0dYanHXvPcciDvDLHCpy6YOhqQq0Ch15krSfycTpAiQKBgGmrnNdv/PIz5EzHo/WXfQAefYkBSFa4hECZ6FOkdYfF09KoC2H4EECtq02RTGBi8HC9qUl+vmDDAzH/aF44QTS5ulQ+gi2iYUpJtCN+BeqQ1tIKe/g6scgGE6lT7W9XIiH4aTu+FayVSkiNS60bQa0nXFP7bzSnbwbPCKGa/pARAoGBAMbpl+vPULiJ4IrGbNQgA1hKNKhSerwBBKRsiM4MlcDVkjlpLd+bQ9POQy2y0r7GZQjWmt0XF3tb3Fp20U/ETUxKI4BktTX2A9hrmj5R3Uq+40KocQonjmIMEHF9GxnWF1YfzKtUD2DrDVp/1YMHv7Is7IVCtyIbLXVuMVXvGeab";
-
-
- func getPrivateKeyFromString(key: String) -> SecKey? {
- // guard let data = key.data(using: .utf8) else { return nil }
- guard let data = Data(base64Encoded: key) else {
- return nil
- }
-
- let parameters: [CFString: Any] = [
- kSecAttrKeyType: kSecAttrKeyTypeRSA,
- kSecAttrKeyClass: kSecAttrKeyClassPrivate,
- kSecAttrKeySizeInBits: 2048,
- kSecReturnPersistentRef: true
- ]
-
- var error: Unmanaged<CFError>?
- guard let privkeyData = Self.stripPrivateKeyHeader(data) else {
- return nil
- }
-
- if let privateKey = SecKeyCreateWithData(privkeyData as CFData, parameters as CFDictionary, &error) {
- return privateKey
- } else {
- print("Error creating private key: \(error!.takeRetainedValue())")
- return nil
- }
- }
-
- @objc public func decrypt(source: NSString) -> NSString? {
- guard let data = Data(base64Encoded: source as String), data.isEmpty == false else {
- KMPrint("需要解密的数据为空.")
- return nil
- }
- guard let key = self.getPrivateKeyFromString(key: Self.RsaPrivate) else {
- KMPrint("私钥生成失败.")
- return nil
- }
-
- // let data: Data = (NSData(base64Encoded: (source as String), options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)! as Data)
- // let data = Data(base64Encoded: source as String)
- if let deData = SecKeyCreateDecryptedData(key, .rsaEncryptionPKCS1, data as CFData, nil) {
- return String(data: deData as Data, encoding: .utf8) as NSString?
- }
- return nil
- }
-
- // 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()!)
- }
- }
|