Fix/Update #1
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: benchmark_page.dart | ||||
| // Created Date: 28/12/2021 15:12:39 | ||||
| // Last Modified: 24/05/2022 17:23:33 | ||||
| // Last Modified: 24/05/2022 23:43:59 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -24,6 +24,51 @@ class BenchmarkPage extends ConsumerWidget { | ||||
|   final Output keyContent = Output(); | ||||
|   final Output benchmarkStatus = Output(large: true); | ||||
| 
 | ||||
|   Future<void> _benchmarkEncryptionOnly( | ||||
|     WidgetRef ref, | ||||
|     Cipher cipher, | ||||
|   ) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
|     AesGcm pc = AesGcm(); | ||||
| 
 | ||||
|     if (state.secretKey.bytes.isEmpty) { | ||||
|       benchmarkStatus | ||||
|           .print('No SecretKey!\nGo in Key tab and generate or derive one.'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     benchmarkStatus.print("Benchmark 2/4/8/16/32/64/128/256MB\n"); | ||||
|     List<int> testedSizes = [2, 4, 8, 16, 32, 64, 128, 256]; | ||||
|     String csv = "size;encryption time\n"; | ||||
| 
 | ||||
|     var beforeBench = DateTime.now(); | ||||
|     Cipher.bytesCountPerChunk = Cipher.bytesCountPerChunk; | ||||
|     benchmarkStatus | ||||
|         .append('[Benchmark] ${Cipher.bytesCountPerChunk} bytes/chunk \n'); | ||||
|     for (int size in testedSizes) { | ||||
|       var b = Uint8List(size * 1000000); | ||||
|       csv += "${size * 1000000};"; | ||||
| 
 | ||||
|       // Encryption | ||||
|       var before = DateTime.now(); | ||||
|       var encryptedBigFile = await cipher.encrypt(b); | ||||
|       var after = DateTime.now(); | ||||
| 
 | ||||
|       var benchmark = | ||||
|           after.millisecondsSinceEpoch - before.millisecondsSinceEpoch; | ||||
|       benchmarkStatus.append('[$size MB] Encryption took $benchmark ms\n'); | ||||
| 
 | ||||
|       csv += "$benchmark\n"; | ||||
|     } | ||||
|     var afterBench = DateTime.now(); | ||||
|     var benchmark = | ||||
|         afterBench.millisecondsSinceEpoch - beforeBench.millisecondsSinceEpoch; | ||||
|     var sum = testedSizes.reduce((a, b) => a + b); | ||||
|     benchmarkStatus.append( | ||||
|         'Benchmark finished.\nGenerated, and encrypted $sum MB in $benchmark ms'); | ||||
|     debugPrint("[Benchmark cvs]\n$csv"); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _benchmark(WidgetRef ref, Cipher cipher, | ||||
|       {bool usePc = false}) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
| @ -37,13 +82,14 @@ class BenchmarkPage extends ConsumerWidget { | ||||
| 
 | ||||
|     benchmarkStatus.print("Benchmark 2/4/8/16/32/64/128/256MB\n"); | ||||
|     List<int> testedSizes = [2, 4, 8, 16, 32, 64, 128, 256]; | ||||
|     String csv = | ||||
|         "size;encryption time;encode time;decryption time;crypto time\n"; | ||||
|     String csv = "size;encryption time;decryption time;crypto time\n"; | ||||
| 
 | ||||
|     var beforeBench = DateTime.now(); | ||||
|     Cipher.bytesCountPerChunk = Cipher.bytesCountPerChunk; | ||||
|     benchmarkStatus | ||||
|         .append('[Benchmark] ${Cipher.bytesCountPerChunk} bytes/chunk \n'); | ||||
|     for (int size in testedSizes) { | ||||
|       var b = ByteData(size * 1000000); | ||||
|       //var bigFile = Uint8List.view(); | ||||
|       var b = Uint8List(size * 1000000); | ||||
|       csv += "${size * 1000000};"; | ||||
|       var cryptoTime = 0; | ||||
| 
 | ||||
| @ -51,10 +97,9 @@ class BenchmarkPage extends ConsumerWidget { | ||||
|       var before = DateTime.now(); | ||||
|       Object encryptedBigFile; | ||||
|       if (usePc) { | ||||
|         encryptedBigFile = | ||||
|             pc.encrypt(b.buffer.asUint8List(), state.secretKey.bytes); | ||||
|         encryptedBigFile = pc.encrypt(b, state.secretKey.bytes); | ||||
|       } else { | ||||
|         encryptedBigFile = await cipher.encrypt(b.buffer.asUint8List()); | ||||
|         encryptedBigFile = await cipher.encrypt(b); | ||||
|       } | ||||
|       var after = DateTime.now(); | ||||
| 
 | ||||
| @ -62,7 +107,7 @@ class BenchmarkPage extends ConsumerWidget { | ||||
|           after.millisecondsSinceEpoch - before.millisecondsSinceEpoch; | ||||
|       benchmarkStatus.append('[$size MB] Encryption took $benchmark ms\n'); | ||||
| 
 | ||||
|       csv += "$benchmark;"; | ||||
|       csv += "$benchmark"; | ||||
|       cryptoTime += benchmark; | ||||
| 
 | ||||
|       // Decryption | ||||
| @ -129,6 +174,9 @@ class BenchmarkPage extends ConsumerWidget { | ||||
|               alignment: Alignment.centerLeft, | ||||
|             ), | ||||
|             keyContent, | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 Row( | ||||
|                   mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
|                   children: [ | ||||
| @ -146,6 +194,17 @@ class BenchmarkPage extends ConsumerWidget { | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|                 Row( | ||||
|                   mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
|                   children: [ | ||||
|                     Button( | ||||
|                       () => _benchmarkEncryptionOnly(ref, cipher), | ||||
|                       "NC Persistence", | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|             benchmarkStatus, | ||||
|           ], | ||||
|         ), | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: aes.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 23/05/2022 23:06:05 | ||||
| // Last Modified: 24/05/2022 23:29:42 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -39,6 +39,7 @@ class AES implements Cipher { | ||||
| 
 | ||||
|     final Map<AESMode, List<AESPadding>> _supported = { | ||||
|       AESMode.gcm: [AESPadding.none], | ||||
|       AESMode.cbc: [AESPadding.pkcs5], | ||||
|     }; | ||||
| 
 | ||||
|     if (!_supported[mode]!.contains(padding)) { | ||||
| @ -46,27 +47,35 @@ class AES implements Cipher { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List> _decrypt(CipherText cipherText) async { | ||||
|     return await platform.decryptAsList( | ||||
|           [cipherText.iv, cipherText.payload], | ||||
|           key.bytes, | ||||
|           algorithm.name, | ||||
|         ) ?? | ||||
|         Uint8List(0); | ||||
|   } | ||||
| 
 | ||||
|   Future<CipherText> _encrypt(Uint8List data) async { | ||||
|     final List<Uint8List> cipherText = | ||||
|         await platform.encryptAsList(data, key.bytes, algorithm.name) ?? | ||||
|             List.empty(); | ||||
|     return CipherText.fromPairIvAndBytes( | ||||
|       cipherText, | ||||
|       dataLength: cipherText.last.length, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List> decrypt(CipherText cipherText) async { | ||||
|     final BytesBuilder decryptedData = BytesBuilder(copy: false); | ||||
| 
 | ||||
|     if (cipherText is CipherTextList) { | ||||
|       for (final CipherText ct in cipherText.list) { | ||||
|         final Uint8List d = await platform.decrypt( | ||||
|               ct.bytes, | ||||
|               key.bytes, | ||||
|               algorithm.name, | ||||
|             ) ?? | ||||
|             Uint8List(0); | ||||
|         decryptedData.add(d); | ||||
|         decryptedData.add(await _decrypt(ct)); | ||||
|       } | ||||
|     } else { | ||||
|       final Uint8List d = await platform.decrypt( | ||||
|             cipherText.bytes, | ||||
|             key.bytes, | ||||
|             algorithm.name, | ||||
|           ) ?? | ||||
|           Uint8List(0); | ||||
|       decryptedData.add(d); | ||||
|       decryptedData.add(await _decrypt(cipherText)); | ||||
|     } | ||||
| 
 | ||||
|     return decryptedData.toBytes(); | ||||
| @ -75,43 +84,23 @@ class AES implements Cipher { | ||||
|   @override | ||||
|   Future<CipherText> encrypt(Uint8List data) async { | ||||
|     Uint8List dataToEncrypt; | ||||
| 
 | ||||
|     final CipherTextList cipherTextList = CipherTextList(); | ||||
|     // If data is bigger than 32mB -> split in chunks | ||||
|     if (data.length > CipherTextList.chunkSize) { | ||||
|       final int chunkNb = (data.length / CipherTextList.chunkSize).ceil(); | ||||
| 
 | ||||
|     if (data.length > Cipher.bytesCountPerChunk) { | ||||
|       final int chunkNb = (data.length / Cipher.bytesCountPerChunk).ceil(); | ||||
|       for (var i = 0; i < chunkNb; i++) { | ||||
|         dataToEncrypt = i < (chunkNb - 1) | ||||
|             ? data.sublist( | ||||
|                 i * CipherTextList.chunkSize, | ||||
|                 (i + 1) * CipherTextList.chunkSize, | ||||
|                 i * Cipher.bytesCountPerChunk, | ||||
|                 (i + 1) * Cipher.bytesCountPerChunk, | ||||
|               ) | ||||
|             : data.sublist(i * CipherTextList.chunkSize); | ||||
|         final Uint8List c = await platform.encrypt( | ||||
|               dataToEncrypt, | ||||
|               key.bytes, | ||||
|               algorithm.name, | ||||
|             ) ?? | ||||
|             Uint8List(0); | ||||
|         cipherTextList.add( | ||||
|           CipherText( | ||||
|             c.sublist(0, 12), | ||||
|             c.sublist(12, c.length - 16), | ||||
|             c.sublist(c.length - 16, c.length), | ||||
|           ), | ||||
|         ); // TODO(hpcl): generify this | ||||
|             : data.sublist(i * Cipher.bytesCountPerChunk); | ||||
|         cipherTextList.add(await _encrypt(dataToEncrypt)); | ||||
|       } | ||||
|     } else { | ||||
|       final Uint8List c = | ||||
|           await platform.encrypt(data, key.bytes, algorithm.name) ?? | ||||
|               Uint8List(0); | ||||
| 
 | ||||
|       return CipherText( | ||||
|         c.sublist(0, 12), | ||||
|         c.sublist(12, c.length - 16), | ||||
|         c.sublist(c.length - 16, c.length), | ||||
|       ); // TODO(hpcl): generify this | ||||
|       return _encrypt(data); | ||||
|     } | ||||
| 
 | ||||
|     return cipherTextList; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -3,9 +3,9 @@ | ||||
| // ----- | ||||
| // File: aes_mode.dart | ||||
| // Created Date: 23/05/2022 22:09:16 | ||||
| // Last Modified: 23/05/2022 22:10:31 | ||||
| // Last Modified: 24/05/2022 23:17:01 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| /// Defines the AES modes of operation. | ||||
| enum AESMode { gcm } | ||||
| enum AESMode { gcm, cbc } | ||||
|  | ||||
| @ -3,9 +3,9 @@ | ||||
| // ----- | ||||
| // File: aes_padding.dart | ||||
| // Created Date: 23/05/2022 22:10:17 | ||||
| // Last Modified: 23/05/2022 22:13:28 | ||||
| // Last Modified: 24/05/2022 23:17:25 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| /// Represents different paddings. | ||||
| enum AESPadding { none } | ||||
| enum AESPadding { none, pkcs5 } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher_text.dart | ||||
| // Created Date: 16/12/2021 16:59:53 | ||||
| // Last Modified: 23/05/2022 23:02:10 | ||||
| // Last Modified: 24/05/2022 21:27:44 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -16,23 +16,61 @@ class CipherText extends ByteArray { | ||||
|   final int _dataLength; | ||||
|   final int _tagLength; | ||||
| 
 | ||||
|   CipherText(Uint8List iv, Uint8List data, Uint8List tag) | ||||
|   final Uint8List _iv; | ||||
| 
 | ||||
|   CipherText(Uint8List iv, Uint8List data, Uint8List? tag) | ||||
|       : _ivLength = iv.length, | ||||
|         _dataLength = data.length, | ||||
|         _tagLength = tag.length, | ||||
|         super(Uint8List.fromList(iv + data + tag)); | ||||
|         _tagLength = tag?.length ?? 0, | ||||
|         _iv = iv, | ||||
|         super((tag != null) ? Uint8List.fromList(data + tag) : data); | ||||
| 
 | ||||
|   CipherText.fromBytes( | ||||
|     Uint8List bytes, { | ||||
|     required int ivLength, | ||||
|     required int dataLength, | ||||
|     int tagLength = 0, | ||||
|   })  : _ivLength = ivLength, | ||||
|         _dataLength = dataLength, | ||||
|         _tagLength = tagLength, | ||||
|         _iv = bytes.sublist(0, ivLength), | ||||
|         super(bytes.sublist(ivLength, bytes.length - tagLength)); | ||||
| 
 | ||||
|   const CipherText.fromIvAndBytes( | ||||
|     Uint8List iv, | ||||
|     super.data, { | ||||
|     required int dataLength, | ||||
|     int tagLength = 0, | ||||
|   })  : _ivLength = iv.length, | ||||
|         _dataLength = dataLength, | ||||
|         _tagLength = tagLength, | ||||
|         _iv = iv; | ||||
| 
 | ||||
|   CipherText.fromPairIvAndBytes( | ||||
|     List<Uint8List> pair, { | ||||
|     required int dataLength, | ||||
|     int tagLength = 0, | ||||
|   })  : _ivLength = pair.first.length, | ||||
|         _dataLength = dataLength, | ||||
|         _tagLength = tagLength, | ||||
|         _iv = pair.first, | ||||
|         super(pair.last); | ||||
| 
 | ||||
|   /// Gets the CipherText IV. | ||||
|   Uint8List get iv => bytes.sublist(0, _ivLength); | ||||
|   Uint8List get iv => _iv; | ||||
| 
 | ||||
|   /// Gets the CipherText data. | ||||
|   Uint8List get data => bytes.sublist(_ivLength, _ivLength + _dataLength); | ||||
|   Uint8List get data => _tagLength > 0 | ||||
|       ? bytes.sublist(0, _dataLength - _tagLength) | ||||
|       : bytes; | ||||
| 
 | ||||
|   /// Gets the CipherText tag. | ||||
|   Uint8List get tag => bytes.sublist( | ||||
|         _ivLength + _dataLength, | ||||
|         _ivLength + _dataLength + _tagLength, | ||||
|       ); | ||||
|   Uint8List get tag => _tagLength > 0 | ||||
|       ? bytes.sublist(_dataLength - _tagLength, _dataLength) | ||||
|       : Uint8List(0); | ||||
| 
 | ||||
|   /// Gets the CipherText data and tag. | ||||
|   Uint8List get payload => bytes; | ||||
| 
 | ||||
|   /// Gets the CipherText IV length. | ||||
|   int get ivLength => _ivLength; | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher_text_list.dart | ||||
| // Created Date: 23/05/2022 22:59:02 | ||||
| // Last Modified: 23/05/2022 23:05:02 | ||||
| // Last Modified: 24/05/2022 20:18:26 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -12,7 +12,6 @@ import 'dart:typed_data'; | ||||
| import 'package:native_crypto/src/core/cipher_text.dart'; | ||||
| 
 | ||||
| class CipherTextList extends CipherText { | ||||
|   static const int chunkSize = 33554432; | ||||
|   final List<CipherText> _list; | ||||
| 
 | ||||
|   CipherTextList() | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 23/05/2022 23:06:20 | ||||
| // Last Modified: 24/05/2022 19:55:38 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -18,9 +18,20 @@ import 'package:native_crypto/src/utils/cipher_algorithm.dart'; | ||||
| /// or decryption - a series of well-defined steps that can | ||||
| /// be followed as a procedure. | ||||
| abstract class Cipher { | ||||
|   /// Returns the size of a chunk of data  | ||||
|   /// that can be processed by the cipher. | ||||
|   static int _bytesCountPerChunk = 33554432; | ||||
| 
 | ||||
|   static int get bytesCountPerChunk => Cipher._bytesCountPerChunk; | ||||
| 
 | ||||
|   static set bytesCountPerChunk(int bytesCount) { | ||||
|     _bytesCountPerChunk = bytesCount; | ||||
|   } | ||||
|    | ||||
|   /// Returns the standard algorithm name for this cipher | ||||
|   CipherAlgorithm get algorithm; | ||||
| 
 | ||||
| 
 | ||||
|   /// Encrypts data. | ||||
|   /// | ||||
|   /// Takes [Uint8List] data as parameter. | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package fr.pointcheval.native_crypto_android | ||||
| 
 | ||||
| import androidx.annotation.NonNull | ||||
| import fr.pointcheval.native_crypto_android.interfaces.Cipher | ||||
| import fr.pointcheval.native_crypto_android.kdf.Pbkdf2 | ||||
| import fr.pointcheval.native_crypto_android.keys.SecretKey | ||||
| import fr.pointcheval.native_crypto_android.utils.CipherAlgorithm | ||||
| @ -23,6 +24,8 @@ class NativeCryptoAndroidPlugin : FlutterPlugin, MethodCallHandler { | ||||
|     private lateinit var channel: MethodChannel | ||||
|     private val name = "plugins.hugop.cl/native_crypto" | ||||
| 
 | ||||
|     private var cipherInstance: Cipher? = null | ||||
| 
 | ||||
|     override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||||
|         channel = MethodChannel(flutterPluginBinding.binaryMessenger, name) | ||||
|         channel.setMethodCallHandler(this) | ||||
| @ -38,11 +41,11 @@ class NativeCryptoAndroidPlugin : FlutterPlugin, MethodCallHandler { | ||||
|         when (call.method) { | ||||
|             "digest" -> methodCallTask = handleDigest(call.arguments()) | ||||
|             "generateSecretKey" -> methodCallTask = handleGenerateSecretKey(call.arguments()) | ||||
|             "generateKeyPair" -> result.notImplemented() | ||||
|             "pbkdf2" -> methodCallTask = handlePbkdf2(call.arguments()) | ||||
|             "encrypt" -> methodCallTask = handleEncrypt(call.arguments()) | ||||
|             "decrypt" -> methodCallTask = handleDecrypt(call.arguments()) | ||||
|             "generateSharedSecretKey" -> result.notImplemented() | ||||
|             "encryptAsList" -> methodCallTask = handleEncryptAsList(call.arguments()) | ||||
|             "decryptAsList" -> methodCallTask = handleDecryptAsList(call.arguments()) | ||||
|             "encrypt" -> methodCallTask = handleCrypt(call.arguments(), true) | ||||
|             "decrypt" -> methodCallTask = handleCrypt(call.arguments(), false) | ||||
|             else -> result.notImplemented() | ||||
|         } | ||||
| 
 | ||||
| @ -95,7 +98,17 @@ class NativeCryptoAndroidPlugin : FlutterPlugin, MethodCallHandler { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun handleEncrypt(arguments: Map<String, Any>?): Task<ByteArray> { | ||||
|     private fun lazyLoadCipher(cipherAlgorithm: CipherAlgorithm) { | ||||
|         if (cipherInstance == null) { | ||||
|             cipherInstance = cipherAlgorithm.getCipher() | ||||
|         } else { | ||||
|             if (cipherInstance!!.algorithm != cipherAlgorithm) { | ||||
|                 cipherInstance = cipherAlgorithm.getCipher() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun handleEncryptAsList(arguments: Map<String, Any>?): Task<List<ByteArray>> { | ||||
|         return Task { | ||||
|             val data: ByteArray = | ||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as ByteArray | ||||
| @ -104,13 +117,29 @@ class NativeCryptoAndroidPlugin : FlutterPlugin, MethodCallHandler { | ||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String | ||||
| 
 | ||||
|             val cipherAlgorithm: CipherAlgorithm = CipherAlgorithm.valueOf(algorithm) | ||||
|             val cipher = cipherAlgorithm.getCipher() | ||||
|             lazyLoadCipher(cipherAlgorithm) | ||||
| 
 | ||||
|             cipher.encrypt(data, key) | ||||
|             cipherInstance!!.encryptAsList(data, key) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun handleDecrypt(arguments: Map<String, Any>?): Task<ByteArray> { | ||||
|     private fun handleDecryptAsList(arguments: Map<String, Any>?): Task<ByteArray> { | ||||
|         return Task { | ||||
|             val data: List<ByteArray> = | ||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as List<ByteArray> | ||||
|             val key: ByteArray = Objects.requireNonNull(arguments?.get(Constants.KEY)) as ByteArray | ||||
|             val algorithm: String = | ||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String | ||||
| 
 | ||||
|             val cipherAlgorithm: CipherAlgorithm = CipherAlgorithm.valueOf(algorithm) | ||||
|             lazyLoadCipher(cipherAlgorithm) | ||||
| 
 | ||||
|             cipherInstance!!.decryptAsList(data, key) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // **EN**Crypt and **DE**Crypt | ||||
|     private fun handleCrypt(arguments: Map<String, Any>?, forEncryption: Boolean): Task<ByteArray> { | ||||
|         return Task { | ||||
|             val data: ByteArray = | ||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as ByteArray | ||||
| @ -119,9 +148,13 @@ class NativeCryptoAndroidPlugin : FlutterPlugin, MethodCallHandler { | ||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String | ||||
| 
 | ||||
|             val cipherAlgorithm: CipherAlgorithm = CipherAlgorithm.valueOf(algorithm) | ||||
|             val cipher = cipherAlgorithm.getCipher() | ||||
|             lazyLoadCipher(cipherAlgorithm) | ||||
| 
 | ||||
|             cipher.decrypt(data, key) | ||||
|             if (forEncryption) { | ||||
|                 cipherInstance!!.encrypt(data, key) | ||||
|             } else { | ||||
|                 cipherInstance!!.decrypt(data, key) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -11,6 +11,10 @@ class AES : Cipher { | ||||
|     override val algorithm: CipherAlgorithm | ||||
|         get() = CipherAlgorithm.aes | ||||
| 
 | ||||
|     var forEncryption: Boolean = true | ||||
|     var cipherInstance: javax.crypto.Cipher? = null; | ||||
|     var secretKey: SecretKeySpec? = null; | ||||
| 
 | ||||
| /*    override fun encrypt(data: ByteArray, key: ByteArray): ByteArray { | ||||
|         val sk: SecretKey = SecretKeySpec(key, "AES") | ||||
|         val cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") | ||||
| @ -35,25 +39,46 @@ class AES : Cipher { | ||||
|     }*/ | ||||
| 
 | ||||
|     override fun encrypt(data: ByteArray, key: ByteArray): ByteArray { | ||||
|         val sk: SecretKey = SecretKeySpec(key, "AES") | ||||
|         val cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") | ||||
|         cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) | ||||
|         // javax.crypto representation = [CIPHERTEXT(n-16)] | ||||
|         val bytes = cipher.doFinal(data) | ||||
|         val iv = cipher.iv | ||||
|         val list : List<ByteArray> = encryptAsList(data, key) | ||||
|         return list.first().plus(list.last()) | ||||
|     } | ||||
| 
 | ||||
|     override fun encryptAsList(data: ByteArray, key: ByteArray): List<ByteArray> { | ||||
|         val sk = SecretKeySpec(key, "AES") | ||||
|         if (cipherInstance == null || !forEncryption || secretKey != sk) { | ||||
|             secretKey = sk | ||||
|             forEncryption = true | ||||
|             // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] | ||||
|         return iv.plus(bytes) | ||||
|             // javax.crypto representation = [CIPHERTEXT(n-16)] | ||||
|             cipherInstance = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") | ||||
|             cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) | ||||
|         } | ||||
|         // javax.crypto representation = [CIPHERTEXT(n-16)] | ||||
|         val bytes: ByteArray = cipherInstance!!.doFinal(data) | ||||
|         val iv: ByteArray = cipherInstance!!.iv | ||||
|         // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] | ||||
|         return listOf(iv, bytes) | ||||
|     } | ||||
| 
 | ||||
|     override fun decrypt(data: ByteArray, key: ByteArray): ByteArray { | ||||
|         val sk: SecretKey = SecretKeySpec(key, "AES") | ||||
|         // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] | ||||
|         val iv: ByteArray = data.take(16).toByteArray() | ||||
|         // javax.crypto representation = [CIPHERTEXT(n-16)] | ||||
|         val iv: ByteArray = data.take(16).toByteArray() | ||||
|         val payload: ByteArray = data.drop(16).toByteArray() | ||||
|         return decryptAsList(listOf(iv, payload), key) | ||||
|     } | ||||
| 
 | ||||
|     override fun decryptAsList(data: List<ByteArray>, key: ByteArray): ByteArray { | ||||
|         if (cipherInstance == null) { | ||||
|             // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] | ||||
|             // javax.crypto representation = [CIPHERTEXT(n-16)] | ||||
|             cipherInstance = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") | ||||
|         } | ||||
|         val sk = SecretKeySpec(key, "AES") | ||||
|         val iv: ByteArray = data.first() | ||||
|         val ivSpec = IvParameterSpec(iv) | ||||
|         val cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") | ||||
|         cipher.init(javax.crypto.Cipher.DECRYPT_MODE, sk, ivSpec) | ||||
|         return cipher.doFinal(payload) | ||||
|         cipherInstance!!.init(javax.crypto.Cipher.DECRYPT_MODE, sk, ivSpec) | ||||
|         forEncryption = false | ||||
|         val payload: ByteArray = data.last() | ||||
|         return cipherInstance!!.doFinal(payload) | ||||
|     } | ||||
| } | ||||
| @ -7,4 +7,6 @@ interface Cipher { | ||||
| 
 | ||||
|     fun encrypt(data: ByteArray, key: ByteArray): ByteArray | ||||
|     fun decrypt(data: ByteArray, key: ByteArray): ByteArray | ||||
|     fun encryptAsList(data: ByteArray, key: ByteArray): List<ByteArray> | ||||
|     fun decryptAsList(data: List<ByteArray>, key: ByteArray): ByteArray | ||||
| } | ||||
| @ -1,4 +1 @@ | ||||
| include: package:flutter_lints/flutter.yaml | ||||
| 
 | ||||
| # Additional information about this file can be found at | ||||
| # https://dart.dev/guides/language/analysis-options | ||||
| include: package:wyatt_analysis/analysis_options.flutter.experimental.yaml | ||||
| @ -2,74 +2,13 @@ | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: native_crypto_platform_interface.dart | ||||
| // Created Date: 25/12/2021 16:43:49 | ||||
| // Last Modified: 25/12/2021 17:39:39 | ||||
| // Created Date: 24/05/2022 19:39:11 | ||||
| // Last Modified: 24/05/2022 19:39:58 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| library native_crypto_platform_interface; | ||||
| 
 | ||||
| import './src/method_channel_native_crypto.dart'; | ||||
| import './src/platform_interface.dart'; | ||||
| 
 | ||||
| /// The interface that implementations of path_provider must implement. | ||||
| /// | ||||
| /// Platform implementations should extend this class rather than implement it as `NativeCrypto` | ||||
| /// does not consider newly added methods to be breaking changes. Extending this class | ||||
| /// (using `extends`) ensures that the subclass will get the default implementation, while | ||||
| /// platform implementations that `implements` this interface will be broken by newly added | ||||
| /// [NativeCryptoPlatform] methods. | ||||
| abstract class NativeCryptoPlatform extends PlatformInterface { | ||||
|   /// Constructs a NativeCryptoPlatform. | ||||
|   NativeCryptoPlatform() : super(token: _token); | ||||
| 
 | ||||
|   static final Object _token = Object(); | ||||
| 
 | ||||
|   static NativeCryptoPlatform _instance = MethodChannelNativeCrypto(); | ||||
| 
 | ||||
|   /// The default instance of [NativeCryptoPlatform] to use. | ||||
|   /// | ||||
|   /// Defaults to [MethodChannelPathProvider]. | ||||
|   static NativeCryptoPlatform get instance => _instance; | ||||
| 
 | ||||
|   /// Platform-specific plugins should set this with their own platform-specific | ||||
|   /// class that extends [NativeCryptoPlatform] when they register themselves. | ||||
|   static set instance(NativeCryptoPlatform instance) { | ||||
|     PlatformInterface.verifyToken(instance, _token); | ||||
|     _instance = instance; | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> digest(Uint8List data, String algorithm) { | ||||
|     throw UnimplementedError('digest is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> generateSecretKey(int bitsCount) { | ||||
|     throw UnimplementedError('generateSecretKey is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> generateKeyPair() { | ||||
|     throw UnimplementedError('generateKeyPair is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> pbkdf2(String password, String salt, int keyBytesCount, | ||||
|       int iterations, String algorithm) { | ||||
|     throw UnimplementedError('pbkdf2 is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> encrypt(Uint8List data, Uint8List key, String algorithm) { | ||||
|     throw UnimplementedError('encrypt is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> decrypt(Uint8List data, Uint8List key, String algorithm) { | ||||
|     throw UnimplementedError('decrypt is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> generateSharedSecretKey( | ||||
|       Uint8List salt, | ||||
|       int keyBytesCount, | ||||
|       Uint8List ephemeralPrivateKey, | ||||
|       Uint8List otherPublicKey, | ||||
|       String hkdfAlgorithm) { | ||||
|     throw UnimplementedError('generateSharedSecretKey is not implemented'); | ||||
|   } | ||||
| } | ||||
| export 'src/method_channel/method_channel_native_crypto.dart'; | ||||
| export 'src/platform_interface/native_crypto_platform.dart'; | ||||
| export 'src/utils/exception.dart'; | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: native_crypto_method_channel.dart | ||||
| // Created Date: 25/12/2021 16:58:04 | ||||
| // Last Modified: 25/12/2021 18:58:53 | ||||
| // Last Modified: 24/05/2022 22:59:32 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -11,19 +11,17 @@ import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| 
 | ||||
| import '../native_crypto_platform_interface.dart'; | ||||
| import 'package:native_crypto_platform_interface/src/platform_interface/native_crypto_platform.dart'; | ||||
| 
 | ||||
| /// An implementation of [NativeCryptoPlatform] that uses method channels. | ||||
| class MethodChannelNativeCrypto extends NativeCryptoPlatform { | ||||
|   /// The method channel used to interact with the native platform. | ||||
|   @visibleForTesting | ||||
|   MethodChannel methodChannel = | ||||
|       const MethodChannel('plugins.hugop.cl/native_crypto'); | ||||
|   MethodChannel channel = const MethodChannel('plugins.hugop.cl/native_crypto'); | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> digest(Uint8List data, String algorithm) { | ||||
|     return methodChannel.invokeMethod<Uint8List>( | ||||
|     return channel.invokeMethod<Uint8List>( | ||||
|       'digest', | ||||
|       <String, dynamic>{ | ||||
|         'data': data, | ||||
| @ -34,7 +32,7 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> generateSecretKey(int bitsCount) { | ||||
|     return methodChannel.invokeMethod<Uint8List>( | ||||
|     return channel.invokeMethod<Uint8List>( | ||||
|       'generateSecretKey', | ||||
|       <String, dynamic>{ | ||||
|         'bitsCount': bitsCount, | ||||
| @ -43,14 +41,14 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> generateKeyPair() { | ||||
|     return methodChannel.invokeMethod<Uint8List>('generateKeyPair'); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> pbkdf2(String password, String salt, int keyBytesCount, | ||||
|       int iterations, String algorithm) { | ||||
|     return methodChannel.invokeMethod<Uint8List>( | ||||
|   Future<Uint8List?> pbkdf2( | ||||
|     String password, | ||||
|     String salt, | ||||
|     int keyBytesCount, | ||||
|     int iterations, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     return channel.invokeMethod<Uint8List>( | ||||
|       'pbkdf2', | ||||
|       <String, dynamic>{ | ||||
|         'password': password, | ||||
| @ -63,8 +61,44 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> encrypt(Uint8List data, Uint8List key, String algorithm) { | ||||
|     return methodChannel.invokeMethod<Uint8List>( | ||||
|   Future<List<Uint8List>?> encryptAsList( | ||||
|     Uint8List data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     return channel.invokeListMethod( | ||||
|       'encryptAsList', | ||||
|       <String, dynamic>{ | ||||
|         'data': data, | ||||
|         'key': key, | ||||
|         'algorithm': algorithm, | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> decryptAsList( | ||||
|     List<Uint8List> data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     return channel.invokeMethod<Uint8List>( | ||||
|       'decryptAsList', | ||||
|       <String, dynamic>{ | ||||
|         'data': data, | ||||
|         'key': key, | ||||
|         'algorithm': algorithm, | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> encrypt( | ||||
|     Uint8List data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     return channel.invokeMethod<Uint8List>( | ||||
|       'encrypt', | ||||
|       <String, dynamic>{ | ||||
|         'data': data, | ||||
| @ -75,8 +109,12 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> decrypt(Uint8List data, Uint8List key, String algorithm) { | ||||
|     return methodChannel.invokeMethod<Uint8List>( | ||||
|   Future<Uint8List?> decrypt( | ||||
|     Uint8List data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     return channel.invokeMethod<Uint8List>( | ||||
|       'decrypt', | ||||
|       <String, dynamic>{ | ||||
|         'data': data, | ||||
| @ -85,23 +123,4 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List?> generateSharedSecretKey( | ||||
|       Uint8List salt, | ||||
|       int keyBytesCount, | ||||
|       Uint8List ephemeralPrivateKey, | ||||
|       Uint8List otherPublicKey, | ||||
|       String hkdfAlgorithm) { | ||||
|     return methodChannel.invokeMethod<Uint8List>( | ||||
|       'generateSharedSecretKey', | ||||
|       <String, dynamic>{ | ||||
|         'salt': salt, | ||||
|         'keyBytesCount': keyBytesCount, | ||||
|         'ephemeralPrivateKey': ephemeralPrivateKey, | ||||
|         'otherPublicKey': otherPublicKey, | ||||
|         'hkdfAlgorithm': hkdfAlgorithm, | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -1,97 +0,0 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: platform_interface.dart | ||||
| // Created Date: 25/12/2021 16:52:56 | ||||
| // Last Modified: 27/12/2021 21:25:39 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'package:meta/meta.dart'; | ||||
| 
 | ||||
| /// Base class for platform interfaces. | ||||
| /// | ||||
| /// Provides a static helper method for ensuring that platform interfaces are | ||||
| /// implemented using `extends` instead of `implements`. | ||||
| /// | ||||
| /// Platform interface classes are expected to have a private static token object which will be | ||||
| /// be passed to [verifyToken] along with a platform interface object for verification. | ||||
| /// | ||||
| /// Sample usage: | ||||
| /// | ||||
| /// ```dart | ||||
| /// abstract class NativeCryptoPlatform extends PlatformInterface { | ||||
| ///   NativeCryptoPlatform() : super(token: _token); | ||||
| /// | ||||
| ///   static NativeCryptoPlatform _instance = MethodChannelNativeCrypto(); | ||||
| /// | ||||
| ///   static const Object _token = Object(); | ||||
| /// | ||||
| ///   static NativeCryptoPlatform get instance => _instance; | ||||
| /// | ||||
| ///   /// Platform-specific plugins should set this with their own platform-specific | ||||
| ///   /// class that extends [NativeCryptoPlatform] when they register themselves. | ||||
| ///   static set instance(NativeCryptoPlatform instance) { | ||||
| ///     PlatformInterface.verifyToken(instance, _token); | ||||
| ///     _instance = instance; | ||||
| ///   } | ||||
| /// | ||||
| ///  } | ||||
| /// ``` | ||||
| /// | ||||
| /// Mockito mocks of platform interfaces will fail the verification, in test code only it is possible | ||||
| /// to include the [MockPlatformInterfaceMixin] for the verification to be temporarily disabled. See | ||||
| /// [MockPlatformInterfaceMixin] for a sample of using Mockito to mock a platform interface. | ||||
| abstract class PlatformInterface { | ||||
|   /// Pass a private, class-specific `const Object()` as the `token`. | ||||
|   PlatformInterface({required Object token}) : _instanceToken = token; | ||||
| 
 | ||||
|   final Object? _instanceToken; | ||||
| 
 | ||||
|   /// Ensures that the platform instance has a token that matches the | ||||
|   /// provided token and throws [AssertionError] if not. | ||||
|   /// | ||||
|   /// This is used to ensure that implementers are using `extends` rather than | ||||
|   /// `implements`. | ||||
|   /// | ||||
|   /// Subclasses of [MockPlatformInterfaceMixin] are assumed to be valid in debug | ||||
|   /// builds. | ||||
|   /// | ||||
|   /// This is implemented as a static method so that it cannot be overridden | ||||
|   /// with `noSuchMethod`. | ||||
|   static void verifyToken(PlatformInterface instance, Object token) { | ||||
|     if (instance is MockPlatformInterfaceMixin) { | ||||
|       bool assertionsEnabled = false; | ||||
|       assert(() { | ||||
|         assertionsEnabled = true; | ||||
|         return true; | ||||
|       }()); | ||||
|       if (!assertionsEnabled) { | ||||
|         throw AssertionError( | ||||
|             '`MockPlatformInterfaceMixin` is not intended for use in release builds.'); | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|     if (!identical(token, instance._instanceToken)) { | ||||
|       throw AssertionError( | ||||
|           'Platform interfaces must not be implemented with `implements`'); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /// A [PlatformInterface] mixin that can be combined with mockito's `Mock`. | ||||
| /// | ||||
| /// It passes the [PlatformInterface.verifyToken] check even though it isn't | ||||
| /// using `extends`. | ||||
| /// | ||||
| /// This class is intended for use in tests only. | ||||
| /// | ||||
| /// Sample usage (assuming NativeCryptoPlatform extends [PlatformInterface]: | ||||
| /// | ||||
| /// ```dart | ||||
| /// class NativeCryptoPlatformMock extends Mock | ||||
| ///    with MockPlatformInterfaceMixin | ||||
| ///    implements NativeCryptoPlatform {} | ||||
| /// ``` | ||||
| @visibleForTesting | ||||
| abstract class MockPlatformInterfaceMixin implements PlatformInterface {} | ||||
| @ -0,0 +1,92 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: native_crypto_platform_interface.dart | ||||
| // Created Date: 25/12/2021 16:43:49 | ||||
| // Last Modified: 24/05/2022 22:58:31 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:native_crypto_platform_interface/src/method_channel/method_channel_native_crypto.dart'; | ||||
| import 'package:plugin_platform_interface/plugin_platform_interface.dart'; | ||||
| 
 | ||||
| /// The interface that implementations of path_provider must implement. | ||||
| /// | ||||
| /// Platform implementations should extend this class rather than implement | ||||
| /// it as `NativeCrypto` does not consider newly added methods to be | ||||
| /// breaking changes. Extending this class (using `extends`) ensures | ||||
| /// that the subclass will get the default implementation, while platform | ||||
| /// implementations that `implements` this interface will be | ||||
| /// broken by newly added [NativeCryptoPlatform] methods. | ||||
| abstract class NativeCryptoPlatform extends PlatformInterface { | ||||
|   /// Constructs a NativeCryptoPlatform. | ||||
|   NativeCryptoPlatform() : super(token: _token); | ||||
| 
 | ||||
|   static final Object _token = Object(); | ||||
| 
 | ||||
|   static NativeCryptoPlatform _instance = MethodChannelNativeCrypto(); | ||||
| 
 | ||||
|   /// The default instance of [NativeCryptoPlatform] to use. | ||||
|   /// | ||||
|   /// Defaults to [MethodChannelNativeCrypto]. | ||||
|   static NativeCryptoPlatform get instance => _instance; | ||||
| 
 | ||||
|   /// Platform-specific plugins should set this with their own platform-specific | ||||
|   /// class that extends [NativeCryptoPlatform] when they register themselves. | ||||
|   static set instance(NativeCryptoPlatform instance) { | ||||
|     PlatformInterface.verifyToken(instance, _token); | ||||
|     _instance = instance; | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> digest(Uint8List data, String algorithm) { | ||||
|     throw UnimplementedError('digest is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> generateSecretKey(int bitsCount) { | ||||
|     throw UnimplementedError('generateSecretKey is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> pbkdf2( | ||||
|     String password, | ||||
|     String salt, | ||||
|     int keyBytesCount, | ||||
|     int iterations, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     throw UnimplementedError('pbkdf2 is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<List<Uint8List>?> encryptAsList( | ||||
|     Uint8List data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     throw UnimplementedError('encryptAsList is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> decryptAsList( | ||||
|     List<Uint8List> data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     throw UnimplementedError('decryptAsList is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> encrypt( | ||||
|     Uint8List data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     throw UnimplementedError('encrypt is not implemented'); | ||||
|   } | ||||
| 
 | ||||
|   Future<Uint8List?> decrypt( | ||||
|     Uint8List data, | ||||
|     Uint8List key, | ||||
|     String algorithm, | ||||
|   ) { | ||||
|     throw UnimplementedError('decrypt is not implemented'); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,53 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: exception.dart | ||||
| // Created Date: 24/05/2022 18:54:48 | ||||
| // Last Modified: 24/05/2022 18:58:39 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| import 'package:flutter/services.dart'; | ||||
| 
 | ||||
| class NativeCryptoException implements Exception { | ||||
|   final String message; | ||||
|   const NativeCryptoException(this.message); | ||||
| } | ||||
| 
 | ||||
| /// Catches a [PlatformException] and returns an [Exception]. | ||||
| /// | ||||
| /// If the [Exception] is a [PlatformException], | ||||
| /// a [NativeCryptoException] is returned. | ||||
| Never convertPlatformException(Object exception, StackTrace stackTrace) { | ||||
|   if (exception is! Exception || exception is! PlatformException) { | ||||
|     Error.throwWithStackTrace(exception, stackTrace); | ||||
|   } | ||||
| 
 | ||||
|   Error.throwWithStackTrace( | ||||
|     platformExceptionToNativeCryptoException(exception, stackTrace), | ||||
|     stackTrace, | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| /// Converts a [PlatformException] into a [NativeCryptoException]. | ||||
| /// | ||||
| /// A [PlatformException] can only be converted to a [NativeCryptoException] | ||||
| /// if the `details` of the exception exist. | ||||
| NativeCryptoException platformExceptionToNativeCryptoException( | ||||
|   PlatformException platformException, | ||||
|   StackTrace stackTrace, | ||||
| ) { | ||||
|   final Map<String, String>? details = platformException.details != null | ||||
|       ? Map<String, String>.from( | ||||
|           platformException.details as Map<String, String>, | ||||
|         ) | ||||
|       : null; | ||||
| 
 | ||||
|   String message = platformException.message ?? ''; | ||||
| 
 | ||||
|   if (details != null) { | ||||
|     message = details['message'] ?? message; | ||||
|   } | ||||
| 
 | ||||
|   return NativeCryptoException(message); | ||||
| } | ||||
| @ -3,15 +3,21 @@ description: A common interface for NativeCrypto plugin. | ||||
| version: 0.1.0 | ||||
| 
 | ||||
| environment: | ||||
|   sdk: ">=2.15.0 <3.0.0" | ||||
|   sdk: ">=2.17.0 <3.0.0" | ||||
|   flutter: ">=2.5.0" | ||||
| 
 | ||||
| dependencies: | ||||
|   flutter: | ||||
|     sdk: flutter | ||||
|    | ||||
|   plugin_platform_interface: ^2.1.2 | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|     sdk: flutter | ||||
| 
 | ||||
|   flutter_lints: ^1.0.4 | ||||
|   wyatt_analysis: | ||||
|     git: | ||||
|       url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages | ||||
|       ref: wyatt_analysis-v2.1.0 | ||||
|       path: packages/wyatt_analysis | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user