شرح كيفيه تشفير وفك تشفير الملفات في Flutter باستخدام كود Native
سنقدم في هذه المقالة التعليمات البرمجية لتشفير وفك تشفير الملفات في تطبيق Flutter باستخدام Kotlin كجزء من قناة الاتصال بين Flutter وAndroid عبر MethodChannel. سيكون هذا الموضوع محل اهتمام المطورين الذين يسعون إلى تعزيز أمان التطبيقات من خلال تشفير الملفات، خاصة في التطبيقات التي تتعامل مع المعلومات الحساسة. سنناقش التعليمات البرمجية بالتفصيل ونوضح كيفية استخدام FlutterFragmentActivity وMethodChannel، بالإضافة إلى أفضل الممارسات للتشفير باستخدام مكتبة AES.
كيفية استخدام MethodChannel لتوصيل Flutter وKotlin
تسمح MethodChannel في Flutter بتمرير البيانات بين Flutter وKotlin على Android، مما يتيح الوصول إلى ميزات النظام غير المتوفرة في إطار عمل Flutter نفسه.
ما هي قناة الطريقة (MethodChannel) ؟
MethodChannel هو التواصل بين Dart وAndroid للاتصال وتنفيذ طرق محددة في Kotlin. في الكود أعلاه، تم إعداد قناة التشفير للتعامل مع طلبات تشفير الملفات وفك تشفيرها.
تنشيط MethodChannel
لتنشيط MethodChannel، تحتاج إلى تجاوزconfigFlutterEngine في MainActivity
package com.example.encryption_example
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.provider.Settings
import android.os.Build
import java.io.File
import javax.crypto.Cipher
import javax.crypto.CipherOutputStream
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
class MainActivity : FlutterFragmentActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "encryption_channel").setMethodCallHandler { call, result ->
when (call.method) {
"encryptFile" -> {
val inputFile = call.argument<String>("inputFile")!!
val outputFile = call.argument<String>("outputFile")!!
val key = call.argument<ByteArray>("key")!!
val iv = call.argument<ByteArray>("iv")!!
encryptFile(inputFile, outputFile, key, iv)
result.success(null)
}
"decryptFile" -> {
val inputFile = call.argument<String>("inputFile")!!
val outputFile = call.argument<String>("outputFile")!!
val key = call.argument<ByteArray>("key")!!
val iv = call.argument<ByteArray>("iv")!!
decryptFile(inputFile, outputFile, key, iv)
result.success(null)
}
else -> {
result.notImplemented()
}
}
}
}
private fun encryptFile(inputFilePath: String, outputFilePath: String, key: ByteArray, iv: ByteArray) {
val inputFile = File(inputFilePath)
val outputFile = File(outputFilePath)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
inputFile.inputStream().use { input ->
CipherOutputStream(outputFile.outputStream(), cipher).use { output ->
val buffer = ByteArray(1024 * 1024) // 1MB buffer
var read: Int
while (input.read(buffer).also { read = it } != -1) {
output.write(buffer, 0, read)
}
output.flush()
}
}
}
private fun decryptFile(inputFilePath: String, outputFilePath: String, key: ByteArray, iv: ByteArray) {
val inputFile = File(inputFilePath)
val outputFile = File(outputFilePath)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
inputFile.inputStream().use { input ->
CipherOutputStream(outputFile.outputStream(), cipher).use { output ->
val buffer = ByteArray(1024 * 1024) // 1MB buffer
var read: Int
while (input.read(buffer).also { read = it } != -1) {
output.write(buffer, 0, read)
}
output.flush()
}
}
}
}تشفير الملفات باستخدام AES في Kotlin
خطوات التشفير
فك تشفير الملفات
كيفية استدعاء وظائف التشفير وفك التشفير الخاصة بـ Flutter؟
تشفير الملفات باستخدام Flutter وSwift
import UIKit
import Flutter
import CryptoSwift
import Foundation
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Handel FlutterMethodChannel
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let deviceChannel = FlutterMethodChannel(name: "encryption_channel",
binaryMessenger: controller.binaryMessenger)
prepareMethodHandler(deviceChannel: deviceChannel)
//////////
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// Handel Call Methods
private func prepareMethodHandler(deviceChannel: FlutterMethodChannel) {
deviceChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
guard let args = call.arguments as? [String: Any] else {
result(FlutterMethodNotImplemented)
return
}
if call.method == "encryptFile" {
guard let inputFile = args["inputFile"] as? String,
let outputFile = args["outputFile"] as? String,
let key = args["key"] as? String else {
result(FlutterMethodNotImplemented)
return
}
do {
try self.encryptFile(inputPath: inputFile, outputPath: outputFile, key: key)
result(nil)
} catch {
result(error.localizedDescription)
}
} else if call.method == "decryptFile" {
guard let inputFile = args["inputFile"] as? String,
let outputFile = args["outputFile"] as? String,
let key = args["key"] as? String else {
result(FlutterMethodNotImplemented)
return
}
do {
try self.decryptFile(inputPath: inputFile, outputPath: outputFile, key: key)
result(nil)
} catch {
result(error.localizedDescription)
}
} else {
result(FlutterMethodNotImplemented)
}
}
)
}
// Encrypt File
func encryptFile(inputPath: String,outputPath: String, key: String) throws {
let inputFileURL = URL(fileURLWithPath: inputPath)
let outputFileURL = URL(fileURLWithPath: outputPath)
let key: [UInt8] = Array(key.utf8)
let iv: [UInt8] = AES.randomIV(AES.blockSize)
let chunkSize = 1024 * 1024 // 1 MB
let inputStream = InputStream(url: inputFileURL )!
let outputStream = OutputStream(url: outputFileURL, append: false)!
inputStream.open()
outputStream.open()
var buffer = [UInt8](repeating: 0, count: chunkSize)
var bytesRead = inputStream.read(&buffer, maxLength: buffer.count)
while bytesRead > 0 {
let chunk = Array(buffer[0..<bytesRead])
let encryptedChunk = try AES(key: key, blockMode: CBC(iv: iv)).encrypt(chunk)
outputStream.write(encryptedChunk, maxLength: encryptedChunk.count)
bytesRead = inputStream.read(&buffer, maxLength: buffer.count)
}
inputStream.close()
outputStream.close()
}
// Decrypt File
func decryptFile(inputPath: String,outputPath: String, key: String) throws {
let encryptedFileURL = URL(fileURLWithPath: inputPath)
let decryptedFileURL = URL(fileURLWithPath: outputPath)
let key: [UInt8] = Array(key.utf8)
let iv: [UInt8] = AES.randomIV(AES.blockSize)
let chunkSize = 1024 * 1024 // 1 MB
let encryptedInputStream = InputStream(url: encryptedFileURL)!
let decryptedOutputStream = OutputStream(url: decryptedFileURL, append: false)!
encryptedInputStream.open()
decryptedOutputStream.open()
var encryptedBuffer = [UInt8](repeating: 0, count: chunkSize)
var encryptedBytesRead = encryptedInputStream.read(&encryptedBuffer, maxLength: encryptedBuffer.count)
while encryptedBytesRead > 0 {
let encryptedChunk = Array(encryptedBuffer[0..<encryptedBytesRead])
let decryptedChunk = try AES(key: key, blockMode: CBC(iv: iv)).decrypt(encryptedChunk)
decryptedOutputStream.write(decryptedChunk, maxLength: decryptedChunk.count)
encryptedBytesRead = encryptedInputStream.read(&encryptedBuffer, maxLength: encryptedBuffer.count)
}
encryptedInputStream.close()
decryptedOutputStream.close()
}
}
كيفيه استعمال كود native في تطبيقات Flutter
شرح خطوات استخدام الكود
import 'dart:io';
import 'package:encrypt/encrypt.dart';
import 'package:flutter/services.dart';
abstract class CustomEncryptor {
static const MethodChannel _encryptionChannel =
MethodChannel('encryption_channel');
static Future<void> encryptFile({
required String inputFile,
required String outputFile,
}) async {
Key key = Key.fromUtf8('my 32 length key................');
final iv = IV.fromLength(16).bytes;
try {
_encryptionChannel.invokeMethod('encryptFile', {
'inputFile': inputFile,
'outputFile': outputFile,
'key': key,
'iv': iv,
}).then((value) {
File(inputFile).deleteSync();
print("Done");
});
} on PlatformException catch (e) {
print('Failed to encrypt file: ${e.message}');
}
}
static Future<void> decryptFile({
required String inputFile,
required String outputFile,
}) async {
Key key = Key.fromUtf8('my 32 length key................');
final iv = IV.fromLength(16).bytes;
try {
await _encryptionChannel.invokeMethod('decryptFile', {
'inputFile': inputFile,
'outputFile': outputFile,
'key': key,
'iv': iv,
}).then((value) {
print("done");
});
} on PlatformException catch (e) {
print('Failed to decrypt file: ${e.message}');
}
}
}
كيفية استخدام CustomEncryptor في تطبيقك ؟
await CustomEncryptor.encryptFile(
inputFile: 'path/to/your/input/file.txt',
outputFile: 'path/to/your/output/encrypted_file.enc',
);
await CustomEncryptor.decryptFile(
inputFile: 'path/to/your/output/encrypted_file.enc',
outputFile: 'path/to/your/output/decrypted_file.txt',
);
