شرح كيفيه تشفير وفك تشفير الملفات في Flutter باستخدام كود Native

شرح كيفيه تشفير وفك تشفير الملفات في Flutter باستخدام كود Native

شرح كيفيه تشفير وفك تشفير الملفات في 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

يتم التشفير وفك التشفير باستخدام خوارزمية AES مع وضع CBC وPKCS5Padding. في هذا الكود، قم بإنشاء وظيفة encryptFile لتشفير الملف باستخدام المفتاح وناقل التهيئة (iv).

خطوات التشفير

قم بتعيين كلمة المرور باستخدام خوارزمية "AES/CBC/PKCS5Padding".
استخدم CipherOutputStream لكتابة البيانات المشفرة إلى ملف.

 فك تشفير الملفات

تعمل وظيفة cryptoFile مثل وظيفة encryptFile، ولكنها تستخدم Cipher.DECRYPT_MODE لفك التشفير.

 كيفية استدعاء وظائف التشفير وفك التشفير الخاصة بـ Flutter؟

يحتوي كود CustomEncryptor في Dart على واجهة تتفاعل مع MethodChannel وتستدعي وظائف التشفير في Kotlin

 تشفير الملفات باستخدام Flutter وSwift

يعد أمان البيانات وتشفير الملفات جانبًا مهمًا لتطبيقات Flutter، خاصة عند التعامل مع المعلومات الحساسة. اليوم سنناقش الكود الكامل لتشفير وفك تشفير الملفات في Swift باستخدام مكتبة CryptoSwift على iOS وربطها مع تطبيق Flutter باستخدام FlutterMethodChannel.
asdasd
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


يتم استخدام مكتبة التشفير لتوفير AES (معيار التشفير المتقدم) كخوارزمية تشفير الملفات في تطبيقات Flutter. تعتمد الخوارزمية على المفتاح وتستخدم IV (ناقل التهيئة) لضمان أمان التشفير.

هنا يتم إنشاء قناة MethodChannel تسمى "encryption_channel" والتي سيتم استخدامها للتفاعل مع النظام الأساسي (Android أو iOS).

inputFile: مسار الملف المراد تشفيره.
OutputFile: مسار الملف لحفظ الملف المشفر.
اتصل بـ invocationMethod لإرسال المعلومات المطلوبة لتشفير الملف على النظام الأساسي.

شرح خطوات استخدام الكود

1. قم بتعيين مفتاح التشفير
أنشئ مفتاحًا بحجم 32 بايت (يجب أن يكون مفتاحًا قويًا للتشفير الآمن).

2. إعداد IV (ناقل التهيئة).
يجب أن يبلغ طول IV 16 بايت ويستخدم لمزيد من الأمان أثناء التشفير وفك التشفير.

3. اتصل بالملف المشفر
قم باستدعاء الدالة encryptFile وقم بتمرير ملف الإدخال وملف الإخراج لتشفير الملف وحفظه.

4. اتصل بملف فك التشفير
يتم استدعاء وظيفة decryptFile بنفس الطريقة، ولكن بالنسبة لفك التشفير، سيتم فك تشفير الملف المشفر وحفظه في ملف الإخراج.
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',
);
تعليقات