Compare commits
No commits in common. "9e0d921564b41f6a209e9beedace6c9f7d210595" and "9160338e7ac38e48ad5596a8eab2fb8d413c65f5" have entirely different histories.
9e0d921564
...
9160338e7a
318
native_crypto_ios/.gitignore → .gitignore
vendored
@ -1,7 +1,107 @@
|
|||||||
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,dart,flutter,intellij+all,kotlin,linux,swift,windows
|
# Created by https://www.gitignore.io/api/windows,visualstudiocode,android,androidstudio,cocoapods,dart,flutter,intellij+all,kotlin,macos,swift,xcode,xcodeinjection
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,dart,flutter,intellij+all,kotlin,linux,swift,windows
|
# Edit at https://www.gitignore.io/?templates=windows,visualstudiocode,android,androidstudio,cocoapods,dart,flutter,intellij+all,kotlin,macos,swift,xcode,xcodeinjection
|
||||||
|
|
||||||
|
### Android ###
|
||||||
|
# Built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
*.aab
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
out/
|
||||||
|
release/
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
proguard/
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Android Studio Navigation editor temp files
|
||||||
|
.navigation/
|
||||||
|
|
||||||
|
# Android Studio captures folder
|
||||||
|
captures/
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
*.iml
|
||||||
|
.idea/workspace.xml
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/gradle.xml
|
||||||
|
.idea/assetWizardSettings.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
.idea/libraries
|
||||||
|
# Android Studio 3 in .gitignore file.
|
||||||
|
.idea/caches
|
||||||
|
.idea/modules.xml
|
||||||
|
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||||
|
.idea/navEditor.xml
|
||||||
|
|
||||||
|
# Keystore files
|
||||||
|
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||||
|
#*.jks
|
||||||
|
#*.keystore
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
.externalNativeBuild
|
||||||
|
|
||||||
|
# Google Services (e.g. APIs or Firebase)
|
||||||
|
# google-services.json
|
||||||
|
|
||||||
|
# Freeline
|
||||||
|
freeline.py
|
||||||
|
freeline/
|
||||||
|
freeline_project_description.json
|
||||||
|
|
||||||
|
# fastlane
|
||||||
|
fastlane/report.xml
|
||||||
|
fastlane/Preview.html
|
||||||
|
fastlane/screenshots
|
||||||
|
fastlane/test_output
|
||||||
|
fastlane/readme.md
|
||||||
|
|
||||||
|
# Version control
|
||||||
|
vcs.xml
|
||||||
|
|
||||||
|
# lint
|
||||||
|
lint/intermediates/
|
||||||
|
lint/generated/
|
||||||
|
lint/outputs/
|
||||||
|
lint/tmp/
|
||||||
|
# lint/reports/
|
||||||
|
|
||||||
|
### Android Patch ###
|
||||||
|
gen-external-apklibs
|
||||||
|
output.json
|
||||||
|
|
||||||
|
# Replacement of .externalNativeBuild directories introduced
|
||||||
|
# with Android Studio 3.5.
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
### CocoaPods ###
|
||||||
|
## CocoaPods GitIgnore Template
|
||||||
|
|
||||||
|
# CocoaPods - Only use to conserve bandwidth / Save time on Pushing
|
||||||
|
# - Also handy if you have a large number of dependant pods
|
||||||
|
# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
|
||||||
|
Pods/
|
||||||
|
|
||||||
### Dart ###
|
### Dart ###
|
||||||
# See https://www.dartlang.org/guides/libraries/private-files
|
# See https://www.dartlang.org/guides/libraries/private-files
|
||||||
@ -9,7 +109,6 @@
|
|||||||
# Files and directories created by pub
|
# Files and directories created by pub
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.packages
|
.packages
|
||||||
build/
|
|
||||||
# If you're building an application, you may want to check-in your pubspec.lock
|
# If you're building an application, you may want to check-in your pubspec.lock
|
||||||
pubspec.lock
|
pubspec.lock
|
||||||
|
|
||||||
@ -17,9 +116,6 @@ pubspec.lock
|
|||||||
# If you don't generate documentation locally you can remove this line.
|
# If you don't generate documentation locally you can remove this line.
|
||||||
doc/api/
|
doc/api/
|
||||||
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env*
|
|
||||||
|
|
||||||
# Avoid committing generated Javascript files:
|
# Avoid committing generated Javascript files:
|
||||||
*.dart.js
|
*.dart.js
|
||||||
*.info.json # Produced by the --dump-info flag.
|
*.info.json # Produced by the --dump-info flag.
|
||||||
@ -29,25 +125,13 @@ doc/api/
|
|||||||
*.js.deps
|
*.js.deps
|
||||||
*.js.map
|
*.js.map
|
||||||
|
|
||||||
.flutter-plugins
|
|
||||||
.flutter-plugins-dependencies
|
|
||||||
|
|
||||||
### Dart Patch ###
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env
|
|
||||||
|
|
||||||
### Flutter ###
|
### Flutter ###
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
.fvm/
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
.pub-cache/
|
.pub-cache/
|
||||||
.pub/
|
.pub/
|
||||||
coverage/
|
|
||||||
lib/generated_plugin_registrant.dart
|
|
||||||
# For library packages, don’t commit the pubspec.lock file.
|
|
||||||
# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.
|
|
||||||
# See https://dart.dev/guides/libraries/private-files#pubspeclock
|
|
||||||
#pubspec.lock
|
|
||||||
|
|
||||||
# Android related
|
# Android related
|
||||||
**/android/**/gradle-wrapper.jar
|
**/android/**/gradle-wrapper.jar
|
||||||
@ -55,7 +139,6 @@ lib/generated_plugin_registrant.dart
|
|||||||
**/android/captures/
|
**/android/captures/
|
||||||
**/android/gradlew
|
**/android/gradlew
|
||||||
**/android/gradlew.bat
|
**/android/gradlew.bat
|
||||||
**/android/key.properties
|
|
||||||
**/android/local.properties
|
**/android/local.properties
|
||||||
**/android/**/GeneratedPluginRegistrant.java
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
@ -76,15 +159,12 @@ lib/generated_plugin_registrant.dart
|
|||||||
**/ios/**/profile
|
**/ios/**/profile
|
||||||
**/ios/**/xcuserdata
|
**/ios/**/xcuserdata
|
||||||
**/ios/.generated/
|
**/ios/.generated/
|
||||||
**/ios/Flutter/.last_build_id
|
|
||||||
**/ios/Flutter/App.framework
|
**/ios/Flutter/App.framework
|
||||||
**/ios/Flutter/Flutter.framework
|
**/ios/Flutter/Flutter.framework
|
||||||
**/ios/Flutter/Flutter.podspec
|
|
||||||
**/ios/Flutter/Generated.xcconfig
|
**/ios/Flutter/Generated.xcconfig
|
||||||
**/ios/Flutter/app.flx
|
**/ios/Flutter/app.flx
|
||||||
**/ios/Flutter/app.zip
|
**/ios/Flutter/app.zip
|
||||||
**/ios/Flutter/flutter_assets/
|
**/ios/Flutter/flutter_assets/
|
||||||
**/ios/Flutter/flutter_export_environment.sh
|
|
||||||
**/ios/ServiceDefinitions.json
|
**/ios/ServiceDefinitions.json
|
||||||
**/ios/Runner/GeneratedPluginRegistrant.*
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
@ -96,7 +176,7 @@ lib/generated_plugin_registrant.dart
|
|||||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
|
||||||
### Intellij+all ###
|
### Intellij+all ###
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
# User-specific stuff
|
# User-specific stuff
|
||||||
@ -106,9 +186,6 @@ lib/generated_plugin_registrant.dart
|
|||||||
.idea/**/dictionaries
|
.idea/**/dictionaries
|
||||||
.idea/**/shelf
|
.idea/**/shelf
|
||||||
|
|
||||||
# AWS User-specific
|
|
||||||
.idea/**/aws.xml
|
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
.idea/**/contentModel.xml
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
@ -129,9 +206,6 @@ lib/generated_plugin_registrant.dart
|
|||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
# auto-import.
|
# auto-import.
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
# .idea/modules.xml
|
||||||
# .idea/*.iml
|
# .idea/*.iml
|
||||||
# .idea/modules
|
# .idea/modules
|
||||||
@ -148,7 +222,6 @@ cmake-build-*/
|
|||||||
*.iws
|
*.iws
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
# mpeltonen/sbt-idea plugin
|
||||||
.idea_modules/
|
.idea_modules/
|
||||||
@ -179,7 +252,6 @@ fabric.properties
|
|||||||
|
|
||||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||||
|
|
||||||
*.iml
|
|
||||||
modules.xml
|
modules.xml
|
||||||
.idea/misc.xml
|
.idea/misc.xml
|
||||||
*.ipr
|
*.ipr
|
||||||
@ -189,10 +261,8 @@ modules.xml
|
|||||||
|
|
||||||
### Kotlin ###
|
### Kotlin ###
|
||||||
# Compiled class file
|
# Compiled class file
|
||||||
*.class
|
|
||||||
|
|
||||||
# Log file
|
# Log file
|
||||||
*.log
|
|
||||||
|
|
||||||
# BlueJ files
|
# BlueJ files
|
||||||
*.ctxt
|
*.ctxt
|
||||||
@ -212,21 +282,6 @@ modules.xml
|
|||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
|
||||||
### Linux ###
|
|
||||||
*~
|
|
||||||
|
|
||||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
|
||||||
.fuse_hidden*
|
|
||||||
|
|
||||||
# KDE directory preferences
|
|
||||||
.directory
|
|
||||||
|
|
||||||
# Linux trash folder which might appear on any partition or disk
|
|
||||||
.Trash-*
|
|
||||||
|
|
||||||
# .nfs files are created when an open file is removed but is still being accessed
|
|
||||||
.nfs*
|
|
||||||
|
|
||||||
### macOS ###
|
### macOS ###
|
||||||
# General
|
# General
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@ -236,7 +291,6 @@ hs_err_pid*
|
|||||||
# Icon must end with two \r
|
# Icon must end with two \r
|
||||||
Icon
|
Icon
|
||||||
|
|
||||||
|
|
||||||
# Thumbnails
|
# Thumbnails
|
||||||
._*
|
._*
|
||||||
|
|
||||||
@ -261,16 +315,10 @@ Temporary Items
|
|||||||
#
|
#
|
||||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||||
|
|
||||||
## User settings
|
## Build generated
|
||||||
xcuserdata/
|
|
||||||
|
|
||||||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
|
||||||
*.xcscmblueprint
|
|
||||||
*.xccheckout
|
|
||||||
|
|
||||||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
|
||||||
DerivedData/
|
DerivedData/
|
||||||
*.moved-aside
|
|
||||||
|
## Various settings
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
!default.pbxuser
|
!default.pbxuser
|
||||||
*.mode1v3
|
*.mode1v3
|
||||||
@ -279,11 +327,15 @@ DerivedData/
|
|||||||
!default.mode2v3
|
!default.mode2v3
|
||||||
*.perspectivev3
|
*.perspectivev3
|
||||||
!default.perspectivev3
|
!default.perspectivev3
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
## Other
|
||||||
|
*.moved-aside
|
||||||
|
*.xccheckout
|
||||||
|
*.xcscmblueprint
|
||||||
|
|
||||||
## Obj-C/Swift specific
|
## Obj-C/Swift specific
|
||||||
*.hmap
|
*.hmap
|
||||||
|
|
||||||
## App packaging
|
|
||||||
*.ipa
|
*.ipa
|
||||||
*.dSYM.zip
|
*.dSYM.zip
|
||||||
*.dSYM
|
*.dSYM
|
||||||
@ -297,12 +349,9 @@ playground.xcworkspace
|
|||||||
# Packages/
|
# Packages/
|
||||||
# Package.pins
|
# Package.pins
|
||||||
# Package.resolved
|
# Package.resolved
|
||||||
# *.xcodeproj
|
|
||||||
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
|
|
||||||
# hence it is not needed unless you have added a package configuration file to your project
|
|
||||||
# .swiftpm
|
|
||||||
|
|
||||||
.build/
|
.build/
|
||||||
|
# Add this line if you want to avoid checking in Xcode SPM integration.
|
||||||
|
# .swiftpm/xcode
|
||||||
|
|
||||||
# CocoaPods
|
# CocoaPods
|
||||||
# We recommend against adding the Pods directory to your .gitignore. However
|
# We recommend against adding the Pods directory to your .gitignore. However
|
||||||
@ -316,22 +365,19 @@ playground.xcworkspace
|
|||||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||||
# Carthage/Checkouts
|
# Carthage/Checkouts
|
||||||
|
|
||||||
Carthage/Build/
|
Carthage/Build
|
||||||
|
|
||||||
# Accio dependency management
|
# Accio dependency management
|
||||||
Dependencies/
|
Dependencies/
|
||||||
.accio/
|
.accio/
|
||||||
|
|
||||||
# fastlane
|
# fastlane
|
||||||
# It is recommended to not store the screenshots in the git repo.
|
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||||
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
|
# screenshots whenever they are needed.
|
||||||
# For more information about the recommended setup visit:
|
# For more information about the recommended setup visit:
|
||||||
# https://docs.fastlane.tools/best-practices/source-control/#source-control
|
# https://docs.fastlane.tools/best-practices/source-control/#source-control
|
||||||
|
|
||||||
fastlane/report.xml
|
|
||||||
fastlane/Preview.html
|
|
||||||
fastlane/screenshots/**/*.png
|
fastlane/screenshots/**/*.png
|
||||||
fastlane/test_output
|
|
||||||
|
|
||||||
# Code Injection
|
# Code Injection
|
||||||
# After new code Injection tools there's a generated folder /iOSInjectionProject
|
# After new code Injection tools there's a generated folder /iOSInjectionProject
|
||||||
@ -340,23 +386,16 @@ fastlane/test_output
|
|||||||
iOSInjectionProject/
|
iOSInjectionProject/
|
||||||
|
|
||||||
### VisualStudioCode ###
|
### VisualStudioCode ###
|
||||||
|
.vscode
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
*.code-workspace
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
### VisualStudioCode Patch ###
|
### VisualStudioCode Patch ###
|
||||||
# Ignore all local history of files
|
# Ignore all local history of files
|
||||||
.history
|
.history
|
||||||
.ionide
|
|
||||||
|
|
||||||
# Support for Project snippet scope
|
|
||||||
!.vscode/*.code-snippets
|
|
||||||
|
|
||||||
### Windows ###
|
### Windows ###
|
||||||
# Windows thumbnail cache files
|
# Windows thumbnail cache files
|
||||||
@ -384,7 +423,122 @@ $RECYCLE.BIN/
|
|||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,dart,flutter,intellij+all,kotlin,linux,swift,windows
|
### Xcode ###
|
||||||
|
# Xcode
|
||||||
|
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||||
|
|
||||||
|
## User settings
|
||||||
|
|
||||||
|
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
||||||
|
|
||||||
|
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
||||||
|
|
||||||
|
## Xcode Patch
|
||||||
|
*.xcodeproj/*
|
||||||
|
!*.xcodeproj/project.pbxproj
|
||||||
|
!*.xcodeproj/xcshareddata/
|
||||||
|
!*.xcworkspace/contents.xcworkspacedata
|
||||||
|
/*.gcno
|
||||||
|
|
||||||
|
### Xcode Patch ###
|
||||||
|
**/xcshareddata/WorkspaceSettings.xcsettings
|
||||||
|
|
||||||
|
### XcodeInjection ###
|
||||||
|
# Code Injection
|
||||||
|
# After new code Injection tools there's a generated folder /iOSInjectionProject
|
||||||
|
# https://github.com/johnno1962/injectionforxcode
|
||||||
|
|
||||||
|
|
||||||
|
### AndroidStudio ###
|
||||||
|
# Covers files to be ignored for android development using Android Studio.
|
||||||
|
|
||||||
|
# Built application files
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle
|
||||||
|
|
||||||
|
# Signing files
|
||||||
|
.signing/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
/*/build/
|
||||||
|
/*/local.properties
|
||||||
|
/*/out
|
||||||
|
/*/*/build
|
||||||
|
/*/*/production
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Android Patch
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
|
||||||
|
# NDK
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# IntelliJ IDEA
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# User-specific configurations
|
||||||
|
.idea/caches/
|
||||||
|
.idea/libraries/
|
||||||
|
.idea/shelf/
|
||||||
|
.idea/.name
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/copyright/profiles_settings.xml
|
||||||
|
.idea/encodings.xml
|
||||||
|
.idea/scopes/scope_settings.xml
|
||||||
|
.idea/vcs.xml
|
||||||
|
.idea/jsLibraryMappings.xml
|
||||||
|
.idea/datasources.xml
|
||||||
|
.idea/dataSources.ids
|
||||||
|
.idea/sqlDataSources.xml
|
||||||
|
.idea/dynamic.xml
|
||||||
|
.idea/uiDesigner.xml
|
||||||
|
|
||||||
|
# OS-specific files
|
||||||
|
.DS_Store?
|
||||||
|
|
||||||
|
# Legacy Eclipse project files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
|
||||||
|
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/mongoSettings.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
|
||||||
|
### AndroidStudio Patch ###
|
||||||
|
|
||||||
|
!/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/windows,visualstudiocode,android,androidstudio,cocoapods,dart,flutter,intellij+all,kotlin,macos,swift,xcode,xcodeinjection
|
||||||
|
|
||||||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||||
|
|
@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: cf4400006550b70f28e4b4af815151d1e74846c6
|
revision: f139b11009aeb8ed2a3a3aa8b0066e482709dde3
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
project_type: plugin
|
project_type: plugin
|
25
CHANGELOG.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
## 0.0.6
|
||||||
|
|
||||||
|
**WIP...**
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
* First AES cross-platform encryption & decryption implementation.
|
@ -1,4 +1,4 @@
|
|||||||
NativeCrypto - iOS Implementation
|
native_crypto
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
170
README.md
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# NativeCrypto for Flutter
|
||||||
|
|
||||||
|

