diff --git a/README.md b/README.md index 2234be8..baf7c92 100644 --- a/README.md +++ b/README.md @@ -1,155 +1,149 @@ -# NativeCrypto - -![native_crypto](/assets/native_crypto.png) - -Fast crypto functions for Flutter. - -* Table of content - * [Background](#background) - * [Performances](#performances) - * [Installation](#installation) - * [Usage](#usage) - * [Example](#example) - * [How](#how) - * [Todo](#todo) - -## Background - -🤔 Why I started this project ? -Because I faced a performance issue when I was using **PointyCastle**. - -It's quite simple, judge for yourself, these are times for AES256 encryption on an Android device (**Huawei P30 Pro**). - -| Size | PointyCastle | -|------|--------------| -| 100 kB | 190 ms -| 200 kB | 314 ms -| 300 kB | 1138 ms -| 400 kB | 2781 ms -| 500 kB | 4691 ms -| 600 kB | 7225 ms -| 700 kB | 10264 ms -| 800 kB | 13582 ms -| 900 kB | 17607 ms - -> We notice that these times, in addition to being far too big, are **not even linear**. - -## Performances - -⏱ On an **Android 10** device: **Huawei P30 Pro** - -| Size | NativeCrypto | -|------|--------------| -| 1 mB | 27 ms -| 2 mB | 43 ms -| 3 mB | 78 ms -| 4 mB | 93 ms -| 5 mB | 100 ms -| 10 mB | 229 ms -| 50 mB | 779 ms - -## Installation - -🚧 You can easely setup a Flutter project with this plugin. - -Just add these lines in your **pubspec.yaml**: - -```yaml -native_crypto: - git: - url: https://gogs.pointcheval.fr/hugo/native-crypto-flutter.git - ref: v0.0.x -``` - -> Replace "x" with the current version! - -Then in your code: - -```dart -// Symmetric crypto. -import 'package:native_crypto/symmetric_crypto.dart'; - -// To handle exceptions. -import 'package:native_crypto/exceptions.dart'; -``` - -## Usage - -To create an AES instance, and generate a key. - -```dart -AES aes = AES(); -await aes.init(KeySize.bits256) -``` - -You can also generate key, then use it in AES. - -```dart -Uint8List aeskey = await KeyGenerator().secretKey(keySize: KeySize.bits256); -AES aes = AES(key: aeskey); -``` - -You can create a key with PBKDF2. - -```dart -Uint8List key = await KeyGenerator().pbkdf2(password, salt, keyLength: 32, iteration: 10000, digest: Digest.sha256); -AES aes = AES(key: key); -``` - -Then you can encrypt/decrypt data with this instance. - -```dart -encryptedPayload = await aes.encrypt(data); -decryptedPayload = await aes.decrypt(encryptedPayload); -``` - -Or you can also use AES on the fly with different keys. - -```dart -Uint8List aeskey = await KeyGenerator().secretKey(keySize: KeySize.bits256); -encryptedPayload = await AES().encrypt(data, key: aeskey); -decryptedPayload = await AES().decrypt(encryptedPayload, key: aeskey); -``` - -Available `enums` are: - -```dart -enum KeySize { bits128, bits192, bits256 } -enum Digest { sha1, sha256, sha512 } -``` - -`KeySizes` defines all available key sizes for generation. - -`Digest` defines all available digest for PBKDF2. - -## Example - -🔍 Look in **example/lib/** for an example app. - -## How - -🔬 But how it is possible ?? - -Using the native implementation of crypto libs available on each OS. - -For **Android**: - -* [javax.crypto](https://docs.oracle.com/javase/7/docs/api/javax/crypto/package-summary.html) -* [java.security](https://docs.oracle.com/javase/7/docs/api/java/security/package-summary.html) - -For **iOS**: - -* [CommonCrypto](https://developer.apple.com/library/archive/documentation/Security/Conceptual/cryptoservices/Introduction/Introduction.html) - -## Todos - -🚀 You can contribute to this project. - -* [x] Implement working cross platform AES encryption/decryption. -* [x] Different key sizes support. -* [x] Improve performances. -* [x] Add exceptions. -* [x] PBKDF2 support. -* [ ] Add other ciphers. -* [ ] Clean platform specific code. -* [ ] Add asym crypto support... +# NativeCrypto for Flutter + +[![NativeCrypto Logo](/assets/native_crypto.png)](https://hugo.pointcheval.fr/) +--- + +Fast and powerful cryptographic functions thanks to **javax.crypto** and **CommonCrypto**. + +## 📝 Table of Contents + +- [About](#about) +- [Getting Started](#getting_started) +- [Example](#example) +- [Usage](#usage) +- [Built Using](#built_using) +- [Authors](#authors) + +## 🧐 About + +The goal of this plugin is to provide simple access to fast and powerful cryptographic functions by calling native libraries. So on **Android** the plugin uses *javax.crypto* and on **iOS** it uses *CommonCrypto*. + +I started this project because using **Pointy Castle** I faced big performance issues on smartphone. It's quite simple, an encryption of 1MB of data in AES256 on an Android device takes **20s** with Pointy Castle against **27ms** using NativeCrypto. + +![Pointy Castle Benchmark](/assets/benchmark_pointycastle.png) + +> We also notice on this benchmark that the AES encryption time does not even increase linearly with size. + +As for NativeCrypto, here is a benchmark realized on an Android device, Huawei P30 Pro. + +| Size (kB) | NativeCrypto **encryption** time (ms) | +|-----------|---------------------------------------| +| 1 mB | 27 ms +| 2 mB | 43 ms +| 3 mB | 78 ms +| 4 mB | 93 ms +| 5 mB | 100 ms +| 10 mB | 229 ms +| 50 mB | 779 ms + +> Less than 1s for 50 mB. + +In short, **NativeCrypto** is incomparable to **Pointy Castle** in terms of performance. + +## 🏁 Getting Started + + + + + +### Prerequisites + +You'll need: + +- Flutter + +### Installing + +Add these lines in your **pubspec.yaml**: + +```yaml +native_crypto: + git: + url: https://gogs.pointcheval.fr/hugo/native-crypto-flutter.git + ref: v0.0.x +``` + +> Replace "x" with the current version! + +Then in your code: + +```dart +import 'package:native_crypto/native_crypto.dart'; +``` + +## 🔍 Example + +Look in **example/lib/** for an example app. + +## 🎈 Usage + +To derive a key with **PBKDF2**. + +```dart +PBKDF2 _pbkdf2 = PBKDF2(keyLength: 32, iteration: 1000, hash: HashAlgorithm.SHA512); +await _pbkdf2.derive(password: "password123", salt: 'salty'); +SecretKey key = _pbkdf2.key; +``` + +To generate a key, and create an **AES Cipher** instance. + +```dart +AESCipher aes = await AESCipher.generate( + AESKeySize.bits256, + CipherParameters( + BlockCipherMode.CBC, + PlainTextPadding.PKCS5, + ), +); +``` + +You can also generate key, then create **AES Cipher**. + +```dart +SecretKey _key = await SecretKey.generate(256, CipherAlgorithm.AES); +AESCipher aes = AESCipher( + _key, + CipherParameters( + BlockCipherMode.CBC, + PlainTextPadding.PKCS5, + ), +); +``` + +Then you can encrypt/decrypt data with this cipher. + +```dart +CipherText cipherText = await aes.encrypt(data); +Uint8List plainText = await aes.decrypt(cipherText); +``` + +You can easely get encrypted bytes and IV from a CipherText + +```dart +Uint8List bytes = cipherText.bytes; +Uint8List iv = cipherText.iv; +``` + +To create a cipher text with custom data. + +```dart +CipherText cipherText = AESCipherText(bytes, iv); +``` + +To create a hashed message + +```dart +MessageDigest md = MessageDigest.getInstance("sha256"); +Uint8List hash = md.digest(message); +``` + +## ⛏️ Built Using + +- [Dart](https://dart.dev) +- [Flutter](https://flutter.dev) - Framework +- [Kotlin](https://kotlinlang.org) - Android Specific code +- [Swift](https://www.apple.com/fr/swift/) - iOS Specific code + +## ✍️ Authors + +- [Hugo Pointcheval](https://github.com/hugo-pcl) - Idea & Initial work diff --git a/assets/benchmark_pointycastle.png b/assets/benchmark_pointycastle.png new file mode 100644 index 0000000..0f35735 Binary files /dev/null and b/assets/benchmark_pointycastle.png differ diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id new file mode 100644 index 0000000..cadd42b --- /dev/null +++ b/example/ios/Flutter/.last_build_id @@ -0,0 +1 @@ +2f8ea5763cdbee83dd665ad298f0e380 \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d983a6a..7cee235 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -19,4 +19,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 61d0a1d..5d6a587 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,11 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -27,8 +23,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,13 +34,11 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2DBF05A146610778D425B9D9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -62,8 +54,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, D294241BEFD2D3EF500C0577 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -82,9 +72,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -230,7 +218,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -319,7 +307,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -396,7 +383,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -452,7 +438,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/pubspec.yaml b/pubspec.yaml index 03d189f..0914ca9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: native_crypto description: Fast crypto functions for Flutter. -version: 0.0.4+1 +version: 0.0.5+1 author: Hugo Pointcheval homepage: https://hugo.pointcheval.fr