Sfoglia il codice sorgente

patch File encryption

alqindiirsyam 8 mesi fa
parent
commit
10abd08cd4

+ 147 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/FileEncryption.swift

@@ -0,0 +1,147 @@
+//
+//  FileEncryption.swift
+//  NexilisLite
+//
+//  Created by Maronakins on 03/12/24.
+//
+
+import Foundation
+import CryptoKit
+import CommonCrypto
+
+public class FileEncryption {
+    
+    static let shared = FileEncryption()
+
+    private init() {}
+    
+    func generateIV() -> Data {
+        var iv = Data(count: kCCBlockSizeAES128)
+        let result = iv.withUnsafeMutableBytes {
+            SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, $0.baseAddress!)
+        }
+        precondition(result == errSecSuccess, "Failed to generate IV")
+        return iv
+    }
+    
+    func readDataFromFile(fileURL: URL) -> Data? {
+        do {
+            return try Data(contentsOf: fileURL)
+        } catch {
+            print("Failed to read file: \(error)")
+            return nil
+        }
+    }
+    
+    func wipeData(_ data: inout Data) {
+        data.resetBytes(in: 0..<data.count)
+        data.count = 0
+    }
+    
+    func encryptFile(_ fileURL: URL) -> Data? {
+        guard let fileData = readDataFromFile(fileURL: fileURL) else { return nil }
+        do {
+            let sealedBox = try AES.GCM.seal(fileData, using: MasterKeyUtil.shared.getMasterKey())
+            return sealedBox.combined
+        } catch {
+            print("Encryption failed: \(error)")
+            return nil
+        }
+    }
+    
+    func encryptFile(_ inputURL: URL, _ outputURL: URL, _ key: SymmetricKey) throws {
+        let keyData = key.withUnsafeBytes { Data($0) }
+        
+        let iv = generateIV()
+        let data = try Data(contentsOf: inputURL)
+        let encryptedData = Data(count: data.count + kCCBlockSizeAES128)
+        var finalData = encryptedData
+        
+        var numBytesEncrypted: size_t = 0
+
+        let status = finalData.withUnsafeMutableBytes { encryptedBytes in
+            data.withUnsafeBytes { dataBytes in
+                key.withUnsafeBytes { keyBytes in
+                    iv.withUnsafeBytes { ivBytes in
+                        CCCrypt(
+                            CCOperation(kCCEncrypt),
+                            CCAlgorithm(kCCAlgorithmAES),
+                            CCOptions(kCCOptionPKCS7Padding),
+                            keyBytes.baseAddress, keyData.count,
+                            ivBytes.baseAddress,
+                            dataBytes.baseAddress, data.count,
+                            encryptedBytes.baseAddress, encryptedData.count,
+                            &numBytesEncrypted
+                        )
+                    }
+                }
+            }
+        }
+
+        guard status == kCCSuccess else {
+            throw NSError(domain: "EncryptionError", code: Int(status), userInfo: nil)
+        }
+
+        finalData.count = numBytesEncrypted
+
+        // Write IV and encrypted data to the output file
+        var outputData = Data()
+        outputData.append(iv)
+        outputData.append(finalData)
+        try outputData.write(to: outputURL)
+    }
+    
+    func decryptToMemory(_ encryptedData: Data) -> Data? {
+        do {
+            let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)
+            return try AES.GCM.open(sealedBox, using: MasterKeyUtil.shared.getMasterKey())
+        } catch {
+            print("Decryption failed: \(error)")
+            return nil
+        }
+    }
+
+    func decryptToMemory(_ encryptedData: URL) throws -> Data? {
+        let encryptedData = try Data(contentsOf: encryptedData)
+        return decryptToMemory(encryptedData)
+    }
+    
+    func decryptToMemory(_ encryptedURL: URL, _ key: SymmetricKey) throws -> Data? {
+        let keyData = key.withUnsafeBytes { Data($0) }
+        
+        let encryptedData = try Data(contentsOf: encryptedURL)
+        let iv = encryptedData.prefix(kCCBlockSizeAES128)
+        let cipherText = encryptedData.suffix(from: kCCBlockSizeAES128)
+        let decryptedData = Data(count: cipherText.count + kCCBlockSizeAES128)
+        var finalData = decryptedData
+        var numBytesDecrypted: size_t = 0
+
+        let status = finalData.withUnsafeMutableBytes { decryptedBytes in
+            cipherText.withUnsafeBytes { cipherBytes in
+                key.withUnsafeBytes { keyBytes in
+                    iv.withUnsafeBytes { ivBytes in
+                        CCCrypt(
+                            CCOperation(kCCDecrypt),
+                            CCAlgorithm(kCCAlgorithmAES),
+                            CCOptions(kCCOptionPKCS7Padding),
+                            keyBytes.baseAddress, keyData.count,
+                            ivBytes.baseAddress,
+                            cipherBytes.baseAddress, cipherText.count,
+                            decryptedBytes.baseAddress, decryptedData.count,
+                            &numBytesDecrypted
+                        )
+                    }
+                }
+            }
+        }
+
+        guard status == kCCSuccess else {
+            throw NSError(domain: "DecryptionError", code: Int(status), userInfo: nil)
+        }
+
+        finalData.count = numBytesDecrypted
+        return finalData
+    }
+    
+    
+}

