Fix/Update #1
| @ -1,3 +1,35 @@ | ||||
| ## 0.1.0 | ||||
| 
 | ||||
| > Breaking changes ! | ||||
| 
 | ||||
| * Follow **Federated Plugin** Flutter standard. | ||||
| 
 | ||||
| ## 0.0.6 | ||||
| 
 | ||||
| * Add KeyPair generation. | ||||
| * Rework exposed API. | ||||
| 
 | ||||
| ## 0.0.5 | ||||
| 
 | ||||
| * New API. | ||||
| * Add digest support. | ||||
| * Clean platform specific code base. | ||||
| 
 | ||||
| ## 0.0.4 | ||||
| 
 | ||||
| * Improve AES. | ||||
| 
 | ||||
| ## 0.0.3 | ||||
| 
 | ||||
| * Add PBKDF2 support. | ||||
| * Add exceptions. | ||||
| * Improve documentation. | ||||
| 
 | ||||
| ## 0.0.2 | ||||
| 
 | ||||
| * Add different key size support. | ||||
| * Improve performances. | ||||
| 
 | ||||
| ## 0.0.1 | ||||
| 
 | ||||
| * TODO: Describe initial release. | ||||
| * First AES cross-platform encryption & decryption implementation. | ||||
|  | ||||
| @ -1 +1,23 @@ | ||||
| TODO: Add your license here. | ||||
| NativeCrypto | ||||
| 
 | ||||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2019 - 2022 Hugo Pointcheval | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
| @ -1,6 +1,6 @@ | ||||
| # native_crypto | ||||
| # NativeCrypto | ||||
| 
 | ||||
| A new flutter plugin project. | ||||
| Fast and powerful cryptographic functions thanks to **javax.crypto** and **CryptoKit**. | ||||
| 
 | ||||
| ## Getting Started | ||||
| 
 | ||||