|
||||||
|
---
|
||||||
|
|
||||||
|
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)
|
||||||
|
- [TODOS](#todos)
|
||||||
|
- [Authors](#authors)
|
||||||
|
|
||||||
|
## 🧐 About <a name = "about"></a>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> 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 <a name = "getting_started"></a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 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 <a name="example"></a>
|
||||||
|
|
||||||
|
Look in **example/lib/** for an example app.
|
||||||
|
|
||||||
|
## 🎈 Usage <a name="usage"></a>
|
||||||
|
|
||||||
|
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 = await md.digest(message);
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⛏️ Built Using <a name = "built_using"></a>
|
||||||
|
|
||||||
|
- [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
|
||||||
|
|
||||||
|
## 🚀 TODOS <a name = "todos">
|
||||||
|
|
||||||
|
Here you can check major changes, roadmap and todos.
|
||||||
|
|
||||||
|
Once the **BlowFish algorithm** is exposed on Android and iOS, I plan to deal with asymmetric cryptography with the implementation of a Key Encapsulation Mechanism.
|
||||||
|
|
||||||
|
- [x] Add PBKDF2 support.
|
||||||
|
- [x] Implement working cross platform AES encryption/decryption.
|
||||||
|
- [x] Add Different key sizes support.
|
||||||
|
- [x] Add exceptions.
|
||||||
|
- [x] Clean platform specific code.
|
||||||
|
- [x] Add digest.
|
||||||
|
- [x] Rework exposed API.
|
||||||
|
- [ ] Implement BlowFish.
|
||||||
|
- [ ] Add KeyPair generation.
|
||||||
|
- [ ] Add KEM.
|
||||||
|
- [ ] Porting NativeCrypto to other platforms...
|
||||||
|
|
||||||
|
You can contribute to this project.
|
||||||
|
|
||||||
|
## ✍️ Authors <a name = "authors"></a>
|
||||||
|
|
||||||
|
- [Hugo Pointcheval](https://github.com/hugo-pcl) - Idea & Initial work
|
8
android/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
44
android/build.gradle
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
group 'fr.pointcheval.native_crypto'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.3.50'
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 29
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 16
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.enableR8=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
@ -1,6 +1,5 @@
|
|||||||
#Fri Jun 23 08:50:38 CEST 2017
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
1
android/settings.gradle
Normal file
@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'native_crypto'
|
3
android/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="fr.pointcheval.native_crypto">
|
||||||
|
</manifest>
|
@ -0,0 +1,93 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
enum class CipherAlgorithm(val spec: String) {
|
||||||
|
AES("AES"),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class BlockCipherMode(val instance: String) {
|
||||||
|
CBC("CBC"),
|
||||||
|
GCM("GCM"),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Padding(val instance: String) {
|
||||||
|
PKCS5("PKCS5Padding"),
|
||||||
|
None("NoPadding")
|
||||||
|
}
|
||||||
|
|
||||||
|
class CipherParameters(private val mode: BlockCipherMode, private val padding: Padding) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return mode.instance + "/" + padding.instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cipher {
|
||||||
|
|
||||||
|
fun getCipherAlgorithm(dartAlgorithm: String) : CipherAlgorithm {
|
||||||
|
return when (dartAlgorithm) {
|
||||||
|
"aes" -> CipherAlgorithm.AES
|
||||||
|
else -> CipherAlgorithm.AES
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInstance(mode : String, padding : String) : CipherParameters {
|
||||||
|
val m = when (mode) {
|
||||||
|
"cbc" -> BlockCipherMode.CBC
|
||||||
|
"gcm" -> BlockCipherMode.GCM
|
||||||
|
else -> throw Exception()
|
||||||
|
}
|
||||||
|
val p = when (padding) {
|
||||||
|
"pkcs5" -> Padding.PKCS5
|
||||||
|
else -> Padding.None
|
||||||
|
}
|
||||||
|
return CipherParameters(m,p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun encrypt(data: ByteArray, key: ByteArray, algorithm: String, mode: String, padding: String) : List<ByteArray> {
|
||||||
|
val algo = getCipherAlgorithm(algorithm)
|
||||||
|
val params = getInstance(mode, padding)
|
||||||
|
|
||||||
|
val keySpecification = algo.spec + "/" + params.toString()
|
||||||
|
|
||||||
|
val mac = Hash().digest(key + data)
|
||||||
|
val sk: SecretKey = SecretKeySpec(key, algo.spec)
|
||||||
|
|
||||||
|
val cipher = Cipher.getInstance(keySpecification)
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, sk)
|
||||||
|
|
||||||
|
val encryptedBytes = cipher.doFinal(mac + data)
|
||||||
|
val iv = cipher.iv
|
||||||
|
|
||||||
|
return listOf(encryptedBytes, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decrypt(payload: Collection<ByteArray>, key: ByteArray, algorithm: String, mode: String, padding: String) : ByteArray? {
|
||||||
|
val algo = getCipherAlgorithm(algorithm)
|
||||||
|
val params = getInstance(mode, padding)
|
||||||
|
|
||||||
|
val keySpecification = algo.spec + "/" + params.toString()
|
||||||
|
|
||||||
|
val sk: SecretKey = SecretKeySpec(key, algo.spec)
|
||||||
|
val cipher = Cipher.getInstance(keySpecification);
|
||||||
|
val iv = payload.last();
|
||||||
|
val ivSpec = IvParameterSpec(iv)
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, sk, ivSpec);
|
||||||
|
|
||||||
|
val decryptedBytes = cipher.doFinal(payload.first());
|
||||||
|
|
||||||
|
val mac = decryptedBytes.copyOfRange(0, 32)
|
||||||
|
val decryptedContent : ByteArray = decryptedBytes.copyOfRange(32, decryptedBytes.size)
|
||||||
|
val verificationMac = Hash().digest(key + decryptedContent)
|
||||||
|
|
||||||
|
return if (mac.contentEquals(verificationMac)) {
|
||||||
|
decryptedContent
|
||||||
|
} else {
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
|
enum class HashAlgorithm(val length : Int) {
|
||||||
|
SHA1(160),
|
||||||
|
SHA224(224),
|
||||||
|
SHA256(256),
|
||||||
|
SHA384(384),
|
||||||
|
SHA512(512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Hash() {
|
||||||
|
fun digest(data: ByteArray?, algorithm: HashAlgorithm): ByteArray {
|
||||||
|
val func : String = when (algorithm) {
|
||||||
|
HashAlgorithm.SHA1 -> "SHA-1"
|
||||||
|
HashAlgorithm.SHA224 -> "SHA-224"
|
||||||
|
HashAlgorithm.SHA256 -> "SHA-256"
|
||||||
|
HashAlgorithm.SHA384 -> "SHA-384"
|
||||||
|
HashAlgorithm.SHA512 -> "SHA-512"
|
||||||
|
}
|
||||||
|
val md = MessageDigest.getInstance(func)
|
||||||
|
return md.digest(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun digest(data: ByteArray?, algorithm: String): ByteArray {
|
||||||
|
val func : HashAlgorithm = when (algorithm) {
|
||||||
|
"sha1" -> HashAlgorithm.SHA1
|
||||||
|
"sha224" -> HashAlgorithm.SHA224
|
||||||
|
"sha256" -> HashAlgorithm.SHA256
|
||||||
|
"sha384" -> HashAlgorithm.SHA384
|
||||||
|
"sha512" -> HashAlgorithm.SHA512
|
||||||
|
else -> HashAlgorithm.SHA256
|
||||||
|
}
|
||||||
|
return digest(data, func)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun digest(data: ByteArray?): ByteArray {
|
||||||
|
return digest(data, HashAlgorithm.SHA256)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
import javax.crypto.SecretKeyFactory
|
||||||
|
import javax.crypto.spec.PBEKeySpec
|
||||||
|
|
||||||
|
class KeyDerivation {
|
||||||
|
fun pbkdf2(password: String, salt: String, keyLength: Int, iteration: Int, algorithm: String): ByteArray {
|
||||||
|
val chars: CharArray = password.toCharArray()
|
||||||
|
val availableHashAlgorithm: Map<String, String> = mapOf(
|
||||||
|
"sha1" to "PBKDF2withHmacSHA1",
|
||||||
|
"sha224" to "PBKDF2withHmacSHA224",
|
||||||
|
"sha256" to "PBKDF2WithHmacSHA256",
|
||||||
|
"sha384" to "PBKDF2withHmacSHA384",
|
||||||
|
"sha512" to "PBKDF2withHmacSHA512"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
// SHA-1 and SHA-2 implemented
|
||||||
|
val spec = PBEKeySpec(chars, salt.toByteArray(), iteration, keyLength * 8)
|
||||||
|
val skf: SecretKeyFactory = SecretKeyFactory.getInstance(availableHashAlgorithm[algorithm]);
|
||||||
|
return skf.generateSecret(spec).encoded
|
||||||
|
} else if (Build.VERSION.SDK_INT >= 10) {
|
||||||
|
// Only SHA-1 is implemented
|
||||||
|
if (!algorithm.equals("sha1")) {
|
||||||
|
throw PlatformVersionException("Only SHA1 is implemented on this SDK version!")
|
||||||
|
}
|
||||||
|
val spec = PBEKeySpec(chars, salt.toByteArray(), iteration, keyLength * 8)
|
||||||
|
val skf: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1");
|
||||||
|
return skf.generateSecret(spec).encoded
|
||||||
|
}
|
||||||
|
throw PlatformVersionException("Invalid SDK version!")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.security.KeyPairGenerator
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import javax.crypto.KeyGenerator
|
||||||
|
|
||||||
|
class KeyGeneration {
|
||||||
|
fun keygen(size : Int) : ByteArray {
|
||||||
|
val secureRandom = SecureRandom()
|
||||||
|
val keyGenerator = if (size in listOf<Int>(128,192,256)) {
|
||||||
|
KeyGenerator.getInstance("AES")
|
||||||
|
} else {
|
||||||
|
KeyGenerator.getInstance("BLOWFISH")
|
||||||
|
}
|
||||||
|
|
||||||
|
keyGenerator.init(size, secureRandom)
|
||||||
|
val sk = keyGenerator.generateKey()
|
||||||
|
|
||||||
|
return sk!!.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rsaKeypairGen(size : Int) : List<ByteArray> {
|
||||||
|
val secureRandom = SecureRandom()
|
||||||
|
val keyGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
|
|
||||||
|
keyGenerator.initialize(size, secureRandom)
|
||||||
|
val keypair = keyGenerator.genKeyPair()
|
||||||
|
val res : List<ByteArray> = listOf(keypair.public.encoded, keypair.private.encoded)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020
|
||||||
|
* Author: Hugo Pointcheval
|
||||||
|
*/
|
||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
|
import io.flutter.plugin.common.MethodChannel.Result
|
||||||
|
import io.flutter.plugin.common.PluginRegistry.Registrar
|
||||||
|
|
||||||
|
|
||||||
|
/** NativeCryptoPlugin */
|
||||||
|
class NativeCryptoPlugin : FlutterPlugin, MethodCallHandler {
|
||||||
|
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
|
val channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "native.crypto")
|
||||||
|
channel.setMethodCallHandler(NativeCryptoPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun registerWith(registrar: Registrar) {
|
||||||
|
val channel = MethodChannel(registrar.messenger(), "native.crypto")
|
||||||
|
channel.setMethodCallHandler(NativeCryptoPlugin())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||||
|
|
||||||
|
when (call.method) {
|
||||||
|
"digest" -> {
|
||||||
|
val message = call.argument<ByteArray>("message")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
|
||||||
|
try {
|
||||||
|
val d = Hash().digest(message, algorithm!!)
|
||||||
|
if (d.isNotEmpty()) {
|
||||||
|
result.success(d)
|
||||||
|
} else {
|
||||||
|
result.error("DIGESTERROR", "DIGEST IS NULL.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("DIGESTEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"pbkdf2" -> {
|
||||||
|
val password = call.argument<String>("password")
|
||||||
|
val salt = call.argument<String>("salt")
|
||||||
|
val keyLength = call.argument<Int>("keyLength")
|
||||||
|
val iteration = call.argument<Int>("iteration")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
|
||||||
|
try {
|
||||||
|
val key = KeyDerivation().pbkdf2(password!!, salt!!, keyLength!!, iteration!!, algorithm!!)
|
||||||
|
if (key.isNotEmpty()) {
|
||||||
|
result.success(key)
|
||||||
|
} else {
|
||||||
|
result.error("PBKDF2ERROR", "PBKDF2 KEY IS NULL.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("PBKDF2EXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"keygen" -> {
|
||||||
|
val size = call.argument<Int>("size") // 128, 192, 256
|
||||||
|
try {
|
||||||
|
val key = KeyGeneration().keygen(size!!)
|
||||||
|
|
||||||
|
if (key.isNotEmpty()) {
|
||||||
|
result.success(key)
|
||||||
|
} else {
|
||||||
|
result.error("KEYGENERROR", "GENERATED KEY IS NULL.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("KEYGENEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"rsaKeypairGen" -> {
|
||||||
|
val size = call.argument<Int>("size")
|
||||||
|
try {
|
||||||
|
val keypair = KeyGeneration().rsaKeypairGen(size!!)
|
||||||
|
|
||||||
|
if (keypair.isNotEmpty()) {
|
||||||
|
result.success(keypair)
|
||||||
|
} else {
|
||||||
|
result.error("KEYPAIRGENERROR", "GENERATED KEYPAIR IS EMPTY.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("KEYPAIRGENEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"encrypt" -> {
|
||||||
|
val data = call.argument<ByteArray>("data")
|
||||||
|
val key = call.argument<ByteArray>("key")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
val mode = call.argument<String>("mode")
|
||||||
|
val padding = call.argument<String>("padding")
|
||||||
|
|
||||||
|
try {
|
||||||
|
val payload = Cipher().encrypt(data!!, key!!, algorithm!!, mode!!, padding!!)
|
||||||
|
|
||||||
|
if (payload.isNotEmpty()) {
|
||||||
|
result.success(payload)
|
||||||
|
} else {
|
||||||
|
result.error("ENCRYPTIONERROR", "ENCRYPTED PAYLOAD IS EMPTY.", null)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
result.error("ENCRYPTIONEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
"decrypt" -> {
|
||||||
|
val payload = call.argument<Collection<ByteArray>>("payload") // Collection<ByteArray>
|
||||||
|
|
||||||
|
val key = call.argument<ByteArray>("key")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
val mode = call.argument<String>("mode")
|
||||||
|
val padding = call.argument<String>("padding")
|
||||||
|
|
||||||
|
var decryptedPayload : ByteArray? = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
decryptedPayload = Cipher().decrypt(payload!!, key!!, algorithm!!, mode!!, padding!!)
|
||||||
|
if (decryptedPayload != null && decryptedPayload.isNotEmpty()) {
|
||||||
|
result.success(decryptedPayload)
|
||||||
|
} else {
|
||||||
|
result.error("DECRYPTIONERROR", "DECRYPTED PAYLOAD IS NULL. MAYBE VERIFICATION MAC IS UNVALID.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("DECRYPTIONEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
class PlatformVersionException(message : String) : Exception(message)
|
BIN
assets/benchmark_pointycastle.png
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
assets/native_crypto.png
Normal file
After Width: | Height: | Size: 30 KiB |
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
**/ios/Flutter/.last_build_id
|
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.flutter-plugins
|
.flutter-plugins
|
||||||
.flutter-plugins-dependencies
|
.flutter-plugins-dependencies
|
||||||
@ -34,13 +33,5 @@
|
|||||||
# Web related
|
# Web related
|
||||||
lib/generated_plugin_registrant.dart
|
lib/generated_plugin_registrant.dart
|
||||||
|
|
||||||
# Symbolication related
|
# Exceptions to above rules.
|
||||||
app.*.symbols
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
|
||||||
# Obfuscation related
|
|
||||||
app.*.map.json
|
|
||||||
|
|
||||||
# Android Studio will place build artifacts here
|
|
||||||
/android/app/debug
|
|
||||||
/android/app/profile
|
|
||||||
/android/app/release
|
|
@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: cf4400006550b70f28e4b4af815151d1e74846c6
|
revision: f139b11009aeb8ed2a3a3aa8b0066e482709dde3
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
7
example/android/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
@ -26,28 +26,24 @@ apply plugin: 'kotlin-android'
|
|||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion flutter.compileSdkVersion
|
compileSdkVersion 28
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = '1.8'
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "fr.pointcheval.native_crypto_example"
|
applicationId "fr.pointcheval.native_crypto_example"
|
||||||
minSdkVersion flutter.minSdkVersion
|
minSdkVersion 16
|
||||||
targetSdkVersion flutter.targetSdkVersion
|
targetSdkVersion 28
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -65,4 +61,7 @@ flutter {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||||
}
|
}
|
@ -1,25 +1,21 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="fr.pointcheval.native_crypto_example">
|
package="fr.pointcheval.native_crypto_example">
|
||||||
<application
|
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||||
|
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||||
|
In most cases you can leave this as-is, but you if you want to provide
|
||||||
|
additional functionality it is fine to subclass or reimplement
|
||||||
|
FlutterApplication and put your custom class here. -->
|
||||||
|
<application
|
||||||
|
android:name="io.flutter.app.FlutterApplication"
|
||||||
android:label="native_crypto_example"
|
android:label="native_crypto_example"
|
||||||
android:name="${applicationName}"
|
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
|
||||||
the Android process has started. This theme is visible to the user
|
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
|
||||||
to determine the Window background behind the Flutter UI. -->
|
|
||||||
<meta-data
|
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
|
||||||
android:resource="@style/NormalTheme"
|
|
||||||
/>
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
@ -0,0 +1,12 @@
|
|||||||
|
package fr.pointcheval.native_crypto_example
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity() {
|
||||||
|
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||||
|
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
8
example/android/app/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -2,11 +2,11 @@ buildscript {
|
|||||||
ext.kotlin_version = '1.3.50'
|
ext.kotlin_version = '1.3.50'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ buildscript {
|
|||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
jcenter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
example/android/gradle.properties
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.enableR8=true
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
6
example/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Fri Dec 18 22:37:36 CET 2020
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
15
example/android/settings.gradle
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
include ':app'
|
||||||
|
|
||||||
|
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
|
||||||
|
|
||||||
|
def plugins = new Properties()
|
||||||
|
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
|
||||||
|
if (pluginsFile.exists()) {
|
||||||
|
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.each { name, path ->
|
||||||
|
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
|
||||||
|
include ":$name"
|
||||||
|
project(":$name").projectDir = pluginDirectory
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
**/dgph
|
|
||||||
*.mode1v3
|
*.mode1v3
|
||||||
*.mode2v3
|
*.mode2v3
|
||||||
*.moved-aside
|
*.moved-aside
|
||||||
@ -19,7 +18,6 @@ Flutter/App.framework
|
|||||||
Flutter/Flutter.framework
|
Flutter/Flutter.framework
|
||||||
Flutter/Flutter.podspec
|
Flutter/Flutter.podspec
|
||||||
Flutter/Generated.xcconfig
|
Flutter/Generated.xcconfig
|
||||||
Flutter/ephemeral/
|
|
||||||
Flutter/app.flx
|
Flutter/app.flx
|
||||||
Flutter/app.zip
|
Flutter/app.zip
|
||||||
Flutter/flutter_assets/
|
Flutter/flutter_assets/
|
1
example/ios/Flutter/.last_build_id
Normal file
@ -0,0 +1 @@
|
|||||||
|
2f8ea5763cdbee83dd665ad298f0e380
|
@ -3,7 +3,7 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>en</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>App</string>
|
<string>App</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@ -21,6 +21,6 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>9.0</string>
|
<string>8.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
2
example/ios/Flutter/Debug.xcconfig
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||||
|
#include "Generated.xcconfig"
|
2
example/ios/Flutter/Release.xcconfig
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
|
#include "Generated.xcconfig"
|
90
example/ios/Podfile
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Uncomment this line to define a global platform for your project
|
||||||
|
# platform :ios, '9.0'
|
||||||
|
|
||||||
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
|
project 'Runner', {
|
||||||
|
'Debug' => :debug,
|
||||||
|
'Profile' => :release,
|
||||||
|
'Release' => :release,
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse_KV_file(file, separator='=')
|
||||||
|
file_abs_path = File.expand_path(file)
|
||||||
|
if !File.exists? file_abs_path
|
||||||
|
return [];
|
||||||
|
end
|
||||||
|
generated_key_values = {}
|
||||||
|
skip_line_start_symbols = ["#", "/"]
|
||||||
|
File.foreach(file_abs_path) do |line|
|
||||||
|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
|
||||||
|
plugin = line.split(pattern=separator)
|
||||||
|
if plugin.length == 2
|
||||||
|
podname = plugin[0].strip()
|
||||||
|
path = plugin[1].strip()
|
||||||
|
podpath = File.expand_path("#{path}", file_abs_path)
|
||||||
|
generated_key_values[podname] = podpath
|
||||||
|
else
|
||||||
|
puts "Invalid plugin specification: #{line}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
generated_key_values
|
||||||
|
end
|
||||||
|
|
||||||
|
target 'Runner' do
|
||||||
|
use_frameworks!
|
||||||
|
use_modular_headers!
|
||||||
|
|
||||||
|
# Flutter Pod
|
||||||
|
|
||||||
|
copied_flutter_dir = File.join(__dir__, 'Flutter')
|
||||||
|
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
|
||||||
|
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
|
||||||
|
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
|
||||||
|
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
|
||||||
|
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
|
||||||
|
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
|
||||||
|
|
||||||
|
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
|
||||||
|
unless File.exist?(generated_xcode_build_settings_path)
|
||||||
|
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||||
|
end
|
||||||
|
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
|
||||||
|
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
|
||||||
|
|
||||||
|
unless File.exist?(copied_framework_path)
|
||||||
|
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
|
||||||
|
end
|
||||||
|
unless File.exist?(copied_podspec_path)
|
||||||
|
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Keep pod path relative so it can be checked into Podfile.lock.
|
||||||
|
pod 'Flutter', :path => 'Flutter'
|
||||||
|
|
||||||
|
# Plugin Pods
|
||||||
|
|
||||||
|
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
|
||||||
|
# referring to absolute paths on developers' machines.
|
||||||
|
system('rm -rf .symlinks')
|
||||||
|
system('mkdir -p .symlinks/plugins')
|
||||||
|
plugin_pods = parse_KV_file('../.flutter-plugins')
|
||||||
|
plugin_pods.each do |name, path|
|
||||||
|
symlink = File.join('.symlinks', 'plugins', name)
|
||||||
|
File.symlink(path, symlink)
|
||||||
|
pod name, :path => File.join(symlink, 'ios')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
|
||||||
|
install! 'cocoapods', :disable_input_output_paths => true
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
target.build_configurations.each do |config|
|
||||||
|
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
22
example/ios/Podfile.lock
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
PODS:
|
||||||
|
- Flutter (1.0.0)
|
||||||
|
- native_crypto (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- Flutter (from `Flutter`)
|
||||||
|
- native_crypto (from `.symlinks/plugins/native_crypto/ios`)
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
Flutter:
|
||||||
|
:path: Flutter
|
||||||
|
native_crypto:
|
||||||
|
:path: ".symlinks/plugins/native_crypto/ios"
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||||
|
native_crypto: 33b8108e3fcc10052862b69863efc2304c59cb2f
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83
|
||||||
|
|
||||||
|
COCOAPODS: 1.9.3
|
@ -3,17 +3,17 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 50;
|
objectVersion = 46;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
20AC864B3037BB896BD381B1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 056766980834B5FAC1C4D331 /* Pods_Runner.framework */; };
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
D294241BEFD2D3EF500C0577 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6CB4DB73769DFCBF23FCC12 /* Pods_Runner.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
@ -30,11 +30,9 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
056766980834B5FAC1C4D331 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
1180301722C337B6C625E46F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
2A0F0FD6D80A80663D317892 /* 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 = "<group>"; };
|
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 = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
@ -46,7 +44,9 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
EC40AF9C4AC2A38A0B8CC0E6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
C6CB4DB73769DFCBF23FCC12 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D3EC88B33A6F35C67BAC8349 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
FB0023B75BB4BD74C9F8D280 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -54,22 +54,19 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
20AC864B3037BB896BD381B1 /* Pods_Runner.framework in Frameworks */,
|
D294241BEFD2D3EF500C0577 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
3024D600AF0E0DED3BB44E03 /* Pods */ = {
|
8C27A9C4EB5E71366C317BF8 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
EC40AF9C4AC2A38A0B8CC0E6 /* Pods-Runner.debug.xcconfig */,
|
C6CB4DB73769DFCBF23FCC12 /* Pods_Runner.framework */,
|
||||||
2A0F0FD6D80A80663D317892 /* Pods-Runner.release.xcconfig */,
|
|
||||||
1180301722C337B6C625E46F /* Pods-Runner.profile.xcconfig */,
|
|
||||||
);
|
);
|
||||||
name = Pods;
|
name = Frameworks;
|
||||||
path = Pods;
|
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
@ -89,8 +86,8 @@
|
|||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
3024D600AF0E0DED3BB44E03 /* Pods */,
|
9F5A6E791DB57C1B2E0BF33E /* Pods */,
|
||||||
F589250F1A900F4BC6E4BB56 /* Frameworks */,
|
8C27A9C4EB5E71366C317BF8 /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -109,6 +106,7 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
97C146F11CF9000F007C117D /* Supporting Files */,
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
@ -117,12 +115,22 @@
|
|||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
F589250F1A900F4BC6E4BB56 /* Frameworks */ = {
|
97C146F11CF9000F007C117D /* Supporting Files */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
056766980834B5FAC1C4D331 /* Pods_Runner.framework */,
|
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9F5A6E791DB57C1B2E0BF33E /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FB0023B75BB4BD74C9F8D280 /* Pods-Runner.debug.xcconfig */,
|
||||||
|
2DBF05A146610778D425B9D9 /* Pods-Runner.release.xcconfig */,
|
||||||
|
D3EC88B33A6F35C67BAC8349 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
@ -132,14 +140,14 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
CE2C3E978245C5FF80E431AC /* [CP] Check Pods Manifest.lock */,
|
D72ACB84F79B4AD23991D136 /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
ED05A5A0A8AF0FA8F71C2C2B /* [CP] Embed Pods Frameworks */,
|
FF811A27CCC4B4D5EBD756CE /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -156,8 +164,8 @@
|
|||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1300;
|
LastUpgradeCheck = 1020;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "The Chromium Authors";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
@ -166,7 +174,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
compatibilityVersion = "Xcode 9.3";
|
compatibilityVersion = "Xcode 3.2";
|
||||||
developmentRegion = en;
|
developmentRegion = en;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
@ -226,7 +234,7 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
CE2C3E978245C5FF80E431AC /* [CP] Check Pods Manifest.lock */ = {
|
D72ACB84F79B4AD23991D136 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
@ -248,17 +256,15 @@
|
|||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
ED05A5A0A8AF0FA8F71C2C2B /* [CP] Embed Pods Frameworks */ = {
|
FF811A27CCC4B4D5EBD756CE /* [CP] Embed Pods Frameworks */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputFileListPaths = (
|
inputPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
@ -340,7 +346,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@ -356,14 +362,18 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 6Z5P8GG96U;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoIosExample;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoExample;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -418,7 +428,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -467,12 +477,11 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
@ -485,14 +494,18 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 6Z5P8GG96U;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoIosExample;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoExample;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@ -508,14 +521,18 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 6Z5P8GG96U;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoIosExample;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoExample;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1300"
|
LastUpgradeVersion = "1020"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@ -27,6 +27,8 @@
|
|||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
@ -36,8 +38,8 @@
|
|||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
<Testables>
|
<AdditionalOptions>
|
||||||
</Testables>
|
</AdditionalOptions>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
@ -59,6 +61,8 @@
|
|||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Profile"
|
buildConfiguration = "Profile"
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 564 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 68 B |
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 68 B |
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 68 B |
@ -4,8 +4,6 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Native Crypto</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@ -42,6 +40,6 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<true/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
1
example/ios/Runner/Runner-Bridging-Header.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
#import "GeneratedPluginRegistrant.h"
|
69
example/lib/main.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:native_crypto_example/pages/kemPage.dart';
|
||||||
|
|
||||||
|
import 'pages/benchmarkPage.dart';
|
||||||
|
import 'pages/cipherPage.dart';
|
||||||
|
import 'pages/hashKeyDerivationPage.dart';
|
||||||
|
|
||||||
|
void main() => runApp(MyApp());
|
||||||
|
|
||||||
|
class MyApp extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_MyAppState createState() => _MyAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyAppState extends State<MyApp> {
|
||||||
|
int _currentIndex = 0;
|
||||||
|
final List<Widget> _children = [
|
||||||
|
HashKeyDerivationPage(),
|
||||||
|
CipherPage(),
|
||||||
|
KemPage(),
|
||||||
|
BenchmarkPage(),
|
||||||
|
];
|
||||||
|
|
||||||
|
void onTabTapped(int index) {
|
||||||
|
setState(() {
|
||||||
|
_currentIndex = index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: 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: [
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.vpn_key),
|
||||||
|
label: 'Key',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.lock),
|
||||||
|
label: 'Encryption',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.connect_without_contact),
|
||||||
|
label: 'KEM',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.timer),
|
||||||
|
label: 'Benchmark',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
144
example/lib/pages/benchmarkPage.dart
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// Copyright (c) 2021
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:native_crypto/native_crypto.dart';
|
||||||
|
|
||||||
|
import '../session.dart';
|
||||||
|
import '../widgets/button.dart';
|
||||||
|
import '../widgets/output.dart';
|
||||||
|
|
||||||
|
class BenchmarkPage extends StatefulWidget {
|
||||||
|
const BenchmarkPage({key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_BenchmarkPageState createState() => _BenchmarkPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BenchmarkPageState extends State<BenchmarkPage> {
|
||||||
|
final Output keyContent = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output benchmarkStatus = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
large: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> _benchmark() async {
|
||||||
|
if (Session.secretKey == null || Session.secretKey.isEmpty) {
|
||||||
|
benchmarkStatus
|
||||||
|
.print('No SecretKey!\nGo in Key tab and generate or derive one.');
|
||||||
|
return;
|
||||||
|
} else if (!Session.aesCipher.isInitialized) {
|
||||||
|
benchmarkStatus.print(
|
||||||
|
'Cipher not initialized!\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 Session.aesCipher.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;
|
||||||
|
|
||||||
|
// Encoding
|
||||||
|
before = DateTime.now();
|
||||||
|
encryptedBigFile.encode();
|
||||||
|
after = DateTime.now();
|
||||||
|
|
||||||
|
benchmark = after.millisecondsSinceEpoch - before.millisecondsSinceEpoch;
|
||||||
|
benchmarkStatus.append('[$size MB] Encoding took $benchmark ms\n');
|
||||||
|
|
||||||
|
csv += "$benchmark;";
|
||||||
|
|
||||||
|
// Decryption
|
||||||
|
before = DateTime.now();
|
||||||
|
await Session.aesCipher.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');
|
||||||
|
log(csv, name: "Benchmark");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clear() {
|
||||||
|
benchmarkStatus.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (Session.secretKey != null) {
|
||||||
|
keyContent.print(Session.secretKey.encoded.toString());
|
||||||
|
Session.aesCipher = AESCipher(
|
||||||
|
Session.secretKey,
|
||||||
|
CipherParameters(
|
||||||
|
BlockCipherMode.CBC,
|
||||||
|
PlainTextPadding.PKCS5,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
child: Text("Secret Key"),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
),
|
||||||
|
keyContent,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Button(
|
||||||
|
onPressed: _benchmark,
|
||||||
|
label: "Launch benchmark",
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _clear,
|
||||||
|
label: "Clear",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
benchmarkStatus,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
205
example/lib/pages/cipherPage.dart
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
// Copyright (c) 2021
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:native_crypto/native_crypto.dart';
|
||||||
|
|
||||||
|
import '../session.dart';
|
||||||
|
import '../utils.dart';
|
||||||
|
import '../widgets/button.dart';
|
||||||
|
import '../widgets/output.dart';
|
||||||
|
|
||||||
|
class CipherPage extends StatefulWidget {
|
||||||
|
const CipherPage({key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CipherPageState createState() => _CipherPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CipherPageState extends State<CipherPage> {
|
||||||
|
final Output keyContent = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output encryptionStatus = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output decryptionStatus = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output cipherExport = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
large: true,
|
||||||
|
editable: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final TextEditingController _plainTextController = TextEditingController();
|
||||||
|
CipherText cipherText;
|
||||||
|
|
||||||
|
void _encrypt() async {
|
||||||
|
final plainText = _plainTextController.text.trim();
|
||||||
|
|
||||||
|
if (Session.secretKey == null || Session.secretKey.isEmpty) {
|
||||||
|
encryptionStatus
|
||||||
|
.print('No SecretKey!\nGo in Key tab and generate or derive one.');
|
||||||
|
} else if (!Session.aesCipher.isInitialized) {
|
||||||
|
encryptionStatus.print(
|
||||||
|
'Cipher not initialized!\nGo in Key tab and generate or derive one.');
|
||||||
|
} else if (plainText.isEmpty) {
|
||||||
|
encryptionStatus.print('Entry is empty');
|
||||||
|
} else {
|
||||||
|
var stringToBytes = TypeHelper.stringToBytes(plainText);
|
||||||
|
cipherText = await Session.aesCipher.encrypt(stringToBytes);
|
||||||
|
encryptionStatus.print('String successfully encrypted.\n');
|
||||||
|
encryptionStatus.append("IV: " +
|
||||||
|
cipherText.iv.toString() +
|
||||||
|
"\nCipherText: " +
|
||||||
|
cipherText.bytes.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _alter() async {
|
||||||
|
if (cipherText == null || cipherText.bytes.isEmpty) {
|
||||||
|
decryptionStatus.print('Encrypt before altering CipherText!');
|
||||||
|
} else {
|
||||||
|
// Add 1 to the first byte
|
||||||
|
List<Uint8List> _altered = cipherText.bytes;
|
||||||
|
_altered[0][0] += 1;
|
||||||
|
// Recreate cipher text with altered data
|
||||||
|
cipherText = AESCipherText.from(_altered, cipherText.iv);
|
||||||
|
encryptionStatus.print('String successfully encrypted.\n');
|
||||||
|
encryptionStatus.append("IV: " +
|
||||||
|
cipherText.iv.toString() +
|
||||||
|
"\nCipherText: " +
|
||||||
|
cipherText.bytes.toString());
|
||||||
|
decryptionStatus.print('CipherText altered!\nDecryption will fail.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _decrypt() async {
|
||||||
|
if (Session.secretKey == null || Session.secretKey.isEmpty) {
|
||||||
|
decryptionStatus
|
||||||
|
.print('No SecretKey!\nGo in Key tab and generate or derive one.');
|
||||||
|
} else if (!Session.aesCipher.isInitialized) {
|
||||||
|
decryptionStatus.print(
|
||||||
|
'Cipher not initialized!\nGo in Key tab and generate or derive one.');
|
||||||
|
} else if (cipherText == null || cipherText.bytes.isEmpty) {
|
||||||
|
decryptionStatus.print('Encrypt before decrypting!');
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Uint8List plainText = await Session.aesCipher.decrypt(cipherText);
|
||||||
|
var bytesToString = TypeHelper.bytesToString(plainText);
|
||||||
|
decryptionStatus
|
||||||
|
.print('String successfully decrypted:\n\n$bytesToString');
|
||||||
|
} on DecryptionException catch (e) {
|
||||||
|
decryptionStatus.print(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _export() async {
|
||||||
|
if (cipherText == null) {
|
||||||
|
decryptionStatus.print('Encrypt data before export!');
|
||||||
|
} else {
|
||||||
|
// TODO: fix export format to support chunks !
|
||||||
|
Uint8List payload = cipherText.encode();
|
||||||
|
String data = TypeHelper.bytesToBase64(payload);
|
||||||
|
decryptionStatus.print('CipherText successfully exported');
|
||||||
|
cipherExport.print(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _import() async {
|
||||||
|
final String data = cipherExport.read();
|
||||||
|
if (data.isEmpty) {
|
||||||
|
encryptionStatus.print('CipherText import failed');
|
||||||
|
} else {
|
||||||
|
Uint8List payload = TypeHelper.base64ToBytes(data);
|
||||||
|
cipherText = AESCipherText.empty();
|
||||||
|
cipherText.decode(payload);
|
||||||
|
encryptionStatus.print('CipherText successfully imported\n');
|
||||||
|
encryptionStatus.append("IV: " +
|
||||||
|
cipherText.iv.toString() +
|
||||||
|
"\nCipherText: " +
|
||||||
|
cipherText.bytes.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (Session.secretKey != null) {
|
||||||
|
keyContent.print(Session.secretKey.encoded.toString());
|
||||||
|
Session.aesCipher = AESCipher(
|
||||||
|
Session.secretKey,
|
||||||
|
CipherParameters(
|
||||||
|
BlockCipherMode.CBC,
|
||||||
|
PlainTextPadding.PKCS5,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_plainTextController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
child: Text("Secret Key"),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
),
|
||||||
|
keyContent,
|
||||||
|
TextField(
|
||||||
|
controller: _plainTextController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Plain text',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _encrypt,
|
||||||
|
label: "Encrypt",
|
||||||
|
),
|
||||||
|
encryptionStatus,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Button(
|
||||||
|
onPressed: _alter,
|
||||||
|
label: "Alter cipher",
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _decrypt,
|
||||||
|
label: "Decrypt",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
decryptionStatus,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Button(
|
||||||
|
onPressed: _export,
|
||||||
|
label: "Export cipher",
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _import,
|
||||||
|
label: "Import cipher",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
cipherExport
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
180
example/lib/pages/hashKeyDerivationPage.dart
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:native_crypto/native_crypto.dart';
|
||||||
|
|
||||||
|
import '../session.dart';
|
||||||
|
import '../utils.dart';
|
||||||
|
import '../widgets/button.dart';
|
||||||
|
import '../widgets/output.dart';
|
||||||
|
|
||||||
|
class HashKeyDerivationPage extends StatefulWidget {
|
||||||
|
const HashKeyDerivationPage({key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_HashKeyDerivationPageState createState() => _HashKeyDerivationPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HashKeyDerivationPageState extends State<HashKeyDerivationPage> {
|
||||||
|
final Output keyContent = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output keyStatus = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output keyExport = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
large: true,
|
||||||
|
editable: true,
|
||||||
|
);
|
||||||
|
final Output pbkdf2Status = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
final Output hashStatus = Output(
|
||||||
|
textEditingController: TextEditingController(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final TextEditingController _pwdTextController = TextEditingController();
|
||||||
|
final TextEditingController _messageTextController = TextEditingController();
|
||||||
|
final TextEditingController _keyTextController = TextEditingController();
|
||||||
|
|
||||||
|
void _generate() async {
|
||||||
|
try {
|
||||||
|
Session.secretKey = await SecretKey.generate(256, CipherAlgorithm.AES);
|
||||||
|
keyContent.print(Session.secretKey.encoded.toString());
|
||||||
|
keyStatus.print(
|
||||||
|
"Secret Key successfully generated.\nLength: ${Session.secretKey.encoded.length} bytes");
|
||||||
|
} catch (e) {
|
||||||
|
keyStatus.print(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _pbkdf2() async {
|
||||||
|
final password = _pwdTextController.text.trim();
|
||||||
|
|
||||||
|
if (password.isEmpty) {
|
||||||
|
pbkdf2Status.print('Password is empty');
|
||||||
|
} else {
|
||||||
|
PBKDF2 _pbkdf2 =
|
||||||
|
PBKDF2(keyLength: 32, iteration: 1000, hash: HashAlgorithm.SHA512);
|
||||||
|
await _pbkdf2.derive(password: password, salt: 'salty');
|
||||||
|
SecretKey key = _pbkdf2.key;
|
||||||
|
pbkdf2Status.print('Key successfully derived.');
|
||||||
|
Session.secretKey = key;
|
||||||
|
keyContent.print(Session.secretKey.encoded.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _export() async {
|
||||||
|
if (Session.secretKey == null || Session.secretKey.isEmpty) {
|
||||||
|
keyStatus
|
||||||
|
.print('No SecretKey!\nGenerate or derive one before exporting!');
|
||||||
|
} else {
|
||||||
|
String key = TypeHelper.bytesToBase64(Session.secretKey.encoded);
|
||||||
|
keyStatus.print('Key successfully exported');
|
||||||
|
keyExport.print(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _import() async {
|
||||||
|
final String key = keyExport.read();
|
||||||
|
if (key.isEmpty) {
|
||||||
|
keyStatus.print('Key import failed');
|
||||||
|
} else {
|
||||||
|
Uint8List keyBytes = TypeHelper.base64ToBytes(key);
|
||||||
|
Session.secretKey =
|
||||||
|
SecretKey.fromBytes(keyBytes, algorithm: CipherAlgorithm.AES);
|
||||||
|
keyStatus.print('Key successfully imported');
|
||||||
|
keyContent.print(Session.secretKey.encoded.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _hash() async {
|
||||||
|
final message = _messageTextController.text.trim();
|
||||||
|
|
||||||
|
if (message.isEmpty) {
|
||||||
|
hashStatus.print('Message is empty');
|
||||||
|
} else {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("sha256");
|
||||||
|
Uint8List hash = await md.digest(TypeHelper.stringToBytes(message));
|
||||||
|
hashStatus.print('Message successfully hashed.\n' + hash.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (Session.secretKey != null) {
|
||||||
|
keyContent.print(Session.secretKey.encoded.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_pwdTextController.dispose();
|
||||||
|
_messageTextController.dispose();
|
||||||
|
_keyTextController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
child: Text("Secret Key"),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
),
|
||||||
|
keyContent,
|
||||||
|
Button(
|
||||||
|
onPressed: _generate,
|
||||||
|
label: "Generate key",
|
||||||
|
),
|
||||||
|
keyStatus,
|
||||||
|
TextField(
|
||||||
|
controller: _pwdTextController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Password',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _pbkdf2,
|
||||||
|
label: "Apply PBKDF2",
|
||||||
|
),
|
||||||
|
pbkdf2Status,
|
||||||
|
TextField(
|
||||||
|
controller: _messageTextController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Message',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _hash,
|
||||||
|
label: "Hash",
|
||||||
|
),
|
||||||
|
hashStatus,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Button(
|
||||||
|
onPressed: _export,
|
||||||
|
label: "Export key",
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
onPressed: _import,
|
||||||
|
label: "Import key",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
keyExport
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
21
example/lib/pages/kemPage.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class KemPage extends StatefulWidget {
|
||||||
|
KemPage({Key key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_KemPageState createState() => _KemPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _KemPageState extends State<KemPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: Center(
|
||||||
|
child: Text("Not implemented."),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
9
example/lib/session.dart
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
|
||||||
|
import 'package:native_crypto/native_crypto.dart';
|
||||||
|
|
||||||
|
class Session {
|
||||||
|
static SecretKey secretKey;
|
||||||
|
static AESCipher aesCipher;
|
||||||
|
}
|
30
example/lib/utils.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
/// Contains some useful functions.
|
||||||
|
class TypeHelper {
|
||||||
|
/// Returns bytes [Uint8List] from a [String].
|
||||||
|
static Uint8List stringToBytes(String source) {
|
||||||
|
var list = source.runes.toList();
|
||||||
|
var bytes = Uint8List.fromList(list);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a [String] from bytes [Uint8List].
|
||||||
|
static String bytesToString(Uint8List bytes) {
|
||||||
|
var string = String.fromCharCodes(bytes);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a `base64` [String] from bytes [Uint8List].
|
||||||
|
static String bytesToBase64(Uint8List bytes) {
|
||||||
|
return base64.encode(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a [Uint8List] from a `base64` [String].
|
||||||
|
static Uint8List base64ToBytes(String encoded) {
|
||||||
|
return base64.decode(encoded);
|
||||||
|
}
|
||||||
|
}
|
24
example/lib/widgets/button.dart
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Button extends StatelessWidget {
|
||||||
|
const Button({Key key, this.onPressed, this.label}) : super(key: key);
|
||||||
|
|
||||||
|
final void Function() onPressed;
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: FlatButton(
|
||||||
|
onPressed: onPressed,
|
||||||
|
color: Colors.blue,
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
55
example/lib/widgets/output.dart
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Output extends StatelessWidget {
|
||||||
|
const Output(
|
||||||
|
{Key key,
|
||||||
|
this.textEditingController,
|
||||||
|
this.large: false,
|
||||||
|
this.editable: false})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final TextEditingController textEditingController;
|
||||||
|
final bool large;
|
||||||
|
final bool editable;
|
||||||
|
|
||||||
|
void print(String message) {
|
||||||
|
log(message, name: "NativeCrypto Example");
|
||||||
|
textEditingController.text = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(String message) {
|
||||||
|
log(message, name: "NativeCrypto Example");
|
||||||
|
textEditingController.text += message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendln(String message) {
|
||||||
|
log(message, name: "NativeCrypto Example");
|
||||||
|
textEditingController.text += message + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
textEditingController.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
String read() {
|
||||||
|
return textEditingController.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: TextField(
|
||||||
|
enableInteractiveSelection: true,
|
||||||
|
readOnly: editable ? false : true,
|
||||||
|
minLines: large ? 3 : 1,
|
||||||
|
maxLines: large ? 500 : 5,
|
||||||
|
decoration: InputDecoration(border: OutlineInputBorder()),
|
||||||
|
controller: textEditingController,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,45 +1,25 @@
|
|||||||
name: native_crypto_example
|
name: native_crypto_example
|
||||||
description: Demonstrates how to use the native_crypto plugin.
|
description: Demonstrates how to use the native_crypto plugin.
|
||||||
|
version: 1.0.0+1
|
||||||
# The following line prevents the package from being accidentally published to
|
publish_to: 'none'
|
||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
|
||||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.15.0 <3.0.0"
|
sdk: ">=2.1.0 <3.0.0"
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
|
||||||
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
|
||||||
# dependencies can be manually updated by changing the version numbers below to
|
|
||||||
# the latest version available on pub.dev. To see which dependencies have newer
|
|
||||||
# versions available, run `flutter pub outdated`.
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
native_crypto:
|
|
||||||
# When depending on this package from a real application you should use:
|
|
||||||
# native_crypto: ^x.y.z
|
|
||||||
# See https://dart.dev/tools/pub/dependencies#version-constraints
|
|
||||||
# The example app is bundled with the plugin so we use a path dependency on
|
|
||||||
# the parent directory to use the current plugin's version.
|
|
||||||
path: ../
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^0.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The "flutter_lints" package below contains a set of recommended lints to
|
native_crypto:
|
||||||
# encourage good coding practices. The lint set provided by the package is
|
path: ../
|
||||||
# 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
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
@ -54,8 +34,8 @@ flutter:
|
|||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
# assets:
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
# https://flutter.dev/assets-and-images/#resolution-aware.
|
@ -13,13 +13,13 @@ import 'package:native_crypto_example/main.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Verify Platform version', (WidgetTester tester) async {
|
testWidgets('Verify Platform version', (WidgetTester tester) async {
|
||||||
// Build our app and trigger a frame.
|
// Build our app and trigger a frame.
|
||||||
await tester.pumpWidget(const MyApp());
|
await tester.pumpWidget(MyApp());
|
||||||
|
|
||||||
// Verify that platform version is retrieved.
|
// Verify that platform version is retrieved.
|
||||||
expect(
|
expect(
|
||||||
find.byWidgetPredicate(
|
find.byWidgetPredicate(
|
||||||
(Widget widget) => widget is Text &&
|
(Widget widget) => widget is Text &&
|
||||||
widget.data!.startsWith('Running on:'),
|
widget.data.startsWith('Running on:'),
|
||||||
),
|
),
|
||||||
findsOneWidget,
|
findsOneWidget,
|
||||||
);
|
);
|
@ -34,5 +34,4 @@ Icon?
|
|||||||
.tags*
|
.tags*
|
||||||
|
|
||||||
/Flutter/Generated.xcconfig
|
/Flutter/Generated.xcconfig
|
||||||
/Flutter/ephemeral/
|
|
||||||
/Flutter/flutter_export_environment.sh
|
/Flutter/flutter_export_environment.sh
|
135
ios/Classes/Cipher.swift
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
//
|
||||||
|
// Cipher.swift
|
||||||
|
//
|
||||||
|
// NativeCryptoPlugin
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CommonCrypto
|
||||||
|
|
||||||
|
enum CipherAlgorithm: String {
|
||||||
|
case AES = "aes"
|
||||||
|
case BlowFish = "blowfish"
|
||||||
|
|
||||||
|
var instance: Int {
|
||||||
|
switch self {
|
||||||
|
case .AES: return kCCAlgorithmAES
|
||||||
|
case .BlowFish: return kCCAlgorithmBlowfish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BlockCipherMode: String {
|
||||||
|
case ECB = "ecb"
|
||||||
|
case CBC = "cbc"
|
||||||
|
|
||||||
|
var instance: Int {
|
||||||
|
switch self {
|
||||||
|
case .CBC: return 0
|
||||||
|
case .ECB: return kCCOptionECBMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Padding: String {
|
||||||
|
case PKCS5 = "pkcs5"
|
||||||
|
case None = "none"
|
||||||
|
|
||||||
|
var instance: Int {
|
||||||
|
switch self {
|
||||||
|
case .PKCS5: return kCCOptionPKCS7Padding
|
||||||
|
case .None: return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cipher {
|
||||||
|
func encrypt(data : Data, key : Data, algorithm : CipherAlgorithm, mode : BlockCipherMode, padding : Padding) -> [Data]? {
|
||||||
|
// Calculate Mac
|
||||||
|
let mac = Hash().digest(data: key + data, algorithm: .SHA256)
|
||||||
|
let payload = mac! + data
|
||||||
|
|
||||||
|
// Generate IV
|
||||||
|
let ivBytes = UnsafeMutableRawPointer.allocate(byteCount: kCCBlockSizeAES128, alignment: 1)
|
||||||
|
defer { ivBytes.deallocate() }
|
||||||
|
let ivStatus = CCRandomGenerateBytes(ivBytes, kCCBlockSizeAES128)
|
||||||
|
if (ivStatus != kCCSuccess) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let ivData = Data(bytes: ivBytes, count: kCCBlockSizeAES128)
|
||||||
|
|
||||||
|
let algo = algorithm.instance
|
||||||
|
let options: CCOptions = UInt32(mode.instance + padding.instance)
|
||||||
|
|
||||||
|
|
||||||
|
guard var ciphertext = crypt(operation: kCCEncrypt,
|
||||||
|
algorithm: algo,
|
||||||
|
options: options,
|
||||||
|
key: key,
|
||||||
|
initializationVector: ivData,
|
||||||
|
dataIn: payload) else { return nil }
|
||||||
|
|
||||||
|
return [ciphertext, ivData]
|
||||||
|
}
|
||||||
|
|
||||||
|
func decrypt(payload : [Data], key : Data, algorithm : CipherAlgorithm, mode : BlockCipherMode, padding : Padding) -> Data? {
|
||||||
|
let encrypted = payload[1] + payload[0]
|
||||||
|
|
||||||
|
guard encrypted.count > kCCBlockSizeAES128 else { return nil }
|
||||||
|
let iv = encrypted.prefix(kCCBlockSizeAES128)
|
||||||
|
let ciphertext = encrypted.suffix(from: kCCBlockSizeAES128)
|
||||||
|
|
||||||
|
let algo = algorithm.instance
|
||||||
|
let options: CCOptions = UInt32(mode.instance + padding.instance)
|
||||||
|
|
||||||
|
guard var decrypted = crypt(operation: kCCDecrypt,
|
||||||
|
algorithm: algo,
|
||||||
|
options: options,
|
||||||
|
key: key,
|
||||||
|
initializationVector: iv,
|
||||||
|
dataIn: ciphertext) else {return nil}
|
||||||
|
|
||||||
|
|
||||||
|
// Create a range based on the length of data to return
|
||||||
|
let range = 0..<32
|
||||||
|
|
||||||
|
// Get a new copy of data
|
||||||
|
let mac = decrypted.subdata(in: range)
|
||||||
|
decrypted.removeSubrange(range)
|
||||||
|
|
||||||
|
let vmac = Hash().digest(data: key + decrypted, algorithm: .SHA256)
|
||||||
|
|
||||||
|
if (mac.base64EncodedData() == vmac!.base64EncodedData()) {
|
||||||
|
return decrypted
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func crypt(operation: Int, algorithm: Int, options: UInt32, key: Data,
|
||||||
|
initializationVector: Data, dataIn: Data) -> Data? {
|
||||||
|
|
||||||
|
return key.withUnsafeBytes { keyUnsafeRawBufferPointer in
|
||||||
|
return dataIn.withUnsafeBytes { dataInUnsafeRawBufferPointer in
|
||||||
|
return initializationVector.withUnsafeBytes { ivUnsafeRawBufferPointer in
|
||||||
|
let dataOutSize: Int = dataIn.count + kCCBlockSizeAES128*2
|
||||||
|
let dataOut = UnsafeMutableRawPointer.allocate(byteCount: dataOutSize,
|
||||||
|
alignment: 1)
|
||||||
|
defer { dataOut.deallocate() }
|
||||||
|
var dataOutMoved: Int = 0
|
||||||
|
let status = CCCrypt(CCOperation(operation), CCAlgorithm(algorithm),
|
||||||
|
CCOptions(options),
|
||||||
|
keyUnsafeRawBufferPointer.baseAddress, key.count,
|
||||||
|
ivUnsafeRawBufferPointer.baseAddress,
|
||||||
|
dataInUnsafeRawBufferPointer.baseAddress, dataIn.count,
|
||||||
|
dataOut, dataOutSize, &dataOutMoved)
|
||||||
|
guard status == kCCSuccess else { return nil }
|
||||||
|
return Data(bytes: dataOut, count: dataOutMoved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
ios/Classes/Hash.swift
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// Hash.swift
|
||||||
|
//
|
||||||
|
// NativeCryptoPlugin
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
//
|
||||||
|
import Foundation
|
||||||
|
import CommonCrypto
|
||||||
|
|
||||||
|
enum HashAlgorithm: String {
|
||||||
|
case SHA1 = "sha1"
|
||||||
|
case SHA224 = "sha224"
|
||||||
|
case SHA256 = "sha256"
|
||||||
|
case SHA384 = "sha384"
|
||||||
|
case SHA512 = "sha512"
|
||||||
|
|
||||||
|
var digestLength: Int {
|
||||||
|
switch self {
|
||||||
|
case .SHA1: return Int(CC_SHA1_DIGEST_LENGTH)
|
||||||
|
case .SHA224: return Int(CC_SHA224_DIGEST_LENGTH)
|
||||||
|
case .SHA256: return Int(CC_SHA256_DIGEST_LENGTH)
|
||||||
|
case .SHA384: return Int(CC_SHA384_DIGEST_LENGTH)
|
||||||
|
case .SHA512: return Int(CC_SHA512_DIGEST_LENGTH)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pbkdf2: UInt32 {
|
||||||
|
switch self {
|
||||||
|
case .SHA1: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA1)
|
||||||
|
case .SHA224: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA224)
|
||||||
|
case .SHA256: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256)
|
||||||
|
case .SHA384: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA384)
|
||||||
|
case .SHA512: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Hash {
|
||||||
|
func digest(data: Data?, algorithm: HashAlgorithm) -> Data? {
|
||||||
|
if (data == nil) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let hashBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: algorithm.digestLength)
|
||||||
|
defer { hashBytes.deallocate() }
|
||||||
|
|
||||||
|
switch algorithm {
|
||||||
|
case .SHA1:
|
||||||
|
data!.withUnsafeBytes { (buffer) -> Void in
|
||||||
|
CC_SHA1(buffer.baseAddress!, CC_LONG(buffer.count), hashBytes)
|
||||||
|
}
|
||||||
|
case .SHA224:
|
||||||
|
data!.withUnsafeBytes { (buffer) -> Void in
|
||||||
|
CC_SHA224(buffer.baseAddress!, CC_LONG(buffer.count), hashBytes)
|
||||||
|
}
|
||||||
|
case .SHA256:
|
||||||
|
data!.withUnsafeBytes { (buffer) -> Void in
|
||||||
|
CC_SHA256(buffer.baseAddress!, CC_LONG(buffer.count), hashBytes)
|
||||||
|
}
|
||||||
|
case .SHA384:
|
||||||
|
data!.withUnsafeBytes { (buffer) -> Void in
|
||||||
|
CC_SHA384(buffer.baseAddress!, CC_LONG(buffer.count), hashBytes)
|
||||||
|
}
|
||||||
|
case .SHA512:
|
||||||
|
data!.withUnsafeBytes { (buffer) -> Void in
|
||||||
|
CC_SHA512(buffer.baseAddress!, CC_LONG(buffer.count), hashBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Data(bytes: hashBytes, count: algorithm.digestLength)
|
||||||
|
}
|
||||||
|
}
|
40
ios/Classes/KeyDerivation.swift
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// KeyDerivation.swift
|
||||||
|
//
|
||||||
|
// NativeCryptoPlugin
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CommonCrypto
|
||||||
|
|
||||||
|
class KeyDerivation {
|
||||||
|
func pbkdf2(password: String, salt: String, keyLength: Int, iteration: Int, algorithm: HashAlgorithm) -> Data? {
|
||||||
|
|
||||||
|
let passwordData = password.data(using: .utf8)!
|
||||||
|
let saltData = salt.data(using: .utf8)!
|
||||||
|
|
||||||
|
var derivedKeyData = Data(repeating: 0, count: keyLength)
|
||||||
|
var localDerivedKeyData = derivedKeyData
|
||||||
|
|
||||||
|
let derivationStatus = derivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
|
||||||
|
saltData.withUnsafeBytes { saltBytes in
|
||||||
|
CCKeyDerivationPBKDF(
|
||||||
|
CCPBKDFAlgorithm(kCCPBKDF2),
|
||||||
|
password, passwordData.count,
|
||||||
|
saltBytes, saltData.count,
|
||||||
|
algorithm.pbkdf2,
|
||||||
|
UInt32(iteration),
|
||||||
|
derivedKeyBytes, localDerivedKeyData.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (derivationStatus != kCCSuccess) {
|
||||||
|
print("Error: \(derivationStatus)")
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return derivedKeyData
|
||||||
|
}
|
||||||
|
}
|
25
ios/Classes/KeyGeneration.swift
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// KeyGeneration.swift
|
||||||
|
//
|
||||||
|
// NativeCryptoPlugin
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
//
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class KeyGeneration {
|
||||||
|
func keygen(size : NSNumber) -> Data? {
|
||||||
|
var bytes = [Int8](repeating: 0, count: size.intValue / 8)
|
||||||
|
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
|
||||||
|
|
||||||
|
if status == errSecSuccess {
|
||||||
|
let keyBytes = bytes.withUnsafeBytes {
|
||||||
|
return Data(Array($0))
|
||||||
|
|
||||||
|
}
|
||||||
|
return keyBytes
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
4
ios/Classes/NativeCryptoPlugin.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#import <Flutter/Flutter.h>
|
||||||
|
|
||||||
|
@interface NativeCryptoPlugin : NSObject<FlutterPlugin>
|
||||||
|
@end
|
@ -1,15 +1,15 @@
|
|||||||
#import "NativeCryptoIosPlugin.h"
|
#import "NativeCryptoPlugin.h"
|
||||||
#if __has_include(<native_crypto_ios/native_crypto_ios-Swift.h>)
|
#if __has_include(<native_crypto/native_crypto-Swift.h>)
|
||||||
#import <native_crypto_ios/native_crypto_ios-Swift.h>
|
#import <native_crypto/native_crypto-Swift.h>
|
||||||
#else
|
#else
|
||||||
// Support project import fallback if the generated compatibility header
|
// Support project import fallback if the generated compatibility header
|
||||||
// is not copied when this plugin is created as a library.
|
// is not copied when this plugin is created as a library.
|
||||||
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
|
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
|
||||||
#import "native_crypto_ios-Swift.h"
|
#import "native_crypto-Swift.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@implementation NativeCryptoIosPlugin
|
@implementation NativeCryptoPlugin
|
||||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||||
[SwiftNativeCryptoIosPlugin registerWithRegistrar:registrar];
|
[SwiftNativeCryptoPlugin registerWithRegistrar:registrar];
|
||||||
}
|
}
|
||||||
@end
|
@end
|
133
ios/Classes/SwiftNativeCryptoPlugin.swift
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
//
|
||||||
|
// NativeCryptoPlugin
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
//
|
||||||
|
import Flutter
|
||||||
|
|
||||||
|
extension FlutterStandardTypedData {
|
||||||
|
var uint8Array: Array<UInt8> {
|
||||||
|
return Array(data)
|
||||||
|
}
|
||||||
|
var int8Array: Array<Int8> {
|
||||||
|
return data.withUnsafeBytes { raw in
|
||||||
|
[Int8](raw.bindMemory(to: Int8.self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SwiftNativeCryptoPlugin: NSObject, FlutterPlugin {
|
||||||
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
|
let channel = FlutterMethodChannel(name: "native.crypto", binaryMessenger: registrar.messenger())
|
||||||
|
let instance = SwiftNativeCryptoPlugin()
|
||||||
|
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
|
switch call.method {
|
||||||
|
case "digest":
|
||||||
|
let args = call.arguments as! NSDictionary
|
||||||
|
|
||||||
|
let message = (args["message"] as! FlutterStandardTypedData).data
|
||||||
|
let algo = args["algorithm"] as! String
|
||||||
|
|
||||||
|
let algorithm : HashAlgorithm? = HashAlgorithm.init(rawValue: algo)
|
||||||
|
|
||||||
|
let hash = Hash().digest(data: message, algorithm: algorithm!)
|
||||||
|
|
||||||
|
if hash != nil {
|
||||||
|
result(FlutterStandardTypedData.init(bytes: hash!))
|
||||||
|
} else {
|
||||||
|
result(FlutterError(code: "DIGESTERROR",
|
||||||
|
message: "DIGEST IS NIL.",
|
||||||
|
details: nil)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case "pbkdf2":
|
||||||
|
let args = call.arguments as! NSDictionary
|
||||||
|
|
||||||
|
let password = args["password"] as! String
|
||||||
|
let salt = args["salt"] as! String
|
||||||
|
let keyLength = args["keyLength"] as! NSNumber
|
||||||
|
let iteration = args["iteration"] as! NSNumber
|
||||||
|
let algo = args["algorithm"] as! String
|
||||||
|
|
||||||
|
let algorithm : HashAlgorithm? = HashAlgorithm.init(rawValue: algo)
|
||||||
|
|
||||||
|
let key = KeyDerivation().pbkdf2(password: password, salt: salt, keyLength: keyLength.intValue, iteration: iteration.intValue, algorithm: algorithm!)
|
||||||
|
|
||||||
|
if key != nil {
|
||||||
|
result(FlutterStandardTypedData.init(bytes: key!))
|
||||||
|
} else {
|
||||||
|
result(FlutterError(code: "PBKDF2ERROR",
|
||||||
|
message: "PBKDF2 KEY IS NIL.",
|
||||||
|
details: nil)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case "keygen":
|
||||||
|
let args = call.arguments as! NSDictionary
|
||||||
|
|
||||||
|
let size = args["size"] as! NSNumber
|
||||||
|
|
||||||
|
let key = KeyGeneration().keygen(size: size)
|
||||||
|
|
||||||
|
if key != nil {
|
||||||
|
result(FlutterStandardTypedData.init(bytes: key!))
|
||||||
|
} else {
|
||||||
|
result(FlutterError(code: "KEYGENERROR",
|
||||||
|
message: "GENERATED KEY IS NIL.",
|
||||||
|
details: nil))
|
||||||
|
}
|
||||||
|
case "encrypt":
|
||||||
|
let args = call.arguments as! NSDictionary
|
||||||
|
|
||||||
|
let data = (args["data"] as! FlutterStandardTypedData).data
|
||||||
|
let key = (args["key"] as! FlutterStandardTypedData).data
|
||||||
|
let algo = args["algorithm"] as! String
|
||||||
|
let mode = args["mode"] as! String
|
||||||
|
let padding = args["padding"] as! String
|
||||||
|
|
||||||
|
let algorithm : CipherAlgorithm? = CipherAlgorithm.init(rawValue: algo)
|
||||||
|
let modeEnum : BlockCipherMode? = BlockCipherMode.init(rawValue: mode)
|
||||||
|
let paddingEnum : Padding? = Padding.init(rawValue: padding)
|
||||||
|
|
||||||
|
let ciphertext = Cipher().encrypt(data: data, key: key, algorithm: algorithm!, mode: modeEnum!, padding: paddingEnum!)
|
||||||
|
|
||||||
|
if ciphertext != nil {
|
||||||
|
result(ciphertext)
|
||||||
|
} else {
|
||||||
|
result(FlutterError(code: "ENCRYPTIONERROR",
|
||||||
|
message: "ENCRYPTED PAYLOAD IS EMPTY.",
|
||||||
|
details: nil))
|
||||||
|
}
|
||||||
|
case "decrypt":
|
||||||
|
let args = call.arguments as! NSDictionary
|
||||||
|
|
||||||
|
let payload = args["payload"] as! NSArray
|
||||||
|
let key = (args["key"] as! FlutterStandardTypedData).data
|
||||||
|
let algo = args["algorithm"] as! String
|
||||||
|
let mode = args["mode"] as! String
|
||||||
|
let padding = args["padding"] as! String
|
||||||
|
|
||||||
|
let encrypted = (payload[0] as! FlutterStandardTypedData).data
|
||||||
|
let iv = (payload[1] as! FlutterStandardTypedData).data
|
||||||
|
let encryptedPayload = [encrypted, iv]
|
||||||
|
|
||||||
|
let algorithm : CipherAlgorithm? = CipherAlgorithm.init(rawValue: algo)
|
||||||
|
let modeEnum : BlockCipherMode? = BlockCipherMode.init(rawValue: mode)
|
||||||
|
let paddingEnum : Padding? = Padding.init(rawValue: padding)
|
||||||
|
|
||||||
|
let decrypted = Cipher().decrypt(payload: encryptedPayload, key: key, algorithm: algorithm!, mode: modeEnum!, padding: paddingEnum!)
|
||||||
|
|
||||||
|
if decrypted != nil {
|
||||||
|
result(FlutterStandardTypedData.init(bytes: decrypted!))
|
||||||
|
} else {
|
||||||
|
result(FlutterError(code: "DECRYPTIONERROR",
|
||||||
|
message: "DECRYPTED PAYLOAD IS NIL. MAYBE VERIFICATION MAC IS UNVALID.",
|
||||||
|
details: nil))
|
||||||
|
}
|
||||||
|
default: result(FlutterMethodNotImplemented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
#
|
#
|
||||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
||||||
# Run `pod lib lint native_crypto_ios.podspec` to validate before publishing.
|
# Run `pod lib lint native_crypto.podspec' to validate before publishing.
|
||||||
#
|
#
|
||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'native_crypto_ios'
|
s.name = 'native_crypto'
|
||||||
s.version = '0.0.1'
|
s.version = '0.0.1'
|
||||||
s.summary = 'A new flutter plugin project.'
|
s.summary = 'A new flutter plugin project.'
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
@ -15,9 +15,9 @@ A new flutter plugin project.
|
|||||||
s.source = { :path => '.' }
|
s.source = { :path => '.' }
|
||||||
s.source_files = 'Classes/**/*'
|
s.source_files = 'Classes/**/*'
|
||||||
s.dependency 'Flutter'
|
s.dependency 'Flutter'
|
||||||
s.platform = :ios, '13.0'
|
s.platform = :ios, '8.0'
|
||||||
|
|
||||||
# Flutter.framework does not contain a i386 slice.
|
# Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported.
|
||||||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
|
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
|
||||||
s.swift_version = '5.0'
|
s.swift_version = '5.0'
|
||||||
end
|
end
|
19
lib/native_crypto.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) 2021
|
||||||
|
// Author: Hugo Pointcheval
|
||||||
|
export './src/exceptions.dart';
|
||||||
|
export './src/key.dart';
|
||||||
|
export './src/keyspec.dart';
|
||||||
|
export './src/keyderivation.dart';
|
||||||
|
export './src/digest.dart';
|
||||||
|
export './src/cipher.dart';
|
||||||
|
//export './src/kem.dart';
|
||||||
|
export './src/platform.dart';
|
||||||
|
export './src/utils.dart';
|
||||||
|
|
||||||
|
export './src/sym/AES.dart';
|
||||||
|
//export './src/asym/RSA.dart';
|
||||||
|
|
||||||
|
const String version = "0.0.6";
|
||||||
|
const String author = "Hugo Pointcheval";
|
||||||
|
const String website = "https://hugo.pointcheval.fr/";
|
||||||
|
const String repository = "https://github.com/hugo-pcl/native-crypto-flutter";
|