meta: Implement access to AES encryption (but fast)
This commit is contained in:
@@ -3,4 +3,5 @@ import 'package:moxplatform_platform_interface/moxplatform_platform_interface.da
|
||||
class MoxplatformPlugin {
|
||||
static IsolateHandler get handler => MoxplatformInterface.handler;
|
||||
static MediaScannerImplementation get media => MoxplatformInterface.media;
|
||||
static CryptographyImplementation get crypto => MoxplatformInterface.crypto;
|
||||
}
|
||||
|
||||
@@ -6,15 +6,23 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.service.ServiceAware;
|
||||
import io.flutter.embedding.engine.plugins.service.ServicePluginBinding;
|
||||
@@ -136,6 +144,38 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "encryptFile":
|
||||
Thread encryptionThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ArrayList args = (ArrayList) call.arguments;
|
||||
String src = (String) args.get(0);
|
||||
String dest = (String) args.get(1);
|
||||
byte[] key = (byte[]) args.get(2);
|
||||
byte[] iv = (byte[]) args.get(3);
|
||||
int algorithm = (int) args.get(4);
|
||||
|
||||
result.success(encryptFile(src, dest, key, iv, algorithm));
|
||||
}
|
||||
});
|
||||
encryptionThread.start();
|
||||
break;
|
||||
case "decryptFile":
|
||||
Thread decryptionThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ArrayList args = (ArrayList) call.arguments;
|
||||
String src = (String) args.get(0);
|
||||
String dest = (String) args.get(1);
|
||||
byte[] key = (byte[]) args.get(2);
|
||||
byte[] iv = (byte[]) args.get(3);
|
||||
int algorithm = (int) args.get(4);
|
||||
|
||||
result.success(decryptFile(src, dest, key, iv, algorithm));
|
||||
}
|
||||
});
|
||||
decryptionThread.start();
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
break;
|
||||
@@ -175,4 +215,84 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
Log.d(TAG, "Detached from service");
|
||||
this.service = null;
|
||||
}
|
||||
|
||||
private String getCipherSpecFromInteger(int algorithm) {
|
||||
switch (algorithm) {
|
||||
case 0: return "AES_128/GCM/NoPadding";
|
||||
case 1: return "AES_256/GCM/NoPadding";
|
||||
case 2: return "AES_256/CBC/PKCS7PADDING";
|
||||
default:
|
||||
Log.d(TAG, "INVALID ALGORITHM");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public boolean encryptFile(String src, String dest, byte[] key, byte[] iv, int algorithm) {
|
||||
String spec = getCipherSpecFromInteger(algorithm);
|
||||
if (spec.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shamelessly stolen from https://github.com/hugo-pcl/native-crypto-flutter/pull/3
|
||||
byte[] buffer = new byte[8096];
|
||||
SecretKeySpec sk = new SecretKeySpec(key, spec);
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(spec);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, sk, new IvParameterSpec(iv));
|
||||
FileInputStream fin = new FileInputStream(src);
|
||||
FileOutputStream fout = new FileOutputStream(dest);
|
||||
CipherOutputStream cout = new CipherOutputStream(fout, cipher);
|
||||
int len = 0;
|
||||
while (true) {
|
||||
len = fin.read(buffer);
|
||||
if (len != 0 && len > 0) {
|
||||
cout.write(buffer, 0, len);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cout.flush();
|
||||
cout.close();
|
||||
fin.close();
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
Log.d(TAG, "ENC: " + ex.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean decryptFile(String src, String dest, byte[] key, byte[] iv, int algorithm) {
|
||||
String spec = getCipherSpecFromInteger(algorithm);
|
||||
if (spec.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shamelessly stolen from https://github.com/hugo-pcl/native-crypto-flutter/pull/3
|
||||
byte[] buffer = new byte[8096];
|
||||
SecretKeySpec sk = new SecretKeySpec(key, spec);
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(spec);
|
||||
cipher.init(Cipher.DECRYPT_MODE, sk, new IvParameterSpec(iv));
|
||||
FileInputStream fin = new FileInputStream(src);
|
||||
FileOutputStream fout = new FileOutputStream(dest);
|
||||
CipherOutputStream cout = new CipherOutputStream(fout, cipher);
|
||||
Log.d(TAG, "Reading from " + src + ", writing to " + dest);
|
||||
int len = 0;
|
||||
while (true) {
|
||||
len = fin.read(buffer);
|
||||
if (len != 0 && len > 0) {
|
||||
cout.write(buffer, 0, len);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cout.flush();
|
||||
cout.close();
|
||||
fin.close();
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
Log.d(TAG, "DEC: " + ex.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
packages/moxplatform_android/lib/src/crypto_android.dart
Normal file
31
packages/moxplatform_android/lib/src/crypto_android.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:moxplatform_platform_interface/moxplatform_platform_interface.dart';
|
||||
|
||||
class AndroidCryptographyImplementation extends CryptographyImplementation {
|
||||
final _methodChannel = const MethodChannel('me.polynom.moxplatform_android');
|
||||
|
||||
@override
|
||||
Future<bool> encryptFile(String sourcePath, String destPath, Uint8List key, Uint8List iv, CipherAlgorithm algorithm) async {
|
||||
final result = await _methodChannel.invokeMethod<bool>('encryptFile', [
|
||||
sourcePath,
|
||||
destPath,
|
||||
key,
|
||||
iv,
|
||||
algorithm.toInt(),
|
||||
]);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> decryptFile(String sourcePath, String destPath, Uint8List key, Uint8List iv, CipherAlgorithm algorithm) async {
|
||||
final result = await _methodChannel.invokeMethod<bool>('decryptFile', [
|
||||
sourcePath,
|
||||
destPath,
|
||||
key,
|
||||
iv,
|
||||
algorithm.toInt(),
|
||||
]);
|
||||
return result ?? false;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:moxplatform_android/src/crypto_android.dart';
|
||||
import 'package:moxplatform_android/src/isolate_android.dart';
|
||||
import 'package:moxplatform_android/src/media_android.dart';
|
||||
import 'package:moxplatform_platform_interface/moxplatform_platform_interface.dart';
|
||||
@@ -8,6 +9,7 @@ class MoxplatformAndroidPlugin extends MoxplatformInterface {
|
||||
print('MoxplatformAndroidPlugin: Registering implementation');
|
||||
MoxplatformInterface.handler = AndroidIsolateHandler();
|
||||
MoxplatformInterface.media = AndroidMediaScannerImplementation();
|
||||
MoxplatformInterface.crypto = AndroidCryptographyImplementation();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
library moxplatform_platform_interface;
|
||||
|
||||
export 'src/crypto.dart';
|
||||
export 'src/crypto_stub.dart';
|
||||
export 'src/interface.dart';
|
||||
export 'src/isolate.dart';
|
||||
export 'src/isolate_stub.dart';
|
||||
|
||||
32
packages/moxplatform_platform_interface/lib/src/crypto.dart
Normal file
32
packages/moxplatform_platform_interface/lib/src/crypto.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
enum CipherAlgorithm {
|
||||
aes128GcmNoPadding,
|
||||
aes256GcmNoPadding,
|
||||
aes256CbcPkcs7,
|
||||
}
|
||||
|
||||
extension CipherAlgorithmToIntExtension on CipherAlgorithm {
|
||||
int toInt() {
|
||||
switch (this) {
|
||||
case CipherAlgorithm.aes128GcmNoPadding: return 0;
|
||||
case CipherAlgorithm.aes256GcmNoPadding: return 1;
|
||||
case CipherAlgorithm.aes256CbcPkcs7: return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around platform-native cryptography APIs
|
||||
abstract class CryptographyImplementation {
|
||||
/// Encrypt the file at [sourcePath] using [algorithm] and write the result back to
|
||||
/// [destPath]. Note that this function runs off-thread as to not block the UI thread.
|
||||
///
|
||||
/// Resolves to true if the encryption was successful. Resolves to fale on failure.
|
||||
Future<bool> encryptFile(String sourcePath, String destPath, Uint8List key, Uint8List iv, CipherAlgorithm algorithm);
|
||||
|
||||
/// Decrypt the file at [sourcePath] using [algorithm] and write the result back to
|
||||
/// [destPath]. Note that this function runs off-thread as to not block the UI thread.
|
||||
///
|
||||
/// Resolves to true if the encryption was successful. Resolves to fale on failure.
|
||||
Future<bool> decryptFile(String sourcePath, String destPath, Uint8List key, Uint8List iv, CipherAlgorithm algorithm);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:moxplatform_platform_interface/src/crypto.dart';
|
||||
|
||||
class StubCryptographyImplementation extends CryptographyImplementation {
|
||||
@override
|
||||
Future<bool> encryptFile(String sourcePath, String destPath, Uint8List key, Uint8List iv, CipherAlgorithm algorithm) async {
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> decryptFile(String sourcePath, String destPath, Uint8List key, Uint8List iv, CipherAlgorithm algorithm) async {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:moxplatform_platform_interface/src/crypto.dart';
|
||||
import 'package:moxplatform_platform_interface/src/crypto_stub.dart';
|
||||
import 'package:moxplatform_platform_interface/src/isolate.dart';
|
||||
import 'package:moxplatform_platform_interface/src/isolate_stub.dart';
|
||||
import 'package:moxplatform_platform_interface/src/media.dart';
|
||||
@@ -11,6 +13,7 @@ abstract class MoxplatformInterface extends PlatformInterface {
|
||||
|
||||
static IsolateHandler handler = StubIsolateHandler();
|
||||
static MediaScannerImplementation media = StubMediaScannerImplementation();
|
||||
static CryptographyImplementation crypto = StubCryptographyImplementation();
|
||||
|
||||
/// Return the current platform name.
|
||||
Future<String?> getPlatformName();
|
||||
|
||||
Reference in New Issue
Block a user