|  | ||||
| @ -44,7 +44,7 @@ android { | ||||
|     defaultConfig { | ||||
|         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). | ||||
|         applicationId "fr.pointcheval.native_crypto_example" | ||||
|         minSdkVersion flutter.minSdkVersion | ||||
|         minSdkVersion 26 | ||||
|         targetSdkVersion flutter.targetSdkVersion | ||||
|         versionCode flutterVersionCode.toInteger() | ||||
|         versionName flutterVersionName | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
|    <application | ||||
|         android:label="native_crypto_example" | ||||
|         android:name="${applicationName}" | ||||
|         android:largeHeap="true" | ||||
|         android:icon="@mipmap/ic_launcher"> | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|  | ||||
							
								
								
									
										68
									
								
								native_crypto/example/lib/home.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								native_crypto/example/lib/home.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: home.dart | ||||
| // Created Date: 28/12/2021 13:48:36 | ||||
| // Last Modified: 28/12/2021 15:18:03 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:native_crypto_example/pages/benchmark_page.dart'; | ||||
| 
 | ||||
| import 'pages/cipher_page.dart'; | ||||
| import 'pages/kdf_page.dart'; | ||||
| 
 | ||||
| class Home extends StatefulWidget { | ||||
|   const Home({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   _HomeState createState() => _HomeState(); | ||||
| } | ||||
| 
 | ||||
| class _HomeState extends State<Home> { | ||||
|   int _currentIndex = 0; | ||||
|   final List<Widget> _children = [ | ||||
|     KdfPage(), | ||||
|     CipherPage(), | ||||
|     BenchmarkPage() | ||||
|   ]; | ||||
| 
 | ||||
|   void onTabTapped(int index) { | ||||
|     setState(() { | ||||
|       _currentIndex = index; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         centerTitle: true, | ||||
|         title: const Text('Native Crypto'), | ||||
|       ), | ||||
|       body: _children[_currentIndex], | ||||
|       bottomNavigationBar: BottomNavigationBar( | ||||
|         selectedItemColor: Colors.blue, | ||||
|         unselectedItemColor: Colors.black, | ||||
|         showUnselectedLabels: true, | ||||
|         onTap: onTabTapped, // new | ||||
|         currentIndex: _currentIndex, // new | ||||
|         items: const [ | ||||
|           BottomNavigationBarItem( | ||||
|             icon: Icon(Icons.vpn_key), | ||||
|             label: 'Key', | ||||
|           ), | ||||
|           BottomNavigationBarItem( | ||||
|             icon: Icon(Icons.lock), | ||||
|             label: 'Encryption', | ||||
|           ), | ||||
|           BottomNavigationBarItem( | ||||
|             icon: Icon(Icons.timer), | ||||
|             label: 'Benchmark', | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -1,62 +1,25 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'dart:async'; | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: main.dart | ||||
| // Created Date: 27/12/2021 21:15:12 | ||||
| // Last Modified: 28/12/2021 13:51:36 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:native_crypto/native_crypto.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||
| import 'package:native_crypto_example/home.dart'; | ||||
| 
 | ||||
| void main() { | ||||
|   runApp(const MyApp()); | ||||
|   runApp(const ProviderScope(child: MyApp())); | ||||
| } | ||||
| 
 | ||||
| class MyApp extends StatefulWidget { | ||||
| class MyApp extends StatelessWidget { | ||||
|   const MyApp({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<MyApp> createState() => _MyAppState(); | ||||
| } | ||||
| 
 | ||||
| class _MyAppState extends State<MyApp> { | ||||
|   String _platformVersion = 'Unknown'; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     initPlatformState(); | ||||
|   } | ||||
| 
 | ||||
|   // Platform messages are asynchronous, so we initialize in an async method. | ||||
|   Future<void> initPlatformState() async { | ||||
|     String platformVersion; | ||||
|     // Platform messages may fail, so we use a try/catch PlatformException. | ||||
|     // We also handle the message potentially returning null. | ||||
|     try { | ||||
|       platformVersion = | ||||
|           await NativeCrypto.platformVersion ?? 'Unknown platform version'; | ||||
|     } on PlatformException { | ||||
|       platformVersion = 'Failed to get platform version.'; | ||||
|     } | ||||
| 
 | ||||
|     // If the widget was removed from the tree while the asynchronous platform | ||||
|     // message was in flight, we want to discard the reply rather than calling | ||||
|     // setState to update our non-existent appearance. | ||||
|     if (!mounted) return; | ||||
| 
 | ||||
|     setState(() { | ||||
|       _platformVersion = platformVersion; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return MaterialApp( | ||||
|       home: Scaffold( | ||||
|         appBar: AppBar( | ||||
|           title: const Text('Plugin example app'), | ||||
|         ), | ||||
|         body: Center( | ||||
|           child: Text('Running on: $_platformVersion\n'), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|     return const MaterialApp(home: Home()); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										137
									
								
								native_crypto/example/lib/pages/benchmark_page.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								native_crypto/example/lib/pages/benchmark_page.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,137 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: benchmark_page.dart | ||||
| // Created Date: 28/12/2021 15:12:39 | ||||
| // Last Modified: 28/12/2021 15:21:05 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||
| import 'package:native_crypto/native_crypto.dart'; | ||||
| import 'package:native_crypto_example/widgets/button.dart'; | ||||
| 
 | ||||
| import '../session.dart'; | ||||
| import '../widgets/output.dart'; | ||||
| 
 | ||||
| class BenchmarkPage extends ConsumerWidget { | ||||
|   BenchmarkPage({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   final Output keyContent = Output(); | ||||
|   final Output benchmarkStatus = Output(large: true); | ||||
| 
 | ||||
|   Future<void> _benchmark(WidgetRef ref, Cipher cipher) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
| 
 | ||||
|     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;encode time;decryption time;crypto time\n"; | ||||
| 
 | ||||
|     var beforeBench = DateTime.now(); | ||||
|     for (int size in testedSizes) { | ||||
|       var bigFile = Uint8List(size * 1000000); | ||||
|       csv += "${size * 1000000};"; | ||||
|       var cryptoTime = 0; | ||||
| 
 | ||||
|       // Encryption | ||||
|       var before = DateTime.now(); | ||||
|       var encryptedBigFile = await cipher.encrypt(bigFile); | ||||
|       var after = DateTime.now(); | ||||
| 
 | ||||
|       var benchmark = | ||||
|           after.millisecondsSinceEpoch - before.millisecondsSinceEpoch; | ||||
|       benchmarkStatus.append('[$size MB] Encryption took $benchmark ms\n'); | ||||
| 
 | ||||
|       csv += "$benchmark;"; | ||||
|       cryptoTime += benchmark; | ||||
| 
 | ||||
|       // Decryption | ||||
|       before = DateTime.now(); | ||||
|       await cipher.decrypt(encryptedBigFile); | ||||
|       after = DateTime.now(); | ||||
| 
 | ||||
|       benchmark = after.millisecondsSinceEpoch - before.millisecondsSinceEpoch; | ||||
|       benchmarkStatus.append('[$size MB] Decryption took $benchmark ms\n'); | ||||
| 
 | ||||
|       csv += "$benchmark;"; | ||||
|       cryptoTime += benchmark; | ||||
|       csv += "$cryptoTime\n"; | ||||
|     } | ||||
|     var afterBench = DateTime.now(); | ||||
|     var benchmark = | ||||
|         afterBench.millisecondsSinceEpoch - beforeBench.millisecondsSinceEpoch; | ||||
|     var sum = testedSizes.reduce((a, b) => a + b); | ||||
|     benchmarkStatus.append( | ||||
|         'Benchmark finished.\nGenerated, encrypted and decrypted $sum MB in $benchmark ms'); | ||||
|     debugPrint("[Benchmark cvs]\n$csv"); | ||||
|   } | ||||
| 
 | ||||
|   void _clear() { | ||||
|     benchmarkStatus.clear(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
|     if (state.secretKey.bytes.isEmpty) { | ||||
|       keyContent | ||||
|           .print('No SecretKey!\nGo in Key tab and generate or derive one.'); | ||||
|       return SingleChildScrollView( | ||||
|         child: Padding( | ||||
|           padding: const EdgeInsets.all(8.0), | ||||
|           child: Column( | ||||
|             children: [ | ||||
|               const Align( | ||||
|                 child: Text("Secret Key"), | ||||
|                 alignment: Alignment.centerLeft, | ||||
|               ), | ||||
|               keyContent, | ||||
|             ], | ||||
|           ), | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|     keyContent.print(state.secretKey.bytes.toString()); | ||||
| 
 | ||||
|     AES cipher = AES(state.secretKey, AESMode.gcm); | ||||
| 
 | ||||
|     return SingleChildScrollView( | ||||
|       child: Padding( | ||||
|         padding: const EdgeInsets.all(8.0), | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             const Align( | ||||
|               child: Text("Secret Key"), | ||||
|               alignment: Alignment.centerLeft, | ||||
|             ), | ||||
|             keyContent, | ||||
|             Row( | ||||
|               mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
|               children: [ | ||||
|                 Button( | ||||
|                   () => _benchmark(ref, cipher), | ||||
|                   "Launch benchmark", | ||||
|                 ), | ||||
|                 Button( | ||||
|                   _clear, | ||||
|                   "Clear", | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|             benchmarkStatus, | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										158
									
								
								native_crypto/example/lib/pages/cipher_page.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								native_crypto/example/lib/pages/cipher_page.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: cipher_page.dart | ||||
| // Created Date: 28/12/2021 13:33:15 | ||||
| // Last Modified: 28/12/2021 15:20:43 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||
| import 'package:native_crypto/native_crypto.dart'; | ||||
| import 'package:native_crypto_example/widgets/button.dart'; | ||||
| 
 | ||||
| import '../session.dart'; | ||||
| import '../utils.dart'; | ||||
| import '../widgets/output.dart'; | ||||
| 
 | ||||
| // ignore: must_be_immutable | ||||
| class CipherPage extends ConsumerWidget { | ||||
|   CipherPage({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   final Output keyContent = Output(); | ||||
|   final Output encryptionStatus = Output(); | ||||
|   final Output decryptionStatus = Output(); | ||||
| 
 | ||||
|   final TextEditingController _plainTextController = TextEditingController(); | ||||
|   CipherText? cipherText; | ||||
| 
 | ||||
|   Future<void> _encrypt(WidgetRef ref, Cipher cipher) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
|     final plainText = _plainTextController.text.trim(); | ||||
| 
 | ||||
|     if (state.secretKey.bytes.isEmpty) { | ||||
|       encryptionStatus | ||||
|           .print('No SecretKey!\nGo in Key tab and generate or derive one.'); | ||||
|     } else if (plainText.isEmpty) { | ||||
|       encryptionStatus.print('Entry is empty'); | ||||
|     } else { | ||||
|       var stringToBytes = plainText.toBytes(); | ||||
|       cipherText = await cipher.encrypt(stringToBytes); | ||||
|       encryptionStatus.print('String successfully encrypted.\n'); | ||||
|       encryptionStatus.append("Nonce: " + | ||||
|           cipherText!.iv.toString() + | ||||
|           "\nData: " + | ||||
|           cipherText!.data.toString() + | ||||
|           "\nTag: " + | ||||
|           cipherText!.tag.toString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _alter() async { | ||||
|     if (cipherText == null) { | ||||
|       decryptionStatus.print('Encrypt before altering CipherText!'); | ||||
|     } else { | ||||
|       // Add 1 to the first byte | ||||
|       Uint8List _altered = cipherText!.data; | ||||
|       _altered[0] += 1; | ||||
|       // Recreate cipher text with altered data | ||||
|       cipherText = CipherText(cipherText!.iv, _altered, cipherText!.tag); | ||||
|       encryptionStatus.print('String successfully encrypted.\n'); | ||||
|       encryptionStatus.append("Nonce: " + | ||||
|           cipherText!.iv.toString() + | ||||
|           "\nData: " + | ||||
|           cipherText!.data.toString() + | ||||
|           "\nTag: " + | ||||
|           cipherText!.tag.toString()); | ||||
|       decryptionStatus.print('CipherText altered!\nDecryption will fail.'); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void _decrypt(WidgetRef ref, Cipher cipher) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
| 
 | ||||
|     if (state.secretKey.bytes.isEmpty) { | ||||
|       decryptionStatus | ||||
|           .print('No SecretKey!\nGo in Key tab and generate or derive one.'); | ||||
|     } else if (cipherText == null) { | ||||
|       decryptionStatus.print('Encrypt before decrypting!'); | ||||
|     } else { | ||||
|       try { | ||||
|         Uint8List plainText = await cipher.decrypt(cipherText!); | ||||
|         var bytesToString = plainText.toStr(); | ||||
|         decryptionStatus | ||||
|             .print('String successfully decrypted:\n\n$bytesToString'); | ||||
|       } on DecryptionException catch (e) { | ||||
|         decryptionStatus.print(e.message); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
|     if (state.secretKey.bytes.isEmpty) { | ||||
|       keyContent | ||||
|           .print('No SecretKey!\nGo in Key tab and generate or derive one.'); | ||||
|       return SingleChildScrollView( | ||||
|         child: Padding( | ||||
|           padding: const EdgeInsets.all(8.0), | ||||
|           child: Column( | ||||
|             children: [ | ||||
|               const Align( | ||||
|                 child: Text("Secret Key"), | ||||
|                 alignment: Alignment.centerLeft, | ||||
|               ), | ||||
|               keyContent, | ||||
|             ], | ||||
|           ), | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|     keyContent.print(state.secretKey.bytes.toString()); | ||||
| 
 | ||||
|     AES cipher = AES(state.secretKey, AESMode.gcm); | ||||
|     return SingleChildScrollView( | ||||
|       child: Padding( | ||||
|         padding: const EdgeInsets.all(8.0), | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             const Align( | ||||
|               child: Text("Secret Key"), | ||||
|               alignment: Alignment.centerLeft, | ||||
|             ), | ||||
|             keyContent, | ||||
|             TextField( | ||||
|               controller: _plainTextController, | ||||
|               decoration: const InputDecoration( | ||||
|                 hintText: 'Plain text', | ||||
|               ), | ||||
|             ), | ||||
|             Button( | ||||
|               () => _encrypt(ref, cipher), | ||||
|               "Encrypt", | ||||
|             ), | ||||
|             encryptionStatus, | ||||
|             Row( | ||||
|               mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
|               children: [ | ||||
|                 Button( | ||||
|                   _alter, | ||||
|                   "Alter cipher", | ||||
|                 ), | ||||
|                 Button( | ||||
|                   () => _decrypt(ref, cipher), | ||||
|                   "Decrypt", | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|             decryptionStatus, | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										130
									
								
								native_crypto/example/lib/pages/kdf_page.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								native_crypto/example/lib/pages/kdf_page.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: kdf_page.dart | ||||
| // Created Date: 28/12/2021 13:40:34 | ||||
| // Last Modified: 28/12/2021 15:14:12 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||
| import 'package:native_crypto/native_crypto.dart'; | ||||
| import 'package:native_crypto_example/widgets/button.dart'; | ||||
| 
 | ||||
| import '../session.dart'; | ||||
| import '../utils.dart'; | ||||
| import '../widgets/output.dart'; | ||||
| 
 | ||||
| class KdfPage extends ConsumerWidget { | ||||
|   KdfPage({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   final Output keyContent = Output(); | ||||
|   final Output keyStatus = Output(); | ||||
|   final Output pbkdf2Status = Output(); | ||||
|   final Output hashStatus = Output(large: true); | ||||
| 
 | ||||
|   final TextEditingController _pwdTextController = TextEditingController(); | ||||
|   final TextEditingController _messageTextController = TextEditingController(); | ||||
| 
 | ||||
|   Future<void> _generate(WidgetRef ref) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
|     try { | ||||
|       SecretKey sk = await SecretKey.fromSecureRandom(256); | ||||
|       state.setKey(sk); | ||||
|       keyStatus.print( | ||||
|           "SecretKey successfully generated.\nLength: ${state.secretKey.bytes.length} bytes"); | ||||
|       keyContent.print(state.secretKey.bytes.toString()); | ||||
|       debugPrint("As hex :\n${sk.base16}"); | ||||
|     } catch (e) { | ||||
|       keyStatus.print(e.toString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _pbkdf2(WidgetRef ref) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
|     final password = _pwdTextController.text.trim(); | ||||
| 
 | ||||
|     if (password.isEmpty) { | ||||
|       pbkdf2Status.print('Password is empty'); | ||||
|     } else { | ||||
|       PBKDF2 _pbkdf2 = PBKDF2(32, 1000, algorithm: HashAlgorithm.sha512); | ||||
|       SecretKey sk = await _pbkdf2.derive(password: password, salt: 'salt'); | ||||
|       state.setKey(sk); | ||||
|       pbkdf2Status.print('Key successfully derived.'); | ||||
|       keyContent.print(state.secretKey.bytes.toString()); | ||||
|       debugPrint("As hex :\n${sk.base16}"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _hash(Hasher hasher) async { | ||||
|     final message = _messageTextController.text.trim(); | ||||
|     if (message.isEmpty) { | ||||
|       hashStatus.print('Message is empty'); | ||||
|     } else { | ||||
|       Uint8List hash = await hasher.digest(message.toBytes()); | ||||
|       hashStatus.print( | ||||
|           'Message successfully hashed with ${hasher.algorithm} :${hash.toStr(to: Encoding.hex)}'); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     return SingleChildScrollView( | ||||
|       child: Padding( | ||||
|         padding: const EdgeInsets.all(8.0), | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             const Align( | ||||
|               child: Text("SecretKey"), | ||||
|               alignment: Alignment.centerLeft, | ||||
|             ), | ||||
|             keyContent, | ||||
|             Button( | ||||
|               () => _generate(ref), | ||||
|               "Generate SecretKey", | ||||
|             ), | ||||
|             keyStatus, | ||||
|             TextField( | ||||
|               controller: _pwdTextController, | ||||
|               decoration: const InputDecoration( | ||||
|                 hintText: 'Password', | ||||
|               ), | ||||
|             ), | ||||
|             Button( | ||||
|               () => _pbkdf2(ref), | ||||
|               "Apply PBKDF2", | ||||
|             ), | ||||
|             pbkdf2Status, | ||||
|             TextField( | ||||
|               controller: _messageTextController, | ||||
|               decoration: const InputDecoration( | ||||
|                 hintText: 'Message', | ||||
|               ), | ||||
|             ), | ||||
|             Row( | ||||
|               mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
|               children: [ | ||||
|                 Button( | ||||
|                   () => _hash(SHA256()), | ||||
|                   "SHA256", | ||||
|                 ), | ||||
|                 Button( | ||||
|                   () => _hash(SHA384()), | ||||
|                   "SHA384", | ||||
|                 ), | ||||
|                 Button( | ||||
|                   () => _hash(SHA512()), | ||||
|                   "SHA512", | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|             hashStatus, | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										24
									
								
								native_crypto/example/lib/session.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								native_crypto/example/lib/session.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: session.dart | ||||
| // Created Date: 28/12/2021 13:54:29 | ||||
| // Last Modified: 28/12/2021 13:58:49 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||
| import 'package:native_crypto/native_crypto.dart'; | ||||
| 
 | ||||
| class Session { | ||||
|   SecretKey secretKey; | ||||
|   Session() : secretKey = SecretKey(Uint8List(0)); | ||||
| 
 | ||||
|   void setKey(SecretKey sk) { secretKey = sk; } | ||||
| } | ||||
| 
 | ||||
| // Providers | ||||
| 
 | ||||
| final sessionProvider = StateProvider<Session>((ref) => Session()); | ||||
							
								
								
									
										52
									
								
								native_crypto/example/lib/utils.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								native_crypto/example/lib/utils.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: utils.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 28/12/2021 14:40:21 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| import 'dart:convert'; | ||||
| 
 | ||||
| enum Encoding { utf16, base64, hex } | ||||
| 
 | ||||
| extension StringX on String { | ||||
|   Uint8List toBytes({final from = Encoding.utf16}) { | ||||
|     Uint8List bytes = Uint8List(0); | ||||
|     switch (from) { | ||||
|       case Encoding.utf16: | ||||
|         bytes = Uint8List.fromList(runes.toList()); | ||||
|         break; | ||||
|       case Encoding.base64: | ||||
|         bytes = base64.decode(this); | ||||
|         break; | ||||
|       case Encoding.hex: | ||||
|       bytes = Uint8List.fromList( | ||||
|         List.generate( | ||||
|           length ~/ 2, | ||||
|           (i) => int.parse(substring(i * 2, (i * 2) + 2), radix: 16), | ||||
|         ).toList(), | ||||
|       ); | ||||
|     } | ||||
|     return bytes; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| extension Uint8ListX on Uint8List { | ||||
|   String toStr({final to = Encoding.utf16}) { | ||||
|     String str = ""; | ||||
|     switch (to) { | ||||
|       case Encoding.utf16: | ||||
|         str = String.fromCharCodes(this); | ||||
|         break; | ||||
|       case Encoding.base64: | ||||
|         str = base64.encode(this); | ||||
|         break; | ||||
|       case Encoding.hex: | ||||
|         str = map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(); | ||||
|     } | ||||
|     return str; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										32
									
								
								native_crypto/example/lib/widgets/button.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								native_crypto/example/lib/widgets/button.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: button.dart | ||||
| // Created Date: 28/12/2021 13:31:17 | ||||
| // Last Modified: 28/12/2021 13:31:34 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| class Button extends StatelessWidget { | ||||
|   final void Function() onPressed; | ||||
|   final String label; | ||||
| 
 | ||||
|   const Button(this.onPressed, this.label, {Key? key}) : super(key: key); | ||||
| 
 | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return ElevatedButton( | ||||
|       onPressed: onPressed, | ||||
|       style: TextButton.styleFrom( | ||||
|         primary: Colors.blue, | ||||
|       ), | ||||
|       child: Text( | ||||
|         label, | ||||
|         style: const TextStyle(color: Colors.white), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										61
									
								
								native_crypto/example/lib/widgets/output.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								native_crypto/example/lib/widgets/output.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: output.dart | ||||
| // Created Date: 28/12/2021 13:31:39 | ||||
| // Last Modified: 28/12/2021 14:12:11 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| // ignore: must_be_immutable | ||||
| class Output extends StatelessWidget { | ||||
|   late TextEditingController controller; | ||||
|   final bool large; | ||||
|   final bool editable; | ||||
| 
 | ||||
|   Output({ | ||||
|     Key? key, | ||||
|     TextEditingController? controller, | ||||
|     this.large = false, | ||||
|     this.editable = false, | ||||
|   }) : super(key: key) { | ||||
|     this.controller = controller ?? TextEditingController(); | ||||
|   } | ||||
| 
 | ||||
|   void print(String message) { | ||||
|     debugPrint(message); | ||||
|     controller.text = message; | ||||
|   } | ||||
| 
 | ||||
|   void append(String message) { | ||||
|     debugPrint(message); | ||||
|     controller.text += message; | ||||
|   } | ||||
| 
 | ||||
|   void appendln(String message) { | ||||
|     debugPrint(message); | ||||
|     controller.text += message + "\n"; | ||||
|   } | ||||
| 
 | ||||
|   void clear() { | ||||
|     controller.clear(); | ||||
|   } | ||||
| 
 | ||||
|   String read() { | ||||
|     return controller.text; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return TextField( | ||||
|       enableInteractiveSelection: true, | ||||
|       readOnly: editable ? false : true, | ||||
|       minLines: large ? 3 : 1, | ||||
|       maxLines: large ? 500 : 5, | ||||
|       decoration: const InputDecoration(border: OutlineInputBorder()), | ||||
|       controller: controller, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -29,6 +29,7 @@ dependencies: | ||||
|   # The following adds the Cupertino Icons font to your application. | ||||
|   # Use with the CupertinoIcons class for iOS style icons. | ||||
|   cupertino_icons: ^1.0.2 | ||||
|   flutter_riverpod: ^1.0.3 | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
| @ -39,7 +40,7 @@ dev_dependencies: | ||||
|   # activated in the `analysis_options.yaml` file located at the root of your | ||||
|   # package. See that file for information about deactivating specific lint | ||||
|   # rules and activating additional ones. | ||||
|   flutter_lints: ^1.0.0 | ||||
|   flutter_lints: ^1.0.4 | ||||
| 
 | ||||
| # For information on the generic Dart part of this file, see the | ||||
| # following page: https://dart.dev/tools/pub/pubspec | ||||
|  | ||||
| @ -1,17 +1,27 @@ | ||||
| // You have generated a new plugin project without | ||||
| // specifying the `--platforms` flag. A plugin project supports no platforms is generated. | ||||
| // To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same | ||||
| // directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms. | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: native_crypto.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 28/12/2021 15:06:48 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:async'; | ||||
| export 'src/byte_array.dart'; | ||||
| export 'src/cipher.dart'; | ||||
| export 'src/cipher_text.dart'; | ||||
| export 'src/ciphers/aes.dart'; | ||||
| export 'src/exceptions.dart'; | ||||
| export 'src/hasher.dart'; | ||||
| export 'src/hashers/sha256.dart'; | ||||
| export 'src/hashers/sha384.dart'; | ||||
| export 'src/hashers/sha512.dart'; | ||||
| export 'src/kdf/pbkdf2.dart'; | ||||
| export 'src/keyderivation.dart'; | ||||
| export 'src/keys/secret_key.dart'; | ||||
| export 'src/utils.dart'; | ||||
| 
 | ||||
| import 'package:flutter/services.dart'; | ||||
| 
 | ||||
| class NativeCrypto { | ||||
|   static const MethodChannel _channel = MethodChannel('native_crypto'); | ||||
| 
 | ||||
|   static Future<String?> get platformVersion async { | ||||
|     final String? version = await _channel.invokeMethod('getPlatformVersion'); | ||||
|     return version; | ||||
|   } | ||||
| } | ||||
| const String version = "0.1.0"; | ||||
| const String author = "Hugo Pointcheval"; | ||||
| const String website = "https://hugo.pointcheval.fr/"; | ||||
| const List<String> repositories = ["https://github.com/hugo-pcl/native-crypto-flutter", "https://git.pointcheval.fr/NativeCrypto/native-crypto-flutter"]; | ||||
|  | ||||
							
								
								
									
										12
									
								
								native_crypto/lib/src/builder.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								native_crypto/lib/src/builder.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: builder.dart | ||||
| // Created Date: 28/12/2021 12:02:34 | ||||
| // Last Modified: 28/12/2021 12:32:12 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| abstract class Builder<T> { | ||||
|   Future<T> build(); | ||||
| } | ||||
							
								
								
									
										46
									
								
								native_crypto/lib/src/builders/aes_builder.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								native_crypto/lib/src/builders/aes_builder.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: aes_builder.dart | ||||
| // Created Date: 28/12/2021 12:03:11 | ||||
| // Last Modified: 28/12/2021 13:39:23 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import '../builder.dart'; | ||||
| import '../ciphers/aes.dart'; | ||||
| import '../exceptions.dart'; | ||||
| import '../keys/secret_key.dart'; | ||||
| 
 | ||||
| class AESBuilder implements Builder<AES> { | ||||
|   SecretKey? _sk; | ||||
|   Future<SecretKey>? _fsk; | ||||
|   AESMode _mode = AESMode.gcm; | ||||
| 
 | ||||
|   AESBuilder withGeneratedKey(int bitsCount) { | ||||
|     _fsk = SecretKey.fromSecureRandom(bitsCount); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   AESBuilder withKey(SecretKey secretKey) { | ||||
|     _sk = secretKey; | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   AESBuilder using(AESMode mode) { | ||||
|     _mode = mode; | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<AES> build() async { | ||||
|     if (_sk == null) { | ||||
|       if (_fsk == null) { | ||||
|         throw CipherInitException("You must specify or generate a secret key."); | ||||
|       } else { | ||||
|         _sk = await _fsk; | ||||
|       } | ||||
|     } | ||||
|     return AES(_sk!, _mode); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										72
									
								
								native_crypto/lib/src/byte_array.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								native_crypto/lib/src/byte_array.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: byte_array.dart | ||||
| // Created Date: 16/12/2021 17:54:16 | ||||
| // Last Modified: 27/12/2021 21:51:36 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'utils.dart'; | ||||
| import 'dart:convert' as convert; | ||||
| 
 | ||||
| class ByteArray { | ||||
|   Uint8List _bytes; | ||||
| 
 | ||||
|   ByteArray(this._bytes); | ||||
| 
 | ||||
|   /// Creates an ByteArray object from a hexdecimal string. | ||||
|   ByteArray.fromBase16(String encoded) : _bytes = Utils.decodeHexString(encoded); | ||||
| 
 | ||||
|   /// Creates an ByteArray object from a Base64 string. | ||||
|   ByteArray.fromBase64(String encoded) | ||||
|       : _bytes = convert.base64.decode(encoded); | ||||
| 
 | ||||
|   /// Creates an ByteArray object from a UTF-8 string. | ||||
|   ByteArray.fromUtf8(String input) | ||||
|       : _bytes = Uint8List.fromList(convert.utf8.encode(input)); | ||||
| 
 | ||||
|   /// Creates an ByteArray object from a length. | ||||
|   ByteArray.fromLength(int length) : _bytes = Uint8List(length); | ||||
| 
 | ||||
|   /// Gets the ByteArray bytes. | ||||
|   // ignore: unnecessary_getters_setters | ||||
|   Uint8List get bytes => _bytes; | ||||
| 
 | ||||
|   /// Sets the ByteArray bytes. | ||||
|   set bytes(Uint8List value) => _bytes = value; | ||||
| 
 | ||||
|   /// Gets the ByteArray bytes as a Hexadecimal representation. | ||||
|   String get base16 => | ||||
|       _bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(); | ||||
| 
 | ||||
|   /// Gets the ByteArray bytes as a Base64 representation. | ||||
|   String get base64 => convert.base64.encode(_bytes); | ||||
| 
 | ||||
|   @override | ||||
|   bool operator ==(other) { | ||||
|     if (other is ByteArray) { | ||||
|       for (int i = 0; i < _bytes.length; i++) { | ||||
|         if (_bytes[i] != other._bytes[i]) { | ||||
|           return false; | ||||
|         } | ||||
|       } | ||||
|        | ||||
|       return true; | ||||
|     } | ||||
|      | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     int hash = 0; | ||||
|     for (int i = 0; i < _bytes.length; i++) { | ||||
|       hash = _bytes[i] + (hash << 6) + (hash << 16) - hash; | ||||
|     } | ||||
|      | ||||
|     return hash; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										37
									
								
								native_crypto/lib/src/cipher.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								native_crypto/lib/src/cipher.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: cipher.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 28/12/2021 12:25:38 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'cipher_text.dart'; | ||||
| 
 | ||||
| /// Represents different cipher algorithms | ||||
| enum CipherAlgorithm { aes, rsa } | ||||
| 
 | ||||
| /// Represents a cipher. | ||||
| /// | ||||
| /// In cryptography, a cipher is an algorithm for performing encryption | ||||
| /// or decryption - a series of well-defined steps that can | ||||
| /// be followed as a procedure. | ||||
| abstract class Cipher { | ||||
|   /// Returns the standard algorithm name for this cipher | ||||
|   CipherAlgorithm get algorithm; | ||||
| 
 | ||||
|   /// Encrypts data. | ||||
|   /// | ||||
|   /// Takes [Uint8List] data as parameter. | ||||
|   /// Returns a [CipherText]. | ||||
|   Future<CipherText> encrypt(Uint8List data); | ||||
| 
 | ||||
|   /// Decrypts cipher text. | ||||
|   /// | ||||
|   /// Takes [CipherText] as parameter. | ||||
|   /// And returns plain text data as [Uint8List]. | ||||
|   Future<Uint8List> decrypt(CipherText cipherText); | ||||
| } | ||||
							
								
								
									
										51
									
								
								native_crypto/lib/src/cipher_text.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								native_crypto/lib/src/cipher_text.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: cipher_text.dart | ||||
| // Created Date: 16/12/2021 16:59:53 | ||||
| // Last Modified: 27/12/2021 22:32:06 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'byte_array.dart'; | ||||
| 
 | ||||
| class CipherText extends ByteArray { | ||||
|   final int _ivLength; | ||||
|   final int _dataLength; | ||||
|   final int _tagLength; | ||||
|    | ||||
|   CipherText(Uint8List iv, Uint8List data, Uint8List tag) : _ivLength = iv.length, _dataLength = data.length, _tagLength = tag.length, super(Uint8List.fromList(iv + data + tag)); | ||||
|    | ||||
|   /// Gets the CipherText IV. | ||||
|   Uint8List get iv => bytes.sublist(0, _ivLength); | ||||
| 
 | ||||
|   /// Gets the CipherText data. | ||||
|   Uint8List get data => bytes.sublist(_ivLength, _ivLength + _dataLength); | ||||
| 
 | ||||
|   /// Gets the CipherText tag. | ||||
|   Uint8List get tag => bytes.sublist(_ivLength + _dataLength, _ivLength + _dataLength + _tagLength); | ||||
| 
 | ||||
|   /// Gets the CipherText IV length. | ||||
|   int get ivLength => _ivLength; | ||||
| 
 | ||||
|   /// Gets the CipherText data length. | ||||
|   int get dataLength => _dataLength; | ||||
| 
 | ||||
|   /// Gets the CipherText tag length. | ||||
|   int get tagLength => _tagLength; | ||||
| } | ||||
| 
 | ||||
| class CipherTextList extends CipherText { | ||||
|   static const int chunkSize = 33554432; | ||||
|   final List<CipherText> _list; | ||||
| 
 | ||||
|   CipherTextList() : _list = [], super(Uint8List(0), Uint8List(0), Uint8List(0)); | ||||
| 
 | ||||
|   void add(CipherText cipherText) { | ||||
|     _list.add(cipherText); | ||||
|   } | ||||
| 
 | ||||
|   get list => _list; | ||||
| } | ||||
							
								
								
									
										112
									
								
								native_crypto/lib/src/ciphers/aes.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								native_crypto/lib/src/ciphers/aes.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: aes.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 28/12/2021 13:39:00 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import '../cipher.dart'; | ||||
| import '../cipher_text.dart'; | ||||
| import '../exceptions.dart'; | ||||
| import '../keys/secret_key.dart'; | ||||
| import '../platform.dart'; | ||||
| import '../utils.dart'; | ||||
| 
 | ||||
| /// Defines the AES modes of operation. | ||||
| enum AESMode { gcm } | ||||
| 
 | ||||
| /// Defines all available key sizes. | ||||
| enum AESKeySize { bits128, bits192, bits256 } | ||||
| 
 | ||||
| /// Represents different paddings. | ||||
| enum AESPadding { none } | ||||
| 
 | ||||
| extension AESKeySizeExtension on AESKeySize { | ||||
|   static final Map<AESKeySize, int> sizes = <AESKeySize, int>{ | ||||
|     AESKeySize.bits128: 128, | ||||
|     AESKeySize.bits192: 192, | ||||
|     AESKeySize.bits256: 256, | ||||
|   }; | ||||
|   static final List<int> supportedSizes = sizes.values.toList(growable: false); | ||||
|   int get length { | ||||
|     return sizes[this]!; // this is safe because `this` is listed in the enum | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class AES implements Cipher { | ||||
|   final SecretKey key; | ||||
|   final AESMode mode; | ||||
|   final AESPadding padding; | ||||
| 
 | ||||
|   @override | ||||
|   CipherAlgorithm get algorithm => CipherAlgorithm.aes; | ||||
| 
 | ||||
|   AES(this.key, this.mode, {this.padding = AESPadding.none}) { | ||||
|     if (!AESKeySizeExtension.supportedSizes.contains(key.bytes.length * 8)) { | ||||
|       throw CipherInitException("Invalid key length!"); | ||||
|     } | ||||
| 
 | ||||
|     Map<AESMode, List<AESPadding>> _supported = { | ||||
|       AESMode.gcm: [AESPadding.none], | ||||
|     }; | ||||
| 
 | ||||
|     if (!_supported[mode]!.contains(padding)) { | ||||
|       throw CipherInitException("Invalid padding!"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Uint8List> decrypt(CipherText cipherText) async { | ||||
|     BytesBuilder decryptedData = BytesBuilder(copy: false); | ||||
|     if (cipherText is CipherTextList) { | ||||
|       for (CipherText ct in cipherText.list) { | ||||
|         Uint8List d = await platform.decrypt( | ||||
|                 ct.bytes, key.bytes, Utils.enumToStr(algorithm)) ?? | ||||
|             Uint8List(0); | ||||
|         decryptedData.add(d); | ||||
|       } | ||||
|     } else { | ||||
|       Uint8List d = await platform.decrypt( | ||||
|               cipherText.bytes, key.bytes, Utils.enumToStr(algorithm)) ?? | ||||
|           Uint8List(0); | ||||
|       decryptedData.add(d); | ||||
|     } | ||||
| 
 | ||||
|     return decryptedData.toBytes(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<CipherText> encrypt(Uint8List data) async { | ||||
|     Uint8List dataToEncrypt; | ||||
|     CipherTextList cipherTextList = CipherTextList(); | ||||
|     // If data is bigger than 32mB -> split in chunks | ||||
|     if (data.length > CipherTextList.chunkSize) { | ||||
|       int chunkNb = (data.length / CipherTextList.chunkSize).ceil(); | ||||
|       for (var i = 0; i < chunkNb; i++) { | ||||
|         dataToEncrypt = i < (chunkNb - 1) | ||||
|             ? data.sublist(i * CipherTextList.chunkSize, (i + 1) * CipherTextList.chunkSize) | ||||
|             : data.sublist(i * CipherTextList.chunkSize); | ||||
|         Uint8List c = await platform.encrypt( | ||||
|           dataToEncrypt, | ||||
|           key.bytes, | ||||
|           Utils.enumToStr(algorithm) | ||||
|         ) ?? Uint8List(0); | ||||
|         cipherTextList.add(CipherText(c.sublist(0, 12), c.sublist(12, c.length - 16), c.sublist(c.length - 16, c.length))); // TODO: generify this | ||||
|       } | ||||
|     } else { | ||||
|       Uint8List c = await platform.encrypt( | ||||
|         data, | ||||
|         key.bytes, | ||||
|         Utils.enumToStr(algorithm) | ||||
|       ) ?? Uint8List(0); | ||||
| 
 | ||||
|       return CipherText(c.sublist(0, 12), c.sublist(12, c.length - 16), c.sublist(c.length - 16, c.length)); // TODO: generify this | ||||
|     } | ||||
| 
 | ||||
|     return cipherTextList; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										41
									
								
								native_crypto/lib/src/exceptions.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								native_crypto/lib/src/exceptions.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: exceptions.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 27/12/2021 23:28:31 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| class NativeCryptoException implements Exception { | ||||
|   String message; | ||||
|   NativeCryptoException(this.message); | ||||
| } | ||||
| 
 | ||||
| class UtilsException extends NativeCryptoException { | ||||
|   UtilsException(message) : super(message); | ||||
| } | ||||
| 
 | ||||
| class KeyException extends NativeCryptoException { | ||||
|   KeyException(message) : super(message); | ||||
| } | ||||
| 
 | ||||
| class KeyDerivationException extends NativeCryptoException { | ||||
|   KeyDerivationException(message) : super(message); | ||||
| } | ||||
| 
 | ||||
| class CipherInitException extends NativeCryptoException { | ||||
|   CipherInitException(message) : super(message); | ||||
| } | ||||
| 
 | ||||
| class EncryptionException extends NativeCryptoException { | ||||
|   EncryptionException(message) : super(message); | ||||
| } | ||||
| 
 | ||||
| class DecryptionException extends NativeCryptoException { | ||||
|   DecryptionException(message) : super(message); | ||||
| } | ||||
| 
 | ||||
| class NotImplementedException extends NativeCryptoException { | ||||
|   NotImplementedException(message) : super(message); | ||||
| } | ||||
							
								
								
									
										27
									
								
								native_crypto/lib/src/hasher.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								native_crypto/lib/src/hasher.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: hasher.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 27/12/2021 22:06:29 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'platform.dart'; | ||||
| import 'utils.dart'; | ||||
| 
 | ||||
| enum HashAlgorithm { sha256, sha384, sha512 } | ||||
| 
 | ||||
| abstract class Hasher { | ||||
|   /// Returns the standard algorithm name for this digest | ||||
|   HashAlgorithm get algorithm; | ||||
| 
 | ||||
|   /// Hashes a message | ||||
|   Future<Uint8List> digest(Uint8List data) async { | ||||
|     Uint8List hash = (await platform.digest(data, Utils.enumToStr(algorithm))) ?? Uint8List(0); | ||||
|      | ||||
|     return hash; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										15
									
								
								native_crypto/lib/src/hashers/sha256.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								native_crypto/lib/src/hashers/sha256.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: sha256.dart | ||||
| // Created Date: 17/12/2021 11:31:20 | ||||
| // Last Modified: 18/12/2021 12:09:33 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import '../hasher.dart'; | ||||
| 
 | ||||
| class SHA256 extends Hasher{ | ||||
|   @override | ||||
|   HashAlgorithm get algorithm => HashAlgorithm.sha256; | ||||
| } | ||||
							
								
								
									
										15
									
								
								native_crypto/lib/src/hashers/sha384.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								native_crypto/lib/src/hashers/sha384.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: sha384.dart | ||||
| // Created Date: 17/12/2021 11:31:53 | ||||
| // Last Modified: 18/12/2021 12:09:45 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import '../hasher.dart'; | ||||
| 
 | ||||
| class SHA384 extends Hasher{ | ||||
|   @override | ||||
|   HashAlgorithm get algorithm => HashAlgorithm.sha384; | ||||
| } | ||||
							
								
								
									
										15
									
								
								native_crypto/lib/src/hashers/sha512.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								native_crypto/lib/src/hashers/sha512.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: sha512.dart | ||||
| // Created Date: 17/12/2021 11:32:14 | ||||
| // Last Modified: 18/12/2021 12:09:58 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import '../hasher.dart'; | ||||
| 
 | ||||
| class SHA512 extends Hasher{ | ||||
|   @override | ||||
|   HashAlgorithm get algorithm => HashAlgorithm.sha512; | ||||
| } | ||||
							
								
								
									
										51
									
								
								native_crypto/lib/src/kdf/pbkdf2.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								native_crypto/lib/src/kdf/pbkdf2.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: pbkdf2.dart | ||||
| // Created Date: 17/12/2021 14:50:42 | ||||
| // Last Modified: 28/12/2021 13:38:50 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import '../exceptions.dart'; | ||||
| import '../hasher.dart'; | ||||
| import '../keyderivation.dart'; | ||||
| import '../keys/secret_key.dart'; | ||||
| import '../platform.dart'; | ||||
| import '../utils.dart'; | ||||
| 
 | ||||
| class PBKDF2 extends KeyDerivation { | ||||
|   final int _keyBytesCount; | ||||
|   final int _iterations; | ||||
|   final HashAlgorithm _hash; | ||||
| 
 | ||||
|   @override | ||||
|   KdfAlgorithm get algorithm => KdfAlgorithm.pbkdf2; | ||||
| 
 | ||||
|   PBKDF2( | ||||
|     int keyBytesCount, | ||||
|     int iterations, { | ||||
|     HashAlgorithm algorithm = HashAlgorithm.sha256, | ||||
|   })  : _keyBytesCount = keyBytesCount, | ||||
|         _iterations = iterations, | ||||
|         _hash = algorithm; | ||||
| 
 | ||||
|   @override | ||||
|   Future<SecretKey> derive({String? password, String? salt}) async { | ||||
|     if (password == null || salt == null) { | ||||
|       throw KeyDerivationException("Password or Salt can't be null!"); | ||||
|     } | ||||
| 
 | ||||
|     Uint8List derivation = (await platform.pbkdf2( | ||||
|       password, | ||||
|       salt, | ||||
|       _keyBytesCount, | ||||
|       _iterations, | ||||
|       Utils.enumToStr(_hash), | ||||
|     )) ?? Uint8List(0); | ||||
| 
 | ||||
|     return SecretKey(derivation); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										20
									
								
								native_crypto/lib/src/key.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								native_crypto/lib/src/key.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: key.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 28/12/2021 13:37:50 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'byte_array.dart'; | ||||
| 
 | ||||
| /// A class representing a key. | ||||
| class Key extends ByteArray { | ||||
|   Key(Uint8List bytes) : super(bytes); | ||||
|   Key.fromBase16(String encoded) : super.fromBase16(encoded); | ||||
|   Key.fromBase64(String encoded) : super.fromBase64(encoded); | ||||
|   Key.fromUtf8(String input) : super.fromUtf8(input); | ||||
| } | ||||
							
								
								
									
										21
									
								
								native_crypto/lib/src/keyderivation.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								native_crypto/lib/src/keyderivation.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: kdf.dart | ||||
| // Created Date: 18/12/2021 11:56:43 | ||||
| // Last Modified: 28/12/2021 13:38:02 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import './keys/secret_key.dart'; | ||||
| 
 | ||||
| enum KdfAlgorithm { pbkdf2 } | ||||
| 
 | ||||
| /// Represents a Key Derivation Function | ||||
| abstract class KeyDerivation { | ||||
|   /// Returns the standard algorithm name for this key derivation function | ||||
|   KdfAlgorithm get algorithm; | ||||
| 
 | ||||
|   /// Derive key | ||||
|   Future<SecretKey> derive(); | ||||
| } | ||||
							
								
								
									
										36
									
								
								native_crypto/lib/src/keys/secret_key.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								native_crypto/lib/src/keys/secret_key.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: secret_key.dart | ||||
| // Created Date: 28/12/2021 13:36:54 | ||||
| // Last Modified: 28/12/2021 13:37:45 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:flutter/services.dart'; | ||||
| 
 | ||||
| import '../exceptions.dart'; | ||||
| import '../key.dart'; | ||||
| import '../platform.dart'; | ||||
| 
 | ||||
| /// A class representing a secret key. | ||||
| /// A secret key is a key that is not accessible by anyone else. | ||||
| /// It is used to encrypt and decrypt data. | ||||
| class SecretKey extends Key { | ||||
|   SecretKey(Uint8List bytes) : super(bytes); | ||||
|   SecretKey.fromBase16(String encoded) : super.fromBase16(encoded); | ||||
|   SecretKey.fromBase64(String encoded) : super.fromBase64(encoded); | ||||
|   SecretKey.fromUtf8(String input) : super.fromUtf8(input); | ||||
| 
 | ||||
|   static Future<SecretKey> fromSecureRandom(int bitsCount) async { | ||||
|     try { | ||||
|       Uint8List _key = (await platform.generateSecretKey(bitsCount)) ?? Uint8List(0); | ||||
|        | ||||
|       return SecretKey(_key); | ||||
|     } on PlatformException catch (e) { | ||||
|       throw KeyException(e); | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										12
									
								
								native_crypto/lib/src/platform.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								native_crypto/lib/src/platform.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: platform.dart | ||||
| // Created Date: 27/12/2021 22:03:58 | ||||
| // Last Modified: 27/12/2021 22:04:30 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; | ||||
| 
 | ||||
| NativeCryptoPlatform platform = NativeCryptoPlatform.instance; | ||||
							
								
								
									
										83
									
								
								native_crypto/lib/src/utils.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								native_crypto/lib/src/utils.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,83 @@ | ||||
| // Author: Hugo Pointcheval | ||||
| // Email: git@pcl.ovh | ||||
| // ----- | ||||
| // File: utils.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 27/12/2021 22:04:07 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'cipher.dart'; | ||||
| import 'exceptions.dart'; | ||||
| import 'hasher.dart'; | ||||
| import 'keyderivation.dart'; | ||||
| 
 | ||||
| class Utils { | ||||
|   /// Returns enum value to string, without the enum name | ||||
|   static String enumToStr(dynamic enumValue) { | ||||
|     return enumValue.toString().split('.').last; | ||||
|   } | ||||
| 
 | ||||
|   /// Returns enum list as string list | ||||
|   static List<String> enumToList<T>(List<T> enumValues) { | ||||
|     List<String> _res = []; | ||||
|     for (T enumValue in enumValues) { | ||||
|       _res.add(enumToStr(enumValue)); | ||||
|     } | ||||
|      | ||||
|     return _res; | ||||
|   } | ||||
| 
 | ||||
|   /// Returns enum from string | ||||
|   static T strToEnum<T>(String str, List<T> enumValues) { | ||||
|     for (T enumValue in enumValues) { | ||||
|       if (enumToStr(enumValue) == str) { | ||||
|         return enumValue; | ||||
|       } | ||||
|     } | ||||
|     throw UtilsException('Invalid enum value: $str'); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns [HashAlgorithm] from his name. | ||||
|   static HashAlgorithm getHashAlgorithm(String algorithm) { | ||||
|     return strToEnum<HashAlgorithm>(algorithm.toLowerCase(), HashAlgorithm.values); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns all available [HashAlgorithm] as String list | ||||
|   static List<String> getAvailableHashAlgorithms() { | ||||
|     return enumToList<HashAlgorithm>(HashAlgorithm.values); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns [KdfAlgorithm] from his name. | ||||
|   static KdfAlgorithm getKdfAlgorithm(String algorithm) { | ||||
|     return strToEnum<KdfAlgorithm>(algorithm.toLowerCase(), KdfAlgorithm.values); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns all available [KdfAlgorithm] as String list | ||||
|   static List<String> getAvailableKdfAlgorithms() { | ||||
|     return enumToList<KdfAlgorithm>(KdfAlgorithm.values); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns [CipherAlgorithm] from his name. | ||||
|   static CipherAlgorithm getCipherAlgorithm(String algorithm) { | ||||
|     return strToEnum<CipherAlgorithm>(algorithm.toLowerCase(), CipherAlgorithm.values); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns all available [CipherAlgorithm] as String list | ||||
|   static List<String> getAvailableCipherAlgorithms() { | ||||
|     return enumToList<CipherAlgorithm>(CipherAlgorithm.values); | ||||
|   } | ||||
| 
 | ||||
|  static  Uint8List decodeHexString(String input) { | ||||
|     assert(input.length % 2 == 0, 'Input needs to be an even length.'); | ||||
| 
 | ||||
|     return Uint8List.fromList( | ||||
|       List.generate( | ||||
|         input.length ~/ 2, | ||||
|         (i) => int.parse(input.substring(i * 2, (i * 2) + 2), radix: 16), | ||||
|       ).toList(), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| name: native_crypto | ||||
| description: Fast and secure cryptography for Flutter. | ||||
| version: 0.0.7 | ||||
| version: 0.1.0 | ||||
| publish_to: 'none' | ||||
| 
 | ||||
| environment: | ||||
| @ -11,9 +11,15 @@ dependencies: | ||||
|   flutter: | ||||
|     sdk: flutter | ||||
|    | ||||
|   native_crypto_android: | ||||
|     path: ../native_crypto_android | ||||
| 
 | ||||
|   native_crypto_ios: | ||||
|     path: ../native_crypto_ios | ||||
| 
 | ||||
|   native_crypto_platform_interface: | ||||
|     path: ../native_crypto_platform_interface | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|     sdk: flutter | ||||
| @ -22,7 +28,7 @@ dev_dependencies: | ||||
| flutter: | ||||
|   plugin: | ||||
|     platforms: | ||||
|       # android: | ||||
|       #   default_package: native_crypto_android | ||||
|       android: | ||||
|         default_package: native_crypto_android | ||||
|       ios: | ||||
|         default_package: native_crypto_ios | ||||
| @ -1,23 +1 @@ | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:flutter_test/flutter_test.dart'; | ||||
| import 'package:native_crypto/native_crypto.dart'; | ||||
| 
 | ||||
| void main() { | ||||
|   const MethodChannel channel = MethodChannel('native_crypto'); | ||||
| 
 | ||||
|   TestWidgetsFlutterBinding.ensureInitialized(); | ||||
| 
 | ||||
|   setUp(() { | ||||
|     channel.setMockMethodCallHandler((MethodCall methodCall) async { | ||||
|       return '42'; | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   tearDown(() { | ||||
|     channel.setMockMethodCallHandler(null); | ||||
|   }); | ||||
| 
 | ||||
|   test('getPlatformVersion', () async { | ||||
|     expect(await NativeCrypto.platformVersion, '42'); | ||||
|   }); | ||||
| } | ||||
| // TODO | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user