meta: Implement access to AES encryption (but fast)

This commit is contained in:
2022-10-04 23:37:32 +02:00
parent 4a89958351
commit 98c3355b44
35 changed files with 858 additions and 0 deletions

View File

@@ -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;
}

View File

@@ -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;
}
}
}

View 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;
}
}

View File

@@ -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

View File

@@ -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';

View 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);
}

View File

@@ -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;
}
}

View File

@@ -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();