+ 44 - 24
appbuilder-ios/NexilisLite/NexilisLite/Source/MasterKeyUtil.swift

@@ -13,20 +13,30 @@ public class MasterKeyUtil {
     static let shared = MasterKeyUtil()
     private let keyAlias = "_iosx_security_master_key"
     private let prefsKeyAlias = "_iosx_security_master_key_easysoft_"
+    private let serverKeyAlias = "_iosx_security_master_key_server_"
 
     private init() {}
     
-    func generateAndStoreKey() throws {
-        if try isKeyExists(keyAliasCode: keyAlias) {
+    func base64toData(_ base64: String) -> Data? {
+        guard let data = Data(base64Encoded: base64) else {
+            return nil
+        }
+        return data
+    }
+    
+    func generateAndStoreKey(_ alias: String, key_s: String? = nil) throws {
+        if try isKeyExists(keyAliasCode: alias) {
 //            print("Master Key already exists, skipping generation.")
             return
         }
-        let key = SymmetricKey(size: .bits256)
-        let keyData = key.withUnsafeBytes { Data($0) }
         
+        let key = (key_s != nil) ? nil : SymmetricKey(size: .bits256)
+        guard let keyData = key?.withUnsafeBytes({ Data($0) }) ?? base64toData(key_s!) else {
+            return
+        }
         let query: [String: Any] = [
             kSecClass as String: kSecClassKey,
-            kSecAttrApplicationTag as String: keyAlias,
+            kSecAttrApplicationTag as String: alias,
             kSecValueData as String: keyData,
             kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
         ]
@@ -39,25 +49,15 @@ public class MasterKeyUtil {
     }
     
     func generateAndStorePrefsKey() throws {
-        if try isKeyExists(keyAliasCode: prefsKeyAlias) {
-//            print("Prefs Key already exists, skipping generation.")
-            return
-        }
-        let key = SymmetricKey(size: .bits256)
-        let keyData = key.withUnsafeBytes { Data($0) }
-        
-        let query: [String: Any] = [
-            kSecClass as String: kSecClassKey,
-            kSecAttrApplicationTag as String: prefsKeyAlias,
-            kSecValueData as String: keyData,
-            kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
-        ]
-        
-        SecItemDelete(query as CFDictionary) // Remove if it exists
-        let status = SecItemAdd(query as CFDictionary, nil)
-        guard status == errSecSuccess else {
-            throw NSError(domain: "KeychainError", code: Int(status), userInfo: nil)
-        }
+        try generateAndStoreKey(prefsKeyAlias)
+    }
+    
+    func generateAndStoreMasterKey() throws {
+        try generateAndStoreKey(keyAlias)
+    }
+    
+    func generateAndStoreServerKey(_ key_s: String) throws {
+        try generateAndStoreKey(serverKeyAlias, key_s: key_s)
     }
     
     func isDeviceNotSecure() -> Bool {
@@ -150,6 +150,26 @@ public class MasterKeyUtil {
         return SymmetricKey(data: keyData)
     }
     
+    func getServerKey() throws -> SymmetricKey {
+        let query: [String: Any] = [
+            kSecClass as String: kSecClassKey,
+            kSecAttrApplicationTag as String: serverKeyAlias,
+            kSecReturnData as String: true
+        ]
+        
+        var item: CFTypeRef?
+        let status = SecItemCopyMatching(query as CFDictionary, &item)
+        guard status == errSecSuccess else {
+            throw NSError(domain: "KeychainError", code: Int(status), userInfo: nil)
+        }
+        
+        guard let keyData = item as? Data else {
+            throw NSError(domain: "KeyRetrievalError", code: -1, userInfo: nil)
+        }
+        
+        return SymmetricKey(data: keyData)
+    }
+    
     func encryptP(data: Data) throws -> Data {
         let key = try getPrefsKey()
         let sealedBox = try AES.GCM.seal(data, using: key)

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -140,7 +140,7 @@ public class Nexilis: NSObject {
         Nexilis.showButtonFB = showButton
         
         do {
-            try MasterKeyUtil.shared.generateAndStoreKey()
+            try MasterKeyUtil.shared.generateAndStoreMasterKey()
             try MasterKeyUtil.shared.generateAndStorePrefsKey()
         } catch {
         }