Switch to Federated Plugin layout
							
								
								
									
										25
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						| @ -1,25 +0,0 @@ | |||||||
| ## 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. |  | ||||||
							
								
								
									
										167
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @ -1,167 +0,0 @@ | |||||||
| # 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 iPhone 11. |  | ||||||
| 
 |  | ||||||
| | Size (kB) | NativeCrypto **encryption** time (ms) | |  | ||||||
| |-----------|---------------------------------------| |  | ||||||
| | 2 mB | 13 ms |  | ||||||
| | 4 mB | 17 ms |  | ||||||
| | 8 mB | 56 ms |  | ||||||
| | 16 mB | 73 ms |  | ||||||
| | 32 mB | 120 ms |  | ||||||
| | 64 mB | 243 ms |  | ||||||
| | 128 mB | 509 ms |  | ||||||
| | 256 mB | 1057 ms |  | ||||||
| 
 |  | ||||||
| > ~1s for 256 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://github.com/hugo-pcl/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. |  | ||||||
| 
 |  | ||||||
| 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. |  | ||||||
| - [x] 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 |  | ||||||
| - [Chisom Maxwell](https://github.com/maxcotech) - For the chunks idea [#2](https://github.com/hugo-pcl/native-crypto-flutter/issues/2) |  | ||||||
							
								
								
									
										8
									
								
								android/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -1,8 +0,0 @@ | |||||||
| *.iml |  | ||||||
| .gradle |  | ||||||
| /local.properties |  | ||||||
| /.idea/workspace.xml |  | ||||||
| /.idea/libraries |  | ||||||
| .DS_Store |  | ||||||
| /build |  | ||||||
| /captures |  | ||||||
| @ -1,44 +0,0 @@ | |||||||
| 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 +0,0 @@ | |||||||
| rootProject.name = 'native_crypto' |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" |  | ||||||
|   package="fr.pointcheval.native_crypto"> |  | ||||||
| </manifest> |  | ||||||
| @ -1,93 +0,0 @@ | |||||||
| 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; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,42 +0,0 @@ | |||||||
| 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) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,35 +0,0 @@ | |||||||
| 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!") |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,32 +0,0 @@ | |||||||
| 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 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,142 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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) { |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,5 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto |  | ||||||
| 
 |  | ||||||
| import java.lang.Exception |  | ||||||
| 
 |  | ||||||
| class PlatformVersionException(message : String) : Exception(message) |  | ||||||
| Before Width: | Height: | Size: 120 KiB | 
| Before Width: | Height: | Size: 30 KiB | 
							
								
								
									
										7
									
								
								example/android/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -1,7 +0,0 @@ | |||||||
| gradle-wrapper.jar |  | ||||||
| /.gradle |  | ||||||
| /captures/ |  | ||||||
| /gradlew |  | ||||||
| /gradlew.bat |  | ||||||
| /local.properties |  | ||||||
| GeneratedPluginRegistrant.java |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| 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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| <?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> |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| org.gradle.jvmargs=-Xmx1536M |  | ||||||
| android.enableR8=true |  | ||||||
| android.useAndroidX=true |  | ||||||
| android.enableJetifier=true |  | ||||||
| @ -1,6 +0,0 @@ | |||||||
| #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 |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| 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 +0,0 @@ | |||||||
| a1d04c54a9dc0dec55298921eadf7972 |  | ||||||
| @ -1,90 +0,0 @@ | |||||||
| # 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 |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| 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.10.1 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| #import "GeneratedPluginRegistrant.h" |  | ||||||
| @ -1,69 +0,0 @@ | |||||||
| // 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', |  | ||||||
|             ), |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,144 +0,0 @@ | |||||||
| // 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, |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,205 +0,0 @@ | |||||||
| // 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 |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,180 +0,0 @@ | |||||||
| // 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 |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:native_crypto/native_crypto.dart'; |  | ||||||
| 
 |  | ||||||
| class KemPage extends StatefulWidget { |  | ||||||
|   KemPage({key}) : super(key: key); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   _KemPageState createState() => _KemPageState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _KemPageState extends State<KemPage> { |  | ||||||
|   void test() async { |  | ||||||
|     KeySpec specs = RSAKeySpec(2048); |  | ||||||
|     KeyPair kp = await KeyPair.generate(specs); |  | ||||||
|     print(kp.isComplete); |  | ||||||
|     print(kp.privateKey); |  | ||||||
|     print(kp.privateKey.encoded); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
|     test(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return Container( |  | ||||||
|       child: Center( |  | ||||||
|         child: Text("Not implemented."), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,9 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'package:native_crypto/native_crypto.dart'; |  | ||||||
| 
 |  | ||||||
| class Session { |  | ||||||
|   static SecretKey secretKey; |  | ||||||
|   static AESCipher aesCipher; |  | ||||||
| } |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| // 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); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| // 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), |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,55 +0,0 @@ | |||||||
| // 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,135 +0,0 @@ | |||||||
| // |  | ||||||
| //  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) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,74 +0,0 @@ | |||||||
| // |  | ||||||
| //  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) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,40 +0,0 @@ | |||||||
| // |  | ||||||
| //  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 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,59 +0,0 @@ | |||||||
| // |  | ||||||
| //  KeyGeneration.swift |  | ||||||
| // |  | ||||||
| //  NativeCryptoPlugin |  | ||||||
| // |  | ||||||
| //  Copyright (c) 2020 |  | ||||||
| //  Author: Hugo Pointcheval |  | ||||||
| // |  | ||||||
| import Foundation |  | ||||||
| import CommonCrypto |  | ||||||
| 
 |  | ||||||
| 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 |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     @available(iOS 10.0, watchOS 3.0, tvOS 10.0, *) |  | ||||||
|     func rsaKeypairGen(size : NSNumber) throws -> [Data]? { |  | ||||||
|          |  | ||||||
|         let tagData = UUID().uuidString.data(using: .utf8) |  | ||||||
|          |  | ||||||
|         let isPermanent = true |  | ||||||
|          |  | ||||||
|         let attributes: [CFString: Any] = [ |  | ||||||
|             kSecAttrKeyType: kSecAttrKeyTypeRSA, |  | ||||||
|             kSecAttrKeySizeInBits: (size.intValue * 8), |  | ||||||
|             kSecPrivateKeyAttrs: [ |  | ||||||
|                 kSecAttrIsPermanent: isPermanent, |  | ||||||
|                 kSecAttrApplicationTag: tagData! |  | ||||||
|             ] |  | ||||||
|         ] |  | ||||||
|          |  | ||||||
|         var error: Unmanaged<CFError>? |  | ||||||
|         guard let privKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else { |  | ||||||
|             throw error!.takeRetainedValue() as Error |  | ||||||
|         } |  | ||||||
|         let pubKey = SecKeyCopyPublicKey(privKey) |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         var errorExport: Unmanaged<CFError>? |  | ||||||
|         let data1 = SecKeyCopyExternalRepresentation(pubKey!, &errorExport) |  | ||||||
|         let unwrappedData1 = data1 as Data? |  | ||||||
|          |  | ||||||
|         let data2 = SecKeyCopyExternalRepresentation(privKey, &errorExport) |  | ||||||
|         let unwrappedData2 = data2 as Data? |  | ||||||
|          |  | ||||||
|         return [unwrappedData1!, unwrappedData2!] |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| #import <Flutter/Flutter.h> |  | ||||||
| 
 |  | ||||||
| @interface NativeCryptoPlugin : NSObject<FlutterPlugin> |  | ||||||
| @end |  | ||||||
| @ -1,158 +0,0 @@ | |||||||
| // |  | ||||||
| //  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 "rsaKeypairGen": |  | ||||||
|         let args = call.arguments as! NSDictionary |  | ||||||
|          |  | ||||||
|         let size = args["size"] as! NSNumber |  | ||||||
|          |  | ||||||
|         let keypair : [Data]? |  | ||||||
|          |  | ||||||
|         if #available(iOS 10.0, *) { |  | ||||||
|             do { |  | ||||||
|                 keypair = try KeyGeneration().rsaKeypairGen(size: size) |  | ||||||
|             } catch { |  | ||||||
|                 keypair = nil |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             // Fallback on earlier versions |  | ||||||
|             keypair = nil |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         if keypair != nil { |  | ||||||
|             result(keypair) |  | ||||||
|         } else { |  | ||||||
|             result(FlutterError(code: "KEYPAIRGENERROR", |  | ||||||
|                                 message: "GENERATED KEYPAIR IS EMPTY.", |  | ||||||
|                                 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,19 +0,0 @@ | |||||||
| // 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"; |  | ||||||
| @ -1,77 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'package:native_crypto/src/exceptions.dart'; |  | ||||||
| import 'package:native_crypto/src/kem.dart'; |  | ||||||
| import 'package:native_crypto/src/key.dart'; |  | ||||||
| 
 |  | ||||||
| /// This represents RSA Key Encapsulation Mechanism |  | ||||||
| class RSAKeyEncapsulationMechanism implements KeyEncapsulationMechanism { |  | ||||||
|   bool _isInit = false; |  | ||||||
|   KemMode _mode; |  | ||||||
| 
 |  | ||||||
|   PublicKey _publicKey; |  | ||||||
|   PrivateKey _privateKey; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   KemAlgorithm get algorithm => KemAlgorithm.RSA; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Object get options => null; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool get isInitialized => _isInit; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   KemMode get mode => _mode; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   KeyPair get keypair => KeyPair.from(_publicKey, _privateKey); |  | ||||||
| 
 |  | ||||||
|   RSAKeyEncapsulationMechanism( |  | ||||||
|     KemMode mode, { |  | ||||||
|     KeyPair keyPair, |  | ||||||
|     PublicKey publicKey, |  | ||||||
|   }) { |  | ||||||
|     _mode = mode; |  | ||||||
|     if (_mode == KemMode.ENCAPSULATION) { |  | ||||||
|       if (publicKey != null) { |  | ||||||
|         _isInit = true; |  | ||||||
|         _publicKey = publicKey; |  | ||||||
|       } else if (keyPair != null) { |  | ||||||
|         if (keyPair.publicKey != null) { |  | ||||||
|           _isInit = true; |  | ||||||
|           _publicKey = keyPair.publicKey; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } else if (_mode == KemMode.DECAPSULATION) { |  | ||||||
|       if (keyPair != null) { |  | ||||||
|         if (keyPair.isComplete) { |  | ||||||
|           _isInit = true; |  | ||||||
|           _publicKey = keyPair.publicKey; |  | ||||||
|           _privateKey = keyPair.privateKey; |  | ||||||
|         } else { |  | ||||||
|           throw KemInitException("Keypair must be complete for decapsulation."); |  | ||||||
|         } |  | ||||||
|       } else { |  | ||||||
|         throw KemInitException("You must provide a keypair for decapsulation."); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Encapsulation> encapsulate() { |  | ||||||
|     if (!_isInit || _mode == KemMode.DECAPSULATION) { |  | ||||||
|       throw KemInitException("KEM not properly initialized."); |  | ||||||
|     } |  | ||||||
|     throw UnimplementedError(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<SecretKey> decapsulate(Encapsulation encapsulation) { |  | ||||||
|     if (!_isInit || _mode == KemMode.ENCAPSULATION) { |  | ||||||
|       throw KemInitException("KEM not properly initialized."); |  | ||||||
|     } |  | ||||||
|     throw UnimplementedError(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,101 +0,0 @@ | |||||||
| // Copyright (c) 2021 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'key.dart'; |  | ||||||
| 
 |  | ||||||
| /// Represents different cipher algorithms |  | ||||||
| enum CipherAlgorithm { AES, None } |  | ||||||
| 
 |  | ||||||
| /// Represents different block cipher modes |  | ||||||
| enum BlockCipherMode { CBC, GCM } |  | ||||||
| 
 |  | ||||||
| /// Represents different padding |  | ||||||
| enum PlainTextPadding { PKCS5, None } |  | ||||||
| 
 |  | ||||||
| /// Represents a cipher. |  | ||||||
| /// |  | ||||||
| /// In cryptography, a cipher is an algorithm for performing encryption |  | ||||||
| /// or decryption - a series of well-defined steps that can |  | ||||||
| /// be followed as a procedure. |  | ||||||
| abstract class Cipher { |  | ||||||
|   /// Returns the standard algorithm name for this cipher |  | ||||||
|   CipherAlgorithm get algorithm; |  | ||||||
| 
 |  | ||||||
|   /// Returns the secret key used for this cipher |  | ||||||
|   SecretKey get secretKey; |  | ||||||
| 
 |  | ||||||
|   /// Returns the parameters used for this cipher |  | ||||||
|   CipherParameters get parameters; |  | ||||||
| 
 |  | ||||||
|   /// Returns true if cipher is initialized |  | ||||||
|   bool get isInitialized; |  | ||||||
| 
 |  | ||||||
|   /// Returnes list of supported [CipherParameters] for this cipher |  | ||||||
|   List<CipherParameters> get supportedParameters; |  | ||||||
| 
 |  | ||||||
|   /// Encrypts data. |  | ||||||
|   /// |  | ||||||
|   /// Takes [Uint8List] data as parameter. |  | ||||||
|   /// Returns a [CipherText]. |  | ||||||
|   Future<CipherText> encrypt(Uint8List data); |  | ||||||
| 
 |  | ||||||
|   /// Decrypts cipher text. |  | ||||||
|   /// |  | ||||||
|   /// Takes [CipherText] as parameter. |  | ||||||
|   /// And returns plain text data as [Uint8List]. |  | ||||||
|   Future<Uint8List> decrypt(CipherText cipherText); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Represents a cipher text. |  | ||||||
| /// |  | ||||||
| /// It's the result of an encryption. |  | ||||||
| abstract class CipherText { |  | ||||||
|   /// Returns the standard algorithm name used for this ciphertext. |  | ||||||
|   CipherAlgorithm get algorithm; |  | ||||||
| 
 |  | ||||||
|   /// Returns the data of this ciphertext (in chunks). |  | ||||||
|   List<Uint8List> get bytes; |  | ||||||
| 
 |  | ||||||
|   /// Returns the IV of this cipertext (in chunks). |  | ||||||
|   List<Uint8List> get iv; |  | ||||||
| 
 |  | ||||||
|   /// Returns the chunk number of this cipherText. |  | ||||||
|   int get size; |  | ||||||
| 
 |  | ||||||
|   /// Returns this ciphertext in simple Byte Array format. |  | ||||||
|   Uint8List encode(); |  | ||||||
| 
 |  | ||||||
|   /// Transforms a simple Byte Array to a NativeCrypto cipherText. |  | ||||||
|   void decode(Uint8List src); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Represents a pair of [BlockCipherMode] and [Padding] |  | ||||||
| class CipherParameters { |  | ||||||
|   BlockCipherMode _mode; |  | ||||||
|   PlainTextPadding _padding; |  | ||||||
| 
 |  | ||||||
|   /// Returns mode used in the cipher |  | ||||||
|   BlockCipherMode get mode => _mode; |  | ||||||
| 
 |  | ||||||
|   /// Returns padding used in the cipher |  | ||||||
|   PlainTextPadding get padding => _padding; |  | ||||||
| 
 |  | ||||||
|   CipherParameters(BlockCipherMode mode, PlainTextPadding padding) { |  | ||||||
|     _mode = mode; |  | ||||||
|     _padding = padding; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool operator ==(Object o) { |  | ||||||
|     if (identical(this, o)) return true; |  | ||||||
| 
 |  | ||||||
|     return o is CipherParameters && |  | ||||||
|         o._mode.index == _mode.index && |  | ||||||
|         o._padding.index == _padding.index; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   int get hashCode => _mode.hashCode ^ _padding.hashCode; |  | ||||||
| } |  | ||||||
| @ -1,41 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'exceptions.dart'; |  | ||||||
| import 'platform.dart'; |  | ||||||
| import 'utils.dart'; |  | ||||||
| 
 |  | ||||||
| enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 } |  | ||||||
| 
 |  | ||||||
| /// Represents message digest, or hash function. |  | ||||||
| class MessageDigest { |  | ||||||
|   HashAlgorithm _algo; |  | ||||||
| 
 |  | ||||||
|   /// Returns the standard algorithm name for this digest |  | ||||||
|   HashAlgorithm get algorithm => _algo; |  | ||||||
| 
 |  | ||||||
|   /// Returns true if digest is initialized |  | ||||||
|   bool get isInitialized => (_algo != null); |  | ||||||
| 
 |  | ||||||
|   /// Creates [MessageDigest] with a specific algorithm |  | ||||||
|   MessageDigest(HashAlgorithm algorithm) { |  | ||||||
|     _algo = algorithm; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Creates [MessageDigest] from the name of an algorithm |  | ||||||
|   MessageDigest.getInstance(String algorithm) { |  | ||||||
|     _algo = Utils.getHashAlgorithm(algorithm); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Hashes a message |  | ||||||
|   Future<Uint8List> digest(Uint8List data) async { |  | ||||||
|     if (!isInitialized) { |  | ||||||
|       throw DigestInitException('Digest not properly initialized.'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Uint8List hash = await Platform().digest(data, _algo); |  | ||||||
|     return hash; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,55 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| class NativeCryptoException implements Exception { |  | ||||||
|   String message; |  | ||||||
|   NativeCryptoException(this.message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class UtilsException extends NativeCryptoException { |  | ||||||
|   UtilsException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class KeyException extends NativeCryptoException { |  | ||||||
|   KeyException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class KeyGenerationException extends NativeCryptoException { |  | ||||||
|   KeyGenerationException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class KeyPairGenerationException extends NativeCryptoException { |  | ||||||
|   KeyPairGenerationException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class KeyDerivationException extends NativeCryptoException { |  | ||||||
|   KeyDerivationException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class CipherInitException extends NativeCryptoException { |  | ||||||
|   CipherInitException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class KemInitException extends NativeCryptoException { |  | ||||||
|   KemInitException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class DigestInitException extends NativeCryptoException { |  | ||||||
|   DigestInitException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class DigestException extends NativeCryptoException { |  | ||||||
|   DigestException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class EncryptionException extends NativeCryptoException { |  | ||||||
|   EncryptionException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class DecryptionException extends NativeCryptoException { |  | ||||||
|   DecryptionException(message) : super(message); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class NotImplementedException extends NativeCryptoException { |  | ||||||
|   NotImplementedException(message) : super(message); |  | ||||||
| } |  | ||||||
| @ -1,52 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'key.dart'; |  | ||||||
| 
 |  | ||||||
| enum KemAlgorithm { RSA, ECDH } |  | ||||||
| 
 |  | ||||||
| enum KemMode { ENCAPSULATION, DECAPSULATION } |  | ||||||
| 
 |  | ||||||
| abstract class KeyEncapsulationMechanism { |  | ||||||
|   /// Returns the standard algorithm name for this kem |  | ||||||
|   KemAlgorithm get algorithm; |  | ||||||
| 
 |  | ||||||
|   /// Returns the parameters used for this kem |  | ||||||
|   Object get options; |  | ||||||
| 
 |  | ||||||
|   /// Returns true if kem is initialized |  | ||||||
|   bool get isInitialized; |  | ||||||
| 
 |  | ||||||
|   /// Returns mode used in this kem. |  | ||||||
|   KemMode get mode; |  | ||||||
| 
 |  | ||||||
|   /// Returns key pair used in this kem. |  | ||||||
|   /// |  | ||||||
|   /// Can be an incomplete if just have public key |  | ||||||
|   /// for example. |  | ||||||
|   KeyPair get keypair; |  | ||||||
| 
 |  | ||||||
|   /// Encapsulate key. |  | ||||||
|   /// |  | ||||||
|   /// Returns an [Encapsulation]. |  | ||||||
|   Future<Encapsulation> encapsulate(); |  | ||||||
| 
 |  | ||||||
|   /// Decapsulate key. |  | ||||||
|   /// |  | ||||||
|   /// Takes [Encapsulation] as parameter. |  | ||||||
|   /// And returns plain text key as [SecretKey]. |  | ||||||
|   Future<SecretKey> decapsulate(Encapsulation encapsulation); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| abstract class Encapsulation { |  | ||||||
|   /// Returns the standard algorithm name used for this encapsulation |  | ||||||
|   KemAlgorithm get algorithm; |  | ||||||
| 
 |  | ||||||
|   /// Returns the secret key used in this encapsulation |  | ||||||
|   SecretKey get secretKey; |  | ||||||
| 
 |  | ||||||
|   /// Returns the encapsulated key |  | ||||||
|   Uint8List get key; |  | ||||||
| } |  | ||||||
							
								
								
									
										118
									
								
								lib/src/key.dart
									
									
									
									
									
								
							
							
						
						| @ -1,118 +0,0 @@ | |||||||
| // Copyright (c) 2021 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'package:flutter/services.dart'; |  | ||||||
| import 'platform.dart'; |  | ||||||
| 
 |  | ||||||
| import 'exceptions.dart'; |  | ||||||
| import 'keyspec.dart'; |  | ||||||
| import 'cipher.dart'; |  | ||||||
| import 'utils.dart'; |  | ||||||
| 
 |  | ||||||
| /// This is the base class of all key types. |  | ||||||
| abstract class Key { |  | ||||||
|   Uint8List _bytes; |  | ||||||
|   String _algo; |  | ||||||
| 
 |  | ||||||
|   /// Returns key as raw byte array. |  | ||||||
|   Uint8List get encoded => _bytes; |  | ||||||
| 
 |  | ||||||
|   /// Returns the standard algorithm name for this key |  | ||||||
|   String get algorithm => _algo; |  | ||||||
| 
 |  | ||||||
|   /// Returns the true if this key is null or empty. |  | ||||||
|   bool get isEmpty => (_bytes == null || _bytes.length == 0); |  | ||||||
| 
 |  | ||||||
|   Key({Uint8List bytes, String algorithm}) { |  | ||||||
|     _bytes = bytes; |  | ||||||
|     _algo = algorithm; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// This represents a secret key, usefull in |  | ||||||
| /// algorithms like AES or BlowFish. |  | ||||||
| class SecretKey extends Key { |  | ||||||
|   /// Creates a key from raw byte array |  | ||||||
|   SecretKey.fromBytes(Uint8List bytes, |  | ||||||
|       {CipherAlgorithm algorithm: CipherAlgorithm.None}) |  | ||||||
|       : super(bytes: bytes, algorithm: algorithm.name); |  | ||||||
| 
 |  | ||||||
|   /// Creates a key from a specific size. |  | ||||||
|   static Future<SecretKey> generate(int size, CipherAlgorithm algorithm) async { |  | ||||||
|     if (algorithm == null) { |  | ||||||
|       throw KeyException("Algorithm can't be null"); |  | ||||||
|     } else if (algorithm == CipherAlgorithm.AES) { |  | ||||||
|       List<int> _supportedSizes = [128, 192, 256]; |  | ||||||
|       if (!_supportedSizes.contains(size)) { |  | ||||||
|         throw KeyException("AES must be 128, 192 or 256 bits long."); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       Uint8List _key = await Platform().keygen(size); |  | ||||||
|       return SecretKey.fromBytes(_key, algorithm: algorithm); |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw KeyException(e); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// This represents a keypair, usefull in |  | ||||||
| /// algorithms like RSA. |  | ||||||
| class KeyPair extends Key { |  | ||||||
|   PublicKey _publicKey; |  | ||||||
|   PrivateKey _privateKey; |  | ||||||
| 
 |  | ||||||
|   /// Returns public key of this key pair. |  | ||||||
|   PublicKey get publicKey => _publicKey; |  | ||||||
| 
 |  | ||||||
|   /// Returns private key of this key pair. |  | ||||||
|   PrivateKey get privateKey => _privateKey; |  | ||||||
| 
 |  | ||||||
|   /// Returns true if key pair contains public AND private keys |  | ||||||
|   bool get isComplete => (_publicKey != null && _privateKey != null); |  | ||||||
| 
 |  | ||||||
|   /// Creates a key pair from public and private keys. |  | ||||||
|   KeyPair.from(PublicKey publicKey, PrivateKey privateKey, {String algorithm}) { |  | ||||||
|     _publicKey = publicKey; |  | ||||||
|     _privateKey = privateKey; |  | ||||||
|     _algo = algorithm; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Creates a key pair from a specific size. |  | ||||||
|   static Future<KeyPair> generate(KeySpec keySpec) async { |  | ||||||
|     List<String> _supportedAlgorithms = ["RSA"]; |  | ||||||
|     if (!_supportedAlgorithms.contains(keySpec.algorithm)) { |  | ||||||
|       throw KeyException(keySpec.algorithm + " not supported!"); |  | ||||||
|     } |  | ||||||
|     if (keySpec.algorithm == "RSA") { |  | ||||||
|       RSAKeySpec spec = keySpec; |  | ||||||
|       try { |  | ||||||
|         List<Uint8List> kp = await Platform().rsaKeypairGen(spec.size); |  | ||||||
|         PublicKey _publicKey = PublicKey.fromBytes(kp.first, "RSA"); |  | ||||||
|         PrivateKey _privateKey = PrivateKey.fromBytes(kp.last, "RSA"); |  | ||||||
|         return KeyPair.from(_publicKey, _privateKey, algorithm: "RSA"); |  | ||||||
|       } on PlatformException catch (e) { |  | ||||||
|         throw KeyException(e); |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       throw NotImplementedException("KeyPair generation not yet implemented."); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// This represents a public key |  | ||||||
| class PublicKey extends Key { |  | ||||||
|   /// Creates a public key from raw byte array |  | ||||||
|   PublicKey.fromBytes(Uint8List bytes, String algorithm) |  | ||||||
|       : super(bytes: bytes, algorithm: algorithm); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// This represents a private key |  | ||||||
| class PrivateKey extends Key { |  | ||||||
|   /// Creates a private key from raw byte array |  | ||||||
|   PrivateKey.fromBytes(Uint8List bytes, String algorithm) |  | ||||||
|       : super(bytes: bytes, algorithm: algorithm); |  | ||||||
| } |  | ||||||
| @ -1,81 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'package:native_crypto/src/digest.dart'; |  | ||||||
| import 'package:native_crypto/src/exceptions.dart'; |  | ||||||
| import 'package:native_crypto/src/key.dart'; |  | ||||||
| 
 |  | ||||||
| import 'platform.dart'; |  | ||||||
| 
 |  | ||||||
| enum KdfAlgorithm { PBKDF2, SCrypt } |  | ||||||
| 
 |  | ||||||
| /// Represents a Key Derivation Function |  | ||||||
| abstract class KeyDerivation { |  | ||||||
|   /// Returns the standard algorithm name for this key derivation function |  | ||||||
|   KdfAlgorithm get algorithm; |  | ||||||
| 
 |  | ||||||
|   /// Returns the derivated key |  | ||||||
|   SecretKey get key; |  | ||||||
| 
 |  | ||||||
|   /// Derive key |  | ||||||
|   Future<void> derive(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class PBKDF2 implements KeyDerivation { |  | ||||||
|   SecretKey _sk; |  | ||||||
| 
 |  | ||||||
|   int _length; |  | ||||||
|   int _iteration; |  | ||||||
|   HashAlgorithm _hash; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   KdfAlgorithm get algorithm => KdfAlgorithm.PBKDF2; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   SecretKey get key => _sk; |  | ||||||
| 
 |  | ||||||
|   PBKDF2({ |  | ||||||
|     int keyLength: 32, |  | ||||||
|     int iteration: 10000, |  | ||||||
|     HashAlgorithm hash: HashAlgorithm.SHA256, |  | ||||||
|   }) { |  | ||||||
|     _length = keyLength; |  | ||||||
|     _iteration = iteration; |  | ||||||
|     _hash = hash; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<void> derive({String password, String salt}) async { |  | ||||||
|     if (password == null || salt == null) { |  | ||||||
|       throw KeyDerivationException("Password or Salt can't be null!"); |  | ||||||
|     } |  | ||||||
|     if (_hash == null) { |  | ||||||
|       throw KeyDerivationException("Hash Algorithm can't be null!"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Uint8List derivation = await Platform().pbkdf2( |  | ||||||
|       password, |  | ||||||
|       salt, |  | ||||||
|       keyLength: _length, |  | ||||||
|       iteration: _iteration, |  | ||||||
|       algorithm: _hash, |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     _sk = SecretKey.fromBytes(derivation); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class Scrypt implements KeyDerivation { |  | ||||||
|   @override |  | ||||||
|   KdfAlgorithm get algorithm => KdfAlgorithm.SCrypt; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   SecretKey get key => throw UnimplementedError(); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<void> derive() { |  | ||||||
|     throw UnimplementedError(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| /// This represents security parameters. |  | ||||||
| abstract class KeySpec { |  | ||||||
|   /// Returns the standard algorithm name for this key |  | ||||||
|   String get algorithm; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class RSAKeySpec implements KeySpec { |  | ||||||
|   int _size; |  | ||||||
| 
 |  | ||||||
|   String get algorithm => "RSA"; |  | ||||||
| 
 |  | ||||||
|   /// Returns the size of RSA keys |  | ||||||
|   int get size => _size; |  | ||||||
| 
 |  | ||||||
|   RSAKeySpec(int size) { |  | ||||||
|     _size = size; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,161 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'package:flutter/services.dart'; |  | ||||||
| 
 |  | ||||||
| import 'cipher.dart'; |  | ||||||
| import 'digest.dart'; |  | ||||||
| import 'exceptions.dart'; |  | ||||||
| import 'utils.dart'; |  | ||||||
| 
 |  | ||||||
| /// Represents a platform, and is usefull to calling |  | ||||||
| /// methods from a specific platform. |  | ||||||
| class Platform { |  | ||||||
|   /// Contains the channel for platform specific code. |  | ||||||
|   static const MethodChannel _channel = const MethodChannel('native.crypto'); |  | ||||||
| 
 |  | ||||||
|   /// Calls native code. |  | ||||||
|   static Future<T> call<T>(String method, [Map<String, dynamic> arguments]) { |  | ||||||
|     return _channel.invokeMethod(method, arguments); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Calls native code that return list. |  | ||||||
|   static Future<List<T>> callList<T>(String method, |  | ||||||
|       [Map<String, dynamic> arguments]) { |  | ||||||
|     return _channel.invokeListMethod(method, arguments); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Digests a message with a specific algorithm |  | ||||||
|   /// |  | ||||||
|   /// Takes message and algorithm as parameters. |  | ||||||
|   /// |  | ||||||
|   /// Returns a hash as [Uint8List]. |  | ||||||
|   Future<Uint8List> digest( |  | ||||||
|     Uint8List message, |  | ||||||
|     HashAlgorithm algorithm, |  | ||||||
|   ) async { |  | ||||||
|     try { |  | ||||||
|       final Uint8List hash = await call('digest', <String, dynamic>{ |  | ||||||
|         'message': message, |  | ||||||
|         'algorithm': algorithm.name, |  | ||||||
|       }); |  | ||||||
|       return hash; |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw DigestException(e.code + " : " + e.message); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Calls native PBKDF2. |  | ||||||
|   /// |  | ||||||
|   /// Takes password and salt as parameters. |  | ||||||
|   /// And optionnally keyLength in bytes, number of iterations and hash algorithm. |  | ||||||
|   /// |  | ||||||
|   /// Returns a key as [Uint8List]. |  | ||||||
|   Future<Uint8List> pbkdf2( |  | ||||||
|     String password, |  | ||||||
|     String salt, { |  | ||||||
|     int keyLength: 32, |  | ||||||
|     int iteration: 10000, |  | ||||||
|     HashAlgorithm algorithm: HashAlgorithm.SHA256, |  | ||||||
|   }) async { |  | ||||||
|     try { |  | ||||||
|       final Uint8List key = await call('pbkdf2', <String, dynamic>{ |  | ||||||
|         'password': password, |  | ||||||
|         'salt': salt, |  | ||||||
|         'keyLength': keyLength, |  | ||||||
|         'iteration': iteration, |  | ||||||
|         'algorithm': algorithm.name, |  | ||||||
|       }); |  | ||||||
|       return key; |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw KeyDerivationException(e.code + " : " + e.message); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Generates a random key. |  | ||||||
|   /// |  | ||||||
|   /// Takes size in bits. |  | ||||||
|   /// |  | ||||||
|   /// Returns a key as [Uint8List]. |  | ||||||
|   Future<Uint8List> keygen(int size) async { |  | ||||||
|     try { |  | ||||||
|       final Uint8List key = await call('keygen', <String, dynamic>{ |  | ||||||
|         'size': size, |  | ||||||
|       }); |  | ||||||
|       return key; |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw KeyGenerationException(e.code + " : " + e.message); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Generates an RSA key pair. |  | ||||||
|   /// |  | ||||||
|   /// Takes size in bits. |  | ||||||
|   /// |  | ||||||
|   /// Returns a key pair as list of [Uint8List], the public key is the |  | ||||||
|   /// first element, and the private is the last. |  | ||||||
|   Future<List<Uint8List>> rsaKeypairGen(int size) async { |  | ||||||
|     try { |  | ||||||
|       final List<Uint8List> keypair = |  | ||||||
|           await callList('rsaKeypairGen', <String, dynamic>{ |  | ||||||
|         'size': size, |  | ||||||
|       }); |  | ||||||
|       return keypair; |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw KeyPairGenerationException(e.code + " : " + e.message); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Encrypts data with a secret key and algorithm. |  | ||||||
|   /// |  | ||||||
|   /// Takes data, key, algorithm, mode and padding as parameters. |  | ||||||
|   /// |  | ||||||
|   /// Encrypts data and returns cipher text |  | ||||||
|   /// and IV as a list of [Uint8List]. |  | ||||||
|   Future<List<Uint8List>> encrypt( |  | ||||||
|     Uint8List data, |  | ||||||
|     Uint8List key, |  | ||||||
|     CipherAlgorithm algorithm, |  | ||||||
|     CipherParameters parameters, |  | ||||||
|   ) async { |  | ||||||
|     try { |  | ||||||
|       final List<Uint8List> payload = |  | ||||||
|           await callList('encrypt', <String, dynamic>{ |  | ||||||
|         'data': data, |  | ||||||
|         'key': key, |  | ||||||
|         'algorithm': algorithm.name, |  | ||||||
|         'mode': parameters.mode.name, |  | ||||||
|         'padding': parameters.padding.name, |  | ||||||
|       }); |  | ||||||
|       return payload; |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw EncryptionException(e.code + " : " + e.message); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Decrypts a payload with a secret key and algorithm. |  | ||||||
|   /// |  | ||||||
|   /// The payload must be a list of `Uint8List` |  | ||||||
|   /// with encrypted cipher as first and IV as second member. |  | ||||||
|   Future<Uint8List> decrypt( |  | ||||||
|     List<Uint8List> payload, |  | ||||||
|     Uint8List key, |  | ||||||
|     CipherAlgorithm algorithm, |  | ||||||
|     CipherParameters parameters, |  | ||||||
|   ) async { |  | ||||||
|     try { |  | ||||||
|       final Uint8List data = await call('decrypt', <String, dynamic>{ |  | ||||||
|         'payload': payload, |  | ||||||
|         'key': key, |  | ||||||
|         'algorithm': algorithm.name, |  | ||||||
|         'mode': parameters.mode.name, |  | ||||||
|         'padding': parameters.padding.name, |  | ||||||
|       }); |  | ||||||
|       return data; |  | ||||||
|     } on PlatformException catch (e) { |  | ||||||
|       throw DecryptionException(e.code + " : " + e.message); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,215 +0,0 @@ | |||||||
| // Copyright (c) 2021 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'package:native_crypto/native_crypto.dart'; |  | ||||||
| 
 |  | ||||||
| import '../cipher.dart'; |  | ||||||
| import '../exceptions.dart'; |  | ||||||
| import '../key.dart'; |  | ||||||
| import '../platform.dart'; |  | ||||||
| import '../utils.dart'; |  | ||||||
| 
 |  | ||||||
| /// Defines all available key sizes. |  | ||||||
| enum AESKeySize { bits128, bits192, bits256 } |  | ||||||
| 
 |  | ||||||
| extension AESKeySizeExtension on AESKeySize { |  | ||||||
|   int get length { |  | ||||||
|     Map<AESKeySize, int> table = <AESKeySize, int>{ |  | ||||||
|       AESKeySize.bits128: 128, |  | ||||||
|       AESKeySize.bits192: 192, |  | ||||||
|       AESKeySize.bits256: 256, |  | ||||||
|     }; |  | ||||||
|     return table[this]; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class AESCipher implements Cipher { |  | ||||||
|   SecretKey _sk; |  | ||||||
|   CipherParameters _params; |  | ||||||
|   bool _isInit; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   CipherAlgorithm get algorithm => CipherAlgorithm.AES; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   SecretKey get secretKey => _sk; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   CipherParameters get parameters => _params; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool get isInitialized => _isInit; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   List<CipherParameters> get supportedParameters => [ |  | ||||||
|         CipherParameters(BlockCipherMode.CBC, PlainTextPadding.PKCS5), |  | ||||||
|       ]; |  | ||||||
| 
 |  | ||||||
|   /// Creates an AES cipher with specified secretKey and mode/padding |  | ||||||
|   AESCipher(SecretKey secretKey, CipherParameters parameters) { |  | ||||||
|     if (secretKey.algorithm != CipherAlgorithm.AES.name) { |  | ||||||
|       List<int> _supportedSizes = [128, 192, 256]; |  | ||||||
|       if (!_supportedSizes.contains(secretKey.encoded.length)) { |  | ||||||
|         throw CipherInitException("Invalid key length!"); |  | ||||||
|       } |  | ||||||
|     } else if (!supportedParameters.contains(parameters)) { |  | ||||||
|       throw CipherInitException("Invalid cipher parameters."); |  | ||||||
|     } |  | ||||||
|     _sk = secretKey; |  | ||||||
|     _params = parameters; |  | ||||||
|     _isInit = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Generates a secret key of specified size, then creates an AES cipher. |  | ||||||
|   static Future<AESCipher> generate( |  | ||||||
|       AESKeySize size, CipherParameters parameters) async { |  | ||||||
|     SecretKey _sk = await SecretKey.generate(size.length, CipherAlgorithm.AES); |  | ||||||
|     return AESCipher(_sk, parameters); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<CipherText> encrypt(Uint8List data) async { |  | ||||||
|     if (!_isInit) { |  | ||||||
|       throw CipherInitException('Cipher not properly initialized.'); |  | ||||||
|     } else if (_sk == null || _sk.isEmpty) { |  | ||||||
|       throw CipherInitException('Invalid key size.'); |  | ||||||
|     } |  | ||||||
|     Uint8List dataToEncrypt; |  | ||||||
|     int maxSize = 33554432; |  | ||||||
|     AESCipherText cipherText = AESCipherText.empty(); |  | ||||||
|     // If data is bigger than 32mB -> split in chunks |  | ||||||
|     if (data.length > maxSize) { |  | ||||||
|       int chunkNb = (data.length / maxSize).ceil(); |  | ||||||
|       for (var i = 0; i < chunkNb; i++) { |  | ||||||
|         if (i < (chunkNb - 1)) { |  | ||||||
|           dataToEncrypt = data.sublist(i * maxSize, (i + 1) * maxSize); |  | ||||||
|         } else { |  | ||||||
|           dataToEncrypt = data.sublist(i * maxSize); |  | ||||||
|         } |  | ||||||
|         List<Uint8List> c = await Platform() |  | ||||||
|             .encrypt(dataToEncrypt, _sk.encoded, algorithm, _params); |  | ||||||
|         cipherText.append(c[0], c[1]); |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       List<Uint8List> c = |  | ||||||
|           await Platform().encrypt(data, _sk.encoded, algorithm, _params); |  | ||||||
|       cipherText.append(c[0], c[1]); |  | ||||||
|     } |  | ||||||
|     return cipherText; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Uint8List> decrypt(CipherText cipherText) async { |  | ||||||
|     if (cipherText.algorithm != CipherAlgorithm.AES) { |  | ||||||
|       throw DecryptionException("This cipher text's algorithm is not AES: " + |  | ||||||
|           cipherText.algorithm.name + |  | ||||||
|           "\nYou must use an AESCipherText."); |  | ||||||
|     } else if (!_isInit) { |  | ||||||
|       throw CipherInitException('Cipher not properly initialized.'); |  | ||||||
|     } else if (_sk == null || _sk.isEmpty) { |  | ||||||
|       throw CipherInitException('Invalid key size.'); |  | ||||||
|     } else if (cipherText.bytes.length != cipherText.iv.length) { |  | ||||||
|       throw DecryptionException( |  | ||||||
|           "This cipher text's bytes chunks length is not the same as iv chunks length"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     BytesBuilder decryptedData = BytesBuilder(); |  | ||||||
|     if (cipherText.size > 1) { |  | ||||||
|       for (var i = 0; i < cipherText.size; i++) { |  | ||||||
|         List<Uint8List> payload = [cipherText.bytes[i], cipherText.iv[i]]; |  | ||||||
|         Uint8List d = |  | ||||||
|             await Platform().decrypt(payload, _sk.encoded, algorithm, _params); |  | ||||||
|         decryptedData.add(d); |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       List<Uint8List> payload = [cipherText.bytes[0], cipherText.iv[0]]; |  | ||||||
|       Uint8List d = |  | ||||||
|           await Platform().decrypt(payload, _sk.encoded, algorithm, _params); |  | ||||||
|       decryptedData.add(d); |  | ||||||
|     } |  | ||||||
|     return decryptedData.toBytes(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class AESCipherText implements CipherText { |  | ||||||
|   List<Uint8List> _bytes; |  | ||||||
|   List<Uint8List> _iv; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   CipherAlgorithm get algorithm => CipherAlgorithm.AES; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   List<Uint8List> get bytes => _bytes; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   List<Uint8List> get iv => _iv; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   int get size => _bytes.length; |  | ||||||
| 
 |  | ||||||
|   AESCipherText(Uint8List bytes, Uint8List iv) { |  | ||||||
|     _bytes = List.from([bytes]); |  | ||||||
|     _iv = List.from([iv]); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   AESCipherText.from(List<Uint8List> bytes, List<Uint8List> iv) { |  | ||||||
|     _bytes = bytes; |  | ||||||
|     _iv = iv; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   AESCipherText.empty() { |  | ||||||
|     _bytes = <Uint8List>[]; |  | ||||||
|     _iv = <Uint8List>[]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   void append(Uint8List bytes, Uint8List iv) { |  | ||||||
|     _bytes.add(bytes); |  | ||||||
|     _iv.add(iv); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns this ciphertext in [Uint8List] format. |  | ||||||
|   /// |  | ||||||
|   /// Encoding |  | ||||||
|   /// -------- |  | ||||||
|   /// Uint8List encoding is : IV_1 + M_1 + IV_2 + M_2 + ... + IV_n + M_n |  | ||||||
|   /// |  | ||||||
|   /// Where **IV_k** is the IV of the cipher text **M_k** |  | ||||||
|   /// |  | ||||||
|   /// IV is **always** 16 bytes long, And the **M** are all max |  | ||||||
|   /// size (of 33 554 480 bytes) except the last one which is shorter than the others. |  | ||||||
|   Uint8List encode() { |  | ||||||
|     BytesBuilder builder = BytesBuilder(); |  | ||||||
|     for (var i = 0; i < size; i++) { |  | ||||||
|       builder.add(_iv[i]); |  | ||||||
|       builder.add(_bytes[i]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return builder.toBytes(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Transforms a [Uint8List] to a *NativeCrypto* cipherText. |  | ||||||
|   /// |  | ||||||
|   /// Decoding |  | ||||||
|   /// -------- |  | ||||||
|   /// See the list as a chain of chunks (IV and Messages) |  | ||||||
|   /// `[IV][MESSAGE][IV][MESSAGE] ... [IV][MESSA...]` |  | ||||||
|   /// |  | ||||||
|   /// Chunk length is IV length + Message length = 16 + 33 554 480 bytes |  | ||||||
|   void decode(Uint8List src) { |  | ||||||
|     ByteBuffer buffer = src.buffer; |  | ||||||
| 
 |  | ||||||
|     int chunkSize = 16 + 33554480; |  | ||||||
|     int chunkNb = (buffer.lengthInBytes / chunkSize).ceil(); |  | ||||||
| 
 |  | ||||||
|     for (var i = 0; i < chunkNb; i++) { |  | ||||||
|       _iv.add(buffer.asUint8List(i * chunkSize, 16)); |  | ||||||
|       if (i < (chunkNb - 1)) { |  | ||||||
|         _bytes.add(buffer.asUint8List(16 + i * chunkSize, 33554480)); |  | ||||||
|       } else { |  | ||||||
|         _bytes.add(buffer.asUint8List(16 + i * chunkSize)); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,141 +0,0 @@ | |||||||
| // Copyright (c) 2020 |  | ||||||
| // Author: Hugo Pointcheval |  | ||||||
| 
 |  | ||||||
| import 'package:flutter/foundation.dart'; |  | ||||||
| 
 |  | ||||||
| import 'cipher.dart'; |  | ||||||
| import 'digest.dart'; |  | ||||||
| import 'exceptions.dart'; |  | ||||||
| import 'kem.dart'; |  | ||||||
| import 'keyderivation.dart'; |  | ||||||
| 
 |  | ||||||
| extension HashAlgorithmExtension on HashAlgorithm { |  | ||||||
|   String get name => describeEnum(this).toLowerCase(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extension KdfAlgorithmExtension on KdfAlgorithm { |  | ||||||
|   String get name => describeEnum(this).toLowerCase(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extension CipherAlgorithmExtension on CipherAlgorithm { |  | ||||||
|   String get name => describeEnum(this).toLowerCase(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extension KemAlgorithmExtension on KemAlgorithm { |  | ||||||
|   String get name => describeEnum(this).toLowerCase(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extension BlockCipherModeExtension on BlockCipherMode { |  | ||||||
|   String get name => describeEnum(this).toLowerCase(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extension PlainTextPaddingExtension on PlainTextPadding { |  | ||||||
|   String get name => describeEnum(this).toLowerCase(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class Utils { |  | ||||||
|   /// Returns [HashAlgorithm] from his name. |  | ||||||
|   static HashAlgorithm getHashAlgorithm(String algorithm) { |  | ||||||
|     String _query = algorithm.toLowerCase(); |  | ||||||
|     for (HashAlgorithm h in HashAlgorithm.values) { |  | ||||||
|       if (_query == h.name) { |  | ||||||
|         return h; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     throw UtilsException("Unknown hash algorithm!"); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns all available [HashAlgorithm] as String list |  | ||||||
|   static List<String> getAvailableHashAlgorithms() { |  | ||||||
|     List<String> _res = []; |  | ||||||
|     for (HashAlgorithm h in HashAlgorithm.values) { |  | ||||||
|       _res.add(h.name); |  | ||||||
|     } |  | ||||||
|     return _res; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns [KdfAlgorithm] from his name. |  | ||||||
|   static KdfAlgorithm getKdfAlgorithm(String algorithm) { |  | ||||||
|     String _query = algorithm.toLowerCase(); |  | ||||||
|     for (KdfAlgorithm h in KdfAlgorithm.values) { |  | ||||||
|       if (_query == h.name) { |  | ||||||
|         return h; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     throw UtilsException("Unknown key derivation algorithm!"); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns all available [KdfAlgorithm] as String list |  | ||||||
|   static List<String> getAvailableKdfAlgorithms() { |  | ||||||
|     List<String> _res = []; |  | ||||||
|     for (KdfAlgorithm h in KdfAlgorithm.values) { |  | ||||||
|       _res.add(h.name); |  | ||||||
|     } |  | ||||||
|     return _res; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns [CipherAlgorithm] from his name. |  | ||||||
|   static CipherAlgorithm getCipherAlgorithm(String algorithm) { |  | ||||||
|     String _query = algorithm.toLowerCase(); |  | ||||||
|     for (CipherAlgorithm c in CipherAlgorithm.values) { |  | ||||||
|       if (_query == c.name) { |  | ||||||
|         return c; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     throw UtilsException("Unknown cipher algorithm!"); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns all available [CipherAlgorithm] as String list |  | ||||||
|   static List<String> getAvailableCipherAlgorithms() { |  | ||||||
|     List<String> _res = []; |  | ||||||
|     for (CipherAlgorithm c in CipherAlgorithm.values) { |  | ||||||
|       _res.add(c.name); |  | ||||||
|     } |  | ||||||
|     return _res; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns [KemAlgorithm] from his name. |  | ||||||
|   static KemAlgorithm getKemAlgorithm(String algorithm) { |  | ||||||
|     String _query = algorithm.toLowerCase(); |  | ||||||
|     for (KemAlgorithm k in KemAlgorithm.values) { |  | ||||||
|       if (_query == k.name) { |  | ||||||
|         return k; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     throw UtilsException("Unknown KEM algorithm!"); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns all available [KemAlgorithm] as String list |  | ||||||
|   static List<String> getAvailableKemAlgorithms() { |  | ||||||
|     List<String> _res = []; |  | ||||||
|     for (KemAlgorithm k in KemAlgorithm.values) { |  | ||||||
|       _res.add(k.name); |  | ||||||
|     } |  | ||||||
|     return _res; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Returns [CipherParameters] from string. |  | ||||||
|   /// |  | ||||||
|   /// For example, `CBC/PKCS5` gives a CipherParameters with |  | ||||||
|   /// CBC mode and PKCS5 as padding. |  | ||||||
|   static CipherParameters getCipherParameters(String parameters) { |  | ||||||
|     List<String> _query = parameters.toLowerCase().split("/"); |  | ||||||
|     BlockCipherMode _mode; |  | ||||||
|     PlainTextPadding _padding; |  | ||||||
|     for (BlockCipherMode b in BlockCipherMode.values) { |  | ||||||
|       if (_query[0] == b.name) { |  | ||||||
|         _mode = b; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     for (PlainTextPadding p in PlainTextPadding.values) { |  | ||||||
|       if (_query[1] == p.name) { |  | ||||||
|         _padding = p; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     if (_mode == null || _padding == null) { |  | ||||||
|       throw UtilsException("Unknown parameters!"); |  | ||||||
|     } else { |  | ||||||
|       return CipherParameters(_mode, _padding); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										389
									
								
								native_crypto/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,389 @@ | |||||||
|  | # 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 | ||||||
|  | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,dart,flutter,intellij+all,kotlin,linux,swift,windows | ||||||
|  | 
 | ||||||
|  | ### Dart ### | ||||||
|  | # See https://www.dartlang.org/guides/libraries/private-files | ||||||
|  | 
 | ||||||
|  | # Files and directories created by pub | ||||||
|  | .dart_tool/ | ||||||
|  | .packages | ||||||
|  | build/ | ||||||
|  | # If you're building an application, you may want to check-in your pubspec.lock | ||||||
|  | pubspec.lock | ||||||
|  | 
 | ||||||
|  | # Directory created by dartdoc | ||||||
|  | # If you don't generate documentation locally you can remove this line. | ||||||
|  | doc/api/ | ||||||
|  | 
 | ||||||
|  | # dotenv environment variables file | ||||||
|  | .env* | ||||||
|  | 
 | ||||||
|  | # Avoid committing generated Javascript files: | ||||||
|  | *.dart.js | ||||||
|  | *.info.json      # Produced by the --dump-info flag. | ||||||
|  | *.js             # When generated by dart2js. Don't specify *.js if your | ||||||
|  |                  # project includes source files written in JavaScript. | ||||||
|  | *.js_ | ||||||
|  | *.js.deps | ||||||
|  | *.js.map | ||||||
|  | 
 | ||||||
|  | .flutter-plugins | ||||||
|  | .flutter-plugins-dependencies | ||||||
|  | 
 | ||||||
|  | ### Dart Patch ### | ||||||
|  | # dotenv environment variables file | ||||||
|  | .env | ||||||
|  | 
 | ||||||
|  | ### Flutter ### | ||||||
|  | # Flutter/Dart/Pub related | ||||||
|  | **/doc/api/ | ||||||
|  | .fvm/ | ||||||
|  | .pub-cache/ | ||||||
|  | .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/**/gradle-wrapper.jar | ||||||
|  | **/android/.gradle | ||||||
|  | **/android/captures/ | ||||||
|  | **/android/gradlew | ||||||
|  | **/android/gradlew.bat | ||||||
|  | **/android/key.properties | ||||||
|  | **/android/local.properties | ||||||
|  | **/android/**/GeneratedPluginRegistrant.java | ||||||
|  | 
 | ||||||
|  | # iOS/XCode related | ||||||
|  | **/ios/**/*.mode1v3 | ||||||
|  | **/ios/**/*.mode2v3 | ||||||
|  | **/ios/**/*.moved-aside | ||||||
|  | **/ios/**/*.pbxuser | ||||||
|  | **/ios/**/*.perspectivev3 | ||||||
|  | **/ios/**/*sync/ | ||||||
|  | **/ios/**/.sconsign.dblite | ||||||
|  | **/ios/**/.tags* | ||||||
|  | **/ios/**/.vagrant/ | ||||||
|  | **/ios/**/DerivedData/ | ||||||
|  | **/ios/**/Icon? | ||||||
|  | **/ios/**/Pods/ | ||||||
|  | **/ios/**/.symlinks/ | ||||||
|  | **/ios/**/profile | ||||||
|  | **/ios/**/xcuserdata | ||||||
|  | **/ios/.generated/ | ||||||
|  | **/ios/Flutter/.last_build_id | ||||||
|  | **/ios/Flutter/App.framework | ||||||
|  | **/ios/Flutter/Flutter.framework | ||||||
|  | **/ios/Flutter/Flutter.podspec | ||||||
|  | **/ios/Flutter/Generated.xcconfig | ||||||
|  | **/ios/Flutter/app.flx | ||||||
|  | **/ios/Flutter/app.zip | ||||||
|  | **/ios/Flutter/flutter_assets/ | ||||||
|  | **/ios/Flutter/flutter_export_environment.sh | ||||||
|  | **/ios/ServiceDefinitions.json | ||||||
|  | **/ios/Runner/GeneratedPluginRegistrant.* | ||||||
|  | 
 | ||||||
|  | # Exceptions to above rules. | ||||||
|  | !**/ios/**/default.mode1v3 | ||||||
|  | !**/ios/**/default.mode2v3 | ||||||
|  | !**/ios/**/default.pbxuser | ||||||
|  | !**/ios/**/default.perspectivev3 | ||||||
|  | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages | ||||||
|  | 
 | ||||||
|  | ### Intellij+all ### | ||||||
|  | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider | ||||||
|  | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||||||
|  | 
 | ||||||
|  | # User-specific stuff | ||||||
|  | .idea/**/workspace.xml | ||||||
|  | .idea/**/tasks.xml | ||||||
|  | .idea/**/usage.statistics.xml | ||||||
|  | .idea/**/dictionaries | ||||||
|  | .idea/**/shelf | ||||||
|  | 
 | ||||||
|  | # AWS User-specific | ||||||
|  | .idea/**/aws.xml | ||||||
|  | 
 | ||||||
|  | # Generated files | ||||||
|  | .idea/**/contentModel.xml | ||||||
|  | 
 | ||||||
|  | # Sensitive or high-churn files | ||||||
|  | .idea/**/dataSources/ | ||||||
|  | .idea/**/dataSources.ids | ||||||
|  | .idea/**/dataSources.local.xml | ||||||
|  | .idea/**/sqlDataSources.xml | ||||||
|  | .idea/**/dynamic.xml | ||||||
|  | .idea/**/uiDesigner.xml | ||||||
|  | .idea/**/dbnavigator.xml | ||||||
|  | 
 | ||||||
|  | # Gradle | ||||||
|  | .idea/**/gradle.xml | ||||||
|  | .idea/**/libraries | ||||||
|  | 
 | ||||||
|  | # Gradle and Maven with auto-import | ||||||
|  | # 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 | ||||||
|  | # auto-import. | ||||||
|  | # .idea/artifacts | ||||||
|  | # .idea/compiler.xml | ||||||
|  | # .idea/jarRepositories.xml | ||||||
|  | # .idea/modules.xml | ||||||
|  | # .idea/*.iml | ||||||
|  | # .idea/modules | ||||||
|  | # *.iml | ||||||
|  | # *.ipr | ||||||
|  | 
 | ||||||
|  | # CMake | ||||||
|  | cmake-build-*/ | ||||||
|  | 
 | ||||||
|  | # Mongo Explorer plugin | ||||||
|  | .idea/**/mongoSettings.xml | ||||||
|  | 
 | ||||||
|  | # File-based project format | ||||||
|  | *.iws | ||||||
|  | 
 | ||||||
|  | # IntelliJ | ||||||
|  | out/ | ||||||
|  | 
 | ||||||
|  | # mpeltonen/sbt-idea plugin | ||||||
|  | .idea_modules/ | ||||||
|  | 
 | ||||||
|  | # JIRA plugin | ||||||
|  | atlassian-ide-plugin.xml | ||||||
|  | 
 | ||||||
|  | # Cursive Clojure plugin | ||||||
|  | .idea/replstate.xml | ||||||
|  | 
 | ||||||
|  | # Crashlytics plugin (for Android Studio and IntelliJ) | ||||||
|  | com_crashlytics_export_strings.xml | ||||||
|  | crashlytics.properties | ||||||
|  | crashlytics-build.properties | ||||||
|  | fabric.properties | ||||||
|  | 
 | ||||||
|  | # Editor-based Rest Client | ||||||
|  | .idea/httpRequests | ||||||
|  | 
 | ||||||
|  | # Android studio 3.1+ serialized cache file | ||||||
|  | .idea/caches/build_file_checksums.ser | ||||||
|  | 
 | ||||||
|  | ### Intellij+all Patch ### | ||||||
|  | # Ignores the whole .idea folder and all .iml files | ||||||
|  | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 | ||||||
|  | 
 | ||||||
|  | .idea/ | ||||||
|  | 
 | ||||||
|  | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 | ||||||
|  | 
 | ||||||
|  | *.iml | ||||||
|  | modules.xml | ||||||
|  | .idea/misc.xml | ||||||
|  | *.ipr | ||||||
|  | 
 | ||||||
|  | # Sonarlint plugin | ||||||
|  | .idea/sonarlint | ||||||
|  | 
 | ||||||
|  | ### Kotlin ### | ||||||
|  | # Compiled class file | ||||||
|  | *.class | ||||||
|  | 
 | ||||||
|  | # Log file | ||||||
|  | *.log | ||||||
|  | 
 | ||||||
|  | # BlueJ files | ||||||
|  | *.ctxt | ||||||
|  | 
 | ||||||
|  | # Mobile Tools for Java (J2ME) | ||||||
|  | .mtj.tmp/ | ||||||
|  | 
 | ||||||
|  | # Package Files # | ||||||
|  | *.jar | ||||||
|  | *.war | ||||||
|  | *.nar | ||||||
|  | *.ear | ||||||
|  | *.zip | ||||||
|  | *.tar.gz | ||||||
|  | *.rar | ||||||
|  | 
 | ||||||
|  | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||||||
|  | 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 ### | ||||||
|  | # General | ||||||
|  | .DS_Store | ||||||
|  | .AppleDouble | ||||||
|  | .LSOverride | ||||||
|  | 
 | ||||||
|  | # Icon must end with two \r | ||||||
|  | Icon | ||||||
|  | 
 | ||||||
|  | # Thumbnails | ||||||
|  | ._* | ||||||
|  | 
 | ||||||
|  | # Files that might appear in the root of a volume | ||||||
|  | .DocumentRevisions-V100 | ||||||
|  | .fseventsd | ||||||
|  | .Spotlight-V100 | ||||||
|  | .TemporaryItems | ||||||
|  | .Trashes | ||||||
|  | .VolumeIcon.icns | ||||||
|  | .com.apple.timemachine.donotpresent | ||||||
|  | 
 | ||||||
|  | # Directories potentially created on remote AFP share | ||||||
|  | .AppleDB | ||||||
|  | .AppleDesktop | ||||||
|  | Network Trash Folder | ||||||
|  | Temporary Items | ||||||
|  | .apdisk | ||||||
|  | 
 | ||||||
|  | ### Swift ### | ||||||
|  | # Xcode | ||||||
|  | # | ||||||
|  | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore | ||||||
|  | 
 | ||||||
|  | ## User settings | ||||||
|  | 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/ | ||||||
|  | *.moved-aside | ||||||
|  | *.pbxuser | ||||||
|  | !default.pbxuser | ||||||
|  | *.mode1v3 | ||||||
|  | !default.mode1v3 | ||||||
|  | *.mode2v3 | ||||||
|  | !default.mode2v3 | ||||||
|  | *.perspectivev3 | ||||||
|  | !default.perspectivev3 | ||||||
|  | 
 | ||||||
|  | ## Obj-C/Swift specific | ||||||
|  | *.hmap | ||||||
|  | 
 | ||||||
|  | ## App packaging | ||||||
|  | *.ipa | ||||||
|  | *.dSYM.zip | ||||||
|  | *.dSYM | ||||||
|  | 
 | ||||||
|  | ## Playgrounds | ||||||
|  | timeline.xctimeline | ||||||
|  | playground.xcworkspace | ||||||
|  | 
 | ||||||
|  | # Swift Package Manager | ||||||
|  | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. | ||||||
|  | # Packages/ | ||||||
|  | # Package.pins | ||||||
|  | # 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/ | ||||||
|  | 
 | ||||||
|  | # CocoaPods | ||||||
|  | # We recommend against adding the Pods directory to your .gitignore. However | ||||||
|  | # you should judge for yourself, the pros and cons are mentioned at: | ||||||
|  | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control | ||||||
|  | # Pods/ | ||||||
|  | # Add this line if you want to avoid checking in source code from the Xcode workspace | ||||||
|  | # *.xcworkspace | ||||||
|  | 
 | ||||||
|  | # Carthage | ||||||
|  | # Add this line if you want to avoid checking in source code from Carthage dependencies. | ||||||
|  | # Carthage/Checkouts | ||||||
|  | 
 | ||||||
|  | Carthage/Build/ | ||||||
|  | 
 | ||||||
|  | # Accio dependency management | ||||||
|  | Dependencies/ | ||||||
|  | .accio/ | ||||||
|  | 
 | ||||||
|  | # fastlane | ||||||
|  | # It is recommended to not store the screenshots in the git repo. | ||||||
|  | # Instead, use fastlane to re-generate the screenshots whenever they are needed. | ||||||
|  | # For more information about the recommended setup visit: | ||||||
|  | # https://docs.fastlane.tools/best-practices/source-control/#source-control | ||||||
|  | 
 | ||||||
|  | fastlane/report.xml | ||||||
|  | fastlane/Preview.html | ||||||
|  | fastlane/screenshots/**/*.png | ||||||
|  | fastlane/test_output | ||||||
|  | 
 | ||||||
|  | # Code Injection | ||||||
|  | # After new code Injection tools there's a generated folder /iOSInjectionProject | ||||||
|  | # https://github.com/johnno1962/injectionforxcode | ||||||
|  | 
 | ||||||
|  | iOSInjectionProject/ | ||||||
|  | 
 | ||||||
|  | ### VisualStudioCode ### | ||||||
|  | .vscode/* | ||||||
|  | !.vscode/settings.json | ||||||
|  | !.vscode/tasks.json | ||||||
|  | !.vscode/launch.json | ||||||
|  | !.vscode/extensions.json | ||||||
|  | *.code-workspace | ||||||
|  | 
 | ||||||
|  | # Local History for Visual Studio Code | ||||||
|  | .history/ | ||||||
|  | 
 | ||||||
|  | ### VisualStudioCode Patch ### | ||||||
|  | # Ignore all local history of files | ||||||
|  | .history | ||||||
|  | .ionide | ||||||
|  | 
 | ||||||
|  | # Support for Project snippet scope | ||||||
|  | !.vscode/*.code-snippets | ||||||
|  | 
 | ||||||
|  | ### Windows ### | ||||||
|  | # Windows thumbnail cache files | ||||||
|  | Thumbs.db | ||||||
|  | Thumbs.db:encryptable | ||||||
|  | ehthumbs.db | ||||||
|  | ehthumbs_vista.db | ||||||
|  | 
 | ||||||
|  | # Dump file | ||||||
|  | *.stackdump | ||||||
|  | 
 | ||||||
|  | # Folder config file | ||||||
|  | [Dd]esktop.ini | ||||||
|  | 
 | ||||||
|  | # Recycle Bin used on file shares | ||||||
|  | $RECYCLE.BIN/ | ||||||
|  | 
 | ||||||
|  | # Windows Installer files | ||||||
|  | *.cab | ||||||
|  | *.msi | ||||||
|  | *.msix | ||||||
|  | *.msm | ||||||
|  | *.msp | ||||||
|  | 
 | ||||||
|  | # Windows shortcuts | ||||||
|  | *.lnk | ||||||
|  | 
 | ||||||
|  | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,dart,flutter,intellij+all,kotlin,linux,swift,windows | ||||||
|  | 
 | ||||||
|  | # 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: f139b11009aeb8ed2a3a3aa8b0066e482709dde3 |   revision: cf4400006550b70f28e4b4af815151d1e74846c6 | ||||||
|   channel: stable |   channel: stable | ||||||
| 
 | 
 | ||||||
| project_type: plugin | project_type: plugin | ||||||
							
								
								
									
										3
									
								
								native_crypto/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,3 @@ | |||||||
|  | ## 0.0.1 | ||||||
|  | 
 | ||||||
|  | * TODO: Describe initial release. | ||||||
							
								
								
									
										1
									
								
								native_crypto/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | TODO: Add your license here. | ||||||
							
								
								
									
										18
									
								
								native_crypto/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,18 @@ | |||||||
|  | # native_crypto | ||||||
|  | 
 | ||||||
|  | A new flutter plugin project. | ||||||
|  | 
 | ||||||
|  | ## Getting Started | ||||||
|  | 
 | ||||||
|  | This project is a starting point for a Flutter | ||||||
|  | [plug-in package](https://flutter.dev/developing-packages/), | ||||||
|  | a specialized package that includes platform-specific implementation code for | ||||||
|  | Android and/or iOS. | ||||||
|  | 
 | ||||||
|  | For help getting started with Flutter, view our | ||||||
|  | [online documentation](https://flutter.dev/docs), which offers tutorials, | ||||||
|  | samples, guidance on mobile development, and a full API reference. | ||||||
|  | 
 | ||||||
|  | The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported. | ||||||
|  | To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same | ||||||
|  | directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms. | ||||||
							
								
								
									
										4
									
								
								native_crypto/analysis_options.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,4 @@ | |||||||
|  | include: package:flutter_lints/flutter.yaml | ||||||
|  | 
 | ||||||
|  | # Additional information about this file can be found at | ||||||
|  | # https://dart.dev/guides/language/analysis-options | ||||||
| @ -22,6 +22,7 @@ | |||||||
| 
 | 
 | ||||||
| # 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 | ||||||
| @ -33,5 +34,13 @@ | |||||||
| # Web related | # Web related | ||||||
| lib/generated_plugin_registrant.dart | lib/generated_plugin_registrant.dart | ||||||
| 
 | 
 | ||||||
| # Exceptions to above rules. | # Symbolication related | ||||||
| !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages | app.*.symbols | ||||||
|  | 
 | ||||||
|  | # 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: f139b11009aeb8ed2a3a3aa8b0066e482709dde3 |   revision: cf4400006550b70f28e4b4af815151d1e74846c6 | ||||||
|   channel: stable |   channel: stable | ||||||
| 
 | 
 | ||||||
| project_type: app | project_type: app | ||||||
							
								
								
									
										29
									
								
								native_crypto/example/analysis_options.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,29 @@ | |||||||
|  | # This file configures the analyzer, which statically analyzes Dart code to | ||||||
|  | # check for errors, warnings, and lints. | ||||||
|  | # | ||||||
|  | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled | ||||||
|  | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be | ||||||
|  | # invoked from the command line by running `flutter analyze`. | ||||||
|  | 
 | ||||||
|  | # The following line activates a set of recommended lints for Flutter apps, | ||||||
|  | # packages, and plugins designed to encourage good coding practices. | ||||||
|  | include: package:flutter_lints/flutter.yaml | ||||||
|  | 
 | ||||||
|  | linter: | ||||||
|  |   # The lint rules applied to this project can be customized in the | ||||||
|  |   # section below to disable rules from the `package:flutter_lints/flutter.yaml` | ||||||
|  |   # included above or to enable additional rules. A list of all available lints | ||||||
|  |   # and their documentation is published at | ||||||
|  |   # https://dart-lang.github.io/linter/lints/index.html. | ||||||
|  |   # | ||||||
|  |   # Instead of disabling a lint rule for the entire project in the | ||||||
|  |   # section below, it can also be suppressed for a single line of code | ||||||
|  |   # or a specific dart file by using the `// ignore: name_of_lint` and | ||||||
|  |   # `// ignore_for_file: name_of_lint` syntax on the line or in the file | ||||||
|  |   # producing the lint. | ||||||
|  |   rules: | ||||||
|  |     # avoid_print: false  # Uncomment to disable the `avoid_print` rule | ||||||
|  |     # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule | ||||||
|  | 
 | ||||||
|  | # Additional information about this file can be found at | ||||||
|  | # https://dart.dev/guides/language/analysis-options | ||||||
							
								
								
									
										13
									
								
								native_crypto/example/android/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,13 @@ | |||||||
|  | gradle-wrapper.jar | ||||||
|  | /.gradle | ||||||
|  | /captures/ | ||||||
|  | /gradlew | ||||||
|  | /gradlew.bat | ||||||
|  | /local.properties | ||||||
|  | GeneratedPluginRegistrant.java | ||||||
|  | 
 | ||||||
|  | # Remember to never publicly share your keystore. | ||||||
|  | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app | ||||||
|  | key.properties | ||||||
|  | **/*.keystore | ||||||
|  | **/*.jks | ||||||
| @ -26,24 +26,28 @@ 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 28 |     compileSdkVersion flutter.compileSdkVersion | ||||||
|  | 
 | ||||||
|  |     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 16 |         minSdkVersion flutter.minSdkVersion | ||||||
|         targetSdkVersion 28 |         targetSdkVersion flutter.targetSdkVersion | ||||||
|         versionCode flutterVersionCode.toInteger() |         versionCode flutterVersionCode.toInteger() | ||||||
|         versionName flutterVersionName |         versionName flutterVersionName | ||||||
|         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     buildTypes { |     buildTypes { | ||||||
| @ -61,7 +65,4 @@ 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,21 +1,25 @@ | |||||||
| <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"> | ||||||
|     <!-- io.flutter.app.FlutterApplication is an android.app.Application that |    <application | ||||||
|          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,6 @@ | |||||||
|  | package fr.pointcheval.native_crypto_example | ||||||
|  | 
 | ||||||
|  | import io.flutter.embedding.android.FlutterActivity | ||||||
|  | 
 | ||||||
|  | class MainActivity: FlutterActivity() { | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- Modify this file to customize your launch splash screen --> | ||||||
|  | <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <item android:drawable="?android:colorBackground" /> | ||||||
|  | 
 | ||||||
|  |     <!-- You can insert your own image assets here --> | ||||||
|  |     <!-- <item> | ||||||
|  |         <bitmap | ||||||
|  |             android:gravity="center" | ||||||
|  |             android:src="@mipmap/launch_image" /> | ||||||
|  |     </item> --> | ||||||
|  | </layer-list> | ||||||
| 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 | 
| @ -0,0 +1,18 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> | ||||||
|  |     <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> | ||||||
|  |     <!-- Theme applied to the Android Window as soon as the process has started. | ||||||
|  |          This theme determines the color of the Android Window while your | ||||||
|  |          Flutter UI initializes, as well as behind your Flutter UI while its | ||||||
|  |          running. | ||||||
|  | 
 | ||||||
|  |          This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||||||
|  |     <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||||||
|  |         <item name="android:windowBackground">?android:colorBackground</item> | ||||||
|  |     </style> | ||||||
|  | </resources> | ||||||
| @ -0,0 +1,18 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> | ||||||
|  |     <style name="LaunchTheme" parent="@android:style/Theme.Light.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> | ||||||
|  |     <!-- Theme applied to the Android Window as soon as the process has started. | ||||||
|  |          This theme determines the color of the Android Window while your | ||||||
|  |          Flutter UI initializes, as well as behind your Flutter UI while its | ||||||
|  |          running. | ||||||
|  | 
 | ||||||
|  |          This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||||||
|  |     <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||||||
|  |         <item name="android:windowBackground">?android:colorBackground</item> | ||||||
|  |     </style> | ||||||
|  | </resources> | ||||||
| @ -2,11 +2,11 @@ buildscript { | |||||||
|     ext.kotlin_version = '1.3.50' |     ext.kotlin_version = '1.3.50' | ||||||
|     repositories { |     repositories { | ||||||
|         google() |         google() | ||||||
|         jcenter() |         mavenCentral() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dependencies { |     dependencies { | ||||||
|         classpath 'com.android.tools.build:gradle:4.1.1' |         classpath 'com.android.tools.build:gradle:4.1.0' | ||||||
|         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() | ||||||
|         jcenter() |         mavenCentral() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1,4 +1,3 @@ | |||||||
| org.gradle.jvmargs=-Xmx1536M | org.gradle.jvmargs=-Xmx1536M | ||||||
| android.enableR8=true |  | ||||||
| android.useAndroidX=true | android.useAndroidX=true | ||||||
| android.enableJetifier=true | android.enableJetifier=true | ||||||
| @ -1,5 +1,6 @@ | |||||||
|  | #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-5.6.2-all.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip | ||||||
							
								
								
									
										11
									
								
								native_crypto/example/android/settings.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,11 @@ | |||||||
|  | include ':app' | ||||||
|  | 
 | ||||||
|  | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") | ||||||
|  | def properties = new Properties() | ||||||
|  | 
 | ||||||
|  | assert localPropertiesFile.exists() | ||||||
|  | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } | ||||||
|  | 
 | ||||||
|  | def flutterSdkPath = properties.getProperty("flutter.sdk") | ||||||
|  | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" | ||||||
|  | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" | ||||||
| @ -1,3 +1,4 @@ | |||||||
|  | **/dgph | ||||||
| *.mode1v3 | *.mode1v3 | ||||||
| *.mode2v3 | *.mode2v3 | ||||||
| *.moved-aside | *.moved-aside | ||||||
| @ -18,6 +19,7 @@ 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/ | ||||||
| @ -3,7 +3,7 @@ | |||||||
| <plist version="1.0"> | <plist version="1.0"> | ||||||
| <dict> | <dict> | ||||||
|   <key>CFBundleDevelopmentRegion</key> |   <key>CFBundleDevelopmentRegion</key> | ||||||
|   <string>$(DEVELOPMENT_LANGUAGE)</string> |   <string>en</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>8.0</string> |   <string>9.0</string> | ||||||
| </dict> | </dict> | ||||||
| </plist> | </plist> | ||||||
| @ -1,3 +1,2 @@ | |||||||
| #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" | ||||||
| #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" |  | ||||||
| #include "Generated.xcconfig" | #include "Generated.xcconfig" | ||||||
| @ -1,3 +1,2 @@ | |||||||
| #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" | ||||||
| #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" |  | ||||||
| #include "Generated.xcconfig" | #include "Generated.xcconfig" | ||||||
							
								
								
									
										41
									
								
								native_crypto/example/ios/Podfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,41 @@ | |||||||
|  | # 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 flutter_root | ||||||
|  |   generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) | ||||||
|  |   unless File.exist?(generated_xcode_build_settings_path) | ||||||
|  |     raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   File.foreach(generated_xcode_build_settings_path) do |line| | ||||||
|  |     matches = line.match(/FLUTTER_ROOT\=(.*)/) | ||||||
|  |     return matches[1].strip if matches | ||||||
|  |   end | ||||||
|  |   raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) | ||||||
|  | 
 | ||||||
|  | flutter_ios_podfile_setup | ||||||
|  | 
 | ||||||
|  | target 'Runner' do | ||||||
|  |   use_frameworks! | ||||||
|  |   use_modular_headers! | ||||||
|  | 
 | ||||||
|  |   flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | post_install do |installer| | ||||||
|  |   installer.pods_project.targets.each do |target| | ||||||
|  |     flutter_additional_ios_build_settings(target) | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										484
									
								
								native_crypto/example/ios/Runner.xcodeproj/project.pbxproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,484 @@ | |||||||
|  | // !$*UTF8*$! | ||||||
|  | { | ||||||
|  | 	archiveVersion = 1; | ||||||
|  | 	classes = { | ||||||
|  | 	}; | ||||||
|  | 	objectVersion = 50; | ||||||
|  | 	objects = { | ||||||
|  | 
 | ||||||
|  | /* Begin PBXBuildFile section */ | ||||||
|  | 		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; | ||||||
|  | 		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; | ||||||
|  | 		74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; | ||||||
|  | 		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; | ||||||
|  | 		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; | ||||||
|  | 		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; | ||||||
|  | /* End PBXBuildFile section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXCopyFilesBuildPhase section */ | ||||||
|  | 		9705A1C41CF9048500538489 /* Embed Frameworks */ = { | ||||||
|  | 			isa = PBXCopyFilesBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			dstPath = ""; | ||||||
|  | 			dstSubfolderSpec = 10; | ||||||
|  | 			files = ( | ||||||
|  | 			); | ||||||
|  | 			name = "Embed Frameworks"; | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXCopyFilesBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXFileReference section */ | ||||||
|  | 		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>"; }; | ||||||
|  | 		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>"; }; | ||||||
|  | 		74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; | ||||||
|  | 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; | ||||||
|  | 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; | ||||||
|  | 		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; | ||||||
|  | 		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||||
|  | 		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<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>"; }; | ||||||
|  | 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | ||||||
|  | /* End PBXFileReference section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXFrameworksBuildPhase section */ | ||||||
|  | 		97C146EB1CF9000F007C117D /* Frameworks */ = { | ||||||
|  | 			isa = PBXFrameworksBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXFrameworksBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXGroup section */ | ||||||
|  | 		9740EEB11CF90186004384FC /* Flutter */ = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, | ||||||
|  | 				9740EEB21CF90195004384FC /* Debug.xcconfig */, | ||||||
|  | 				7AFA3C8E1D35360C0083082E /* Release.xcconfig */, | ||||||
|  | 				9740EEB31CF90195004384FC /* Generated.xcconfig */, | ||||||
|  | 			); | ||||||
|  | 			name = Flutter; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146E51CF9000F007C117D = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				9740EEB11CF90186004384FC /* Flutter */, | ||||||
|  | 				97C146F01CF9000F007C117D /* Runner */, | ||||||
|  | 				97C146EF1CF9000F007C117D /* Products */, | ||||||
|  | 			); | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146EF1CF9000F007C117D /* Products */ = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C146EE1CF9000F007C117D /* Runner.app */, | ||||||
|  | 			); | ||||||
|  | 			name = Products; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146F01CF9000F007C117D /* Runner */ = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C146FA1CF9000F007C117D /* Main.storyboard */, | ||||||
|  | 				97C146FD1CF9000F007C117D /* Assets.xcassets */, | ||||||
|  | 				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, | ||||||
|  | 				97C147021CF9000F007C117D /* Info.plist */, | ||||||
|  | 				1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, | ||||||
|  | 				1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, | ||||||
|  | 				74858FAE1ED2DC5600515810 /* AppDelegate.swift */, | ||||||
|  | 				74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, | ||||||
|  | 			); | ||||||
|  | 			path = Runner; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | /* End PBXGroup section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXNativeTarget section */ | ||||||
|  | 		97C146ED1CF9000F007C117D /* Runner */ = { | ||||||
|  | 			isa = PBXNativeTarget; | ||||||
|  | 			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; | ||||||
|  | 			buildPhases = ( | ||||||
|  | 				9740EEB61CF901F6004384FC /* Run Script */, | ||||||
|  | 				97C146EA1CF9000F007C117D /* Sources */, | ||||||
|  | 				97C146EB1CF9000F007C117D /* Frameworks */, | ||||||
|  | 				97C146EC1CF9000F007C117D /* Resources */, | ||||||
|  | 				9705A1C41CF9048500538489 /* Embed Frameworks */, | ||||||
|  | 				3B06AD1E1E4923F5004D2608 /* Thin Binary */, | ||||||
|  | 			); | ||||||
|  | 			buildRules = ( | ||||||
|  | 			); | ||||||
|  | 			dependencies = ( | ||||||
|  | 			); | ||||||
|  | 			name = Runner; | ||||||
|  | 			productName = Runner; | ||||||
|  | 			productReference = 97C146EE1CF9000F007C117D /* Runner.app */; | ||||||
|  | 			productType = "com.apple.product-type.application"; | ||||||
|  | 		}; | ||||||
|  | /* End PBXNativeTarget section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXProject section */ | ||||||
|  | 		97C146E61CF9000F007C117D /* Project object */ = { | ||||||
|  | 			isa = PBXProject; | ||||||
|  | 			attributes = { | ||||||
|  | 				LastUpgradeCheck = 1300; | ||||||
|  | 				ORGANIZATIONNAME = ""; | ||||||
|  | 				TargetAttributes = { | ||||||
|  | 					97C146ED1CF9000F007C117D = { | ||||||
|  | 						CreatedOnToolsVersion = 7.3.1; | ||||||
|  | 						LastSwiftMigration = 1100; | ||||||
|  | 					}; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; | ||||||
|  | 			compatibilityVersion = "Xcode 9.3"; | ||||||
|  | 			developmentRegion = en; | ||||||
|  | 			hasScannedForEncodings = 0; | ||||||
|  | 			knownRegions = ( | ||||||
|  | 				en, | ||||||
|  | 				Base, | ||||||
|  | 			); | ||||||
|  | 			mainGroup = 97C146E51CF9000F007C117D; | ||||||
|  | 			productRefGroup = 97C146EF1CF9000F007C117D /* Products */; | ||||||
|  | 			projectDirPath = ""; | ||||||
|  | 			projectRoot = ""; | ||||||
|  | 			targets = ( | ||||||
|  | 				97C146ED1CF9000F007C117D /* Runner */, | ||||||
|  | 			); | ||||||
|  | 		}; | ||||||
|  | /* End PBXProject section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXResourcesBuildPhase section */ | ||||||
|  | 		97C146EC1CF9000F007C117D /* Resources */ = { | ||||||
|  | 			isa = PBXResourcesBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, | ||||||
|  | 				3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, | ||||||
|  | 				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, | ||||||
|  | 				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXResourcesBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXShellScriptBuildPhase section */ | ||||||
|  | 		3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { | ||||||
|  | 			isa = PBXShellScriptBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 			); | ||||||
|  | 			inputPaths = ( | ||||||
|  | 			); | ||||||
|  | 			name = "Thin Binary"; | ||||||
|  | 			outputPaths = ( | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 			shellPath = /bin/sh; | ||||||
|  | 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; | ||||||
|  | 		}; | ||||||
|  | 		9740EEB61CF901F6004384FC /* Run Script */ = { | ||||||
|  | 			isa = PBXShellScriptBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 			); | ||||||
|  | 			inputPaths = ( | ||||||
|  | 			); | ||||||
|  | 			name = "Run Script"; | ||||||
|  | 			outputPaths = ( | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 			shellPath = /bin/sh; | ||||||
|  | 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; | ||||||
|  | 		}; | ||||||
|  | /* End PBXShellScriptBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXSourcesBuildPhase section */ | ||||||
|  | 		97C146EA1CF9000F007C117D /* Sources */ = { | ||||||
|  | 			isa = PBXSourcesBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 				74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, | ||||||
|  | 				1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXSourcesBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXVariantGroup section */ | ||||||
|  | 		97C146FA1CF9000F007C117D /* Main.storyboard */ = { | ||||||
|  | 			isa = PBXVariantGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C146FB1CF9000F007C117D /* Base */, | ||||||
|  | 			); | ||||||
|  | 			name = Main.storyboard; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { | ||||||
|  | 			isa = PBXVariantGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C147001CF9000F007C117D /* Base */, | ||||||
|  | 			); | ||||||
|  | 			name = LaunchScreen.storyboard; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | /* End PBXVariantGroup section */ | ||||||
|  | 
 | ||||||
|  | /* Begin XCBuildConfiguration section */ | ||||||
|  | 		249021D3217E4FDB00AE95B9 /* Profile */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ALWAYS_SEARCH_USER_PATHS = NO; | ||||||
|  | 				CLANG_ANALYZER_NONNULL = YES; | ||||||
|  | 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | ||||||
|  | 				CLANG_CXX_LIBRARY = "libc++"; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CLANG_ENABLE_OBJC_ARC = YES; | ||||||
|  | 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||||||
|  | 				CLANG_WARN_BOOL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_COMMA = YES; | ||||||
|  | 				CLANG_WARN_CONSTANT_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||||||
|  | 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||||||
|  | 				CLANG_WARN_EMPTY_BODY = YES; | ||||||
|  | 				CLANG_WARN_ENUM_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_INFINITE_RECURSION = YES; | ||||||
|  | 				CLANG_WARN_INT_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||||
|  | 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||||
|  | 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||||
|  | 				CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||||
|  | 				CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||||
|  | 				CLANG_WARN_UNREACHABLE_CODE = YES; | ||||||
|  | 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||||||
|  | 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||||||
|  | 				COPY_PHASE_STRIP = NO; | ||||||
|  | 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | ||||||
|  | 				ENABLE_NS_ASSERTIONS = NO; | ||||||
|  | 				ENABLE_STRICT_OBJC_MSGSEND = YES; | ||||||
|  | 				GCC_C_LANGUAGE_STANDARD = gnu99; | ||||||
|  | 				GCC_NO_COMMON_BLOCKS = YES; | ||||||
|  | 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||||||
|  | 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||||||
|  | 				GCC_WARN_UNDECLARED_SELECTOR = YES; | ||||||
|  | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||||
|  | 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||||
|  | 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||||
|  | 				IPHONEOS_DEPLOYMENT_TARGET = 9.0; | ||||||
|  | 				MTL_ENABLE_DEBUG_INFO = NO; | ||||||
|  | 				SDKROOT = iphoneos; | ||||||
|  | 				SUPPORTED_PLATFORMS = iphoneos; | ||||||
|  | 				TARGETED_DEVICE_FAMILY = "1,2"; | ||||||
|  | 				VALIDATE_PRODUCT = YES; | ||||||
|  | 			}; | ||||||
|  | 			name = Profile; | ||||||
|  | 		}; | ||||||
|  | 		249021D4217E4FDB00AE95B9 /* Profile */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||||||
|  | 				DEVELOPMENT_TEAM = 6Z5P8GG96U; | ||||||
|  | 				ENABLE_BITCODE = NO; | ||||||
|  | 				INFOPLIST_FILE = Runner/Info.plist; | ||||||
|  | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
|  | 					"$(inherited)", | ||||||
|  | 					"@executable_path/Frameworks", | ||||||
|  | 				); | ||||||
|  | 				PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoExample; | ||||||
|  | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||||||
|  | 				SWIFT_VERSION = 5.0; | ||||||
|  | 				VERSIONING_SYSTEM = "apple-generic"; | ||||||
|  | 			}; | ||||||
|  | 			name = Profile; | ||||||
|  | 		}; | ||||||
|  | 		97C147031CF9000F007C117D /* Debug */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ALWAYS_SEARCH_USER_PATHS = NO; | ||||||
|  | 				CLANG_ANALYZER_NONNULL = YES; | ||||||
|  | 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | ||||||
|  | 				CLANG_CXX_LIBRARY = "libc++"; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CLANG_ENABLE_OBJC_ARC = YES; | ||||||
|  | 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||||||
|  | 				CLANG_WARN_BOOL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_COMMA = YES; | ||||||
|  | 				CLANG_WARN_CONSTANT_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||||||
|  | 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||||||
|  | 				CLANG_WARN_EMPTY_BODY = YES; | ||||||
|  | 				CLANG_WARN_ENUM_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_INFINITE_RECURSION = YES; | ||||||
|  | 				CLANG_WARN_INT_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||||
|  | 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||||
|  | 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||||
|  | 				CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||||
|  | 				CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||||
|  | 				CLANG_WARN_UNREACHABLE_CODE = YES; | ||||||
|  | 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||||||
|  | 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||||||
|  | 				COPY_PHASE_STRIP = NO; | ||||||
|  | 				DEBUG_INFORMATION_FORMAT = dwarf; | ||||||
|  | 				ENABLE_STRICT_OBJC_MSGSEND = YES; | ||||||
|  | 				ENABLE_TESTABILITY = YES; | ||||||
|  | 				GCC_C_LANGUAGE_STANDARD = gnu99; | ||||||
|  | 				GCC_DYNAMIC_NO_PIC = NO; | ||||||
|  | 				GCC_NO_COMMON_BLOCKS = YES; | ||||||
|  | 				GCC_OPTIMIZATION_LEVEL = 0; | ||||||
|  | 				GCC_PREPROCESSOR_DEFINITIONS = ( | ||||||
|  | 					"DEBUG=1", | ||||||
|  | 					"$(inherited)", | ||||||
|  | 				); | ||||||
|  | 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||||||
|  | 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||||||
|  | 				GCC_WARN_UNDECLARED_SELECTOR = YES; | ||||||
|  | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||||
|  | 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||||
|  | 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||||
|  | 				IPHONEOS_DEPLOYMENT_TARGET = 9.0; | ||||||
|  | 				MTL_ENABLE_DEBUG_INFO = YES; | ||||||
|  | 				ONLY_ACTIVE_ARCH = YES; | ||||||
|  | 				SDKROOT = iphoneos; | ||||||
|  | 				TARGETED_DEVICE_FAMILY = "1,2"; | ||||||
|  | 			}; | ||||||
|  | 			name = Debug; | ||||||
|  | 		}; | ||||||
|  | 		97C147041CF9000F007C117D /* Release */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ALWAYS_SEARCH_USER_PATHS = NO; | ||||||
|  | 				CLANG_ANALYZER_NONNULL = YES; | ||||||
|  | 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | ||||||
|  | 				CLANG_CXX_LIBRARY = "libc++"; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CLANG_ENABLE_OBJC_ARC = YES; | ||||||
|  | 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||||||
|  | 				CLANG_WARN_BOOL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_COMMA = YES; | ||||||
|  | 				CLANG_WARN_CONSTANT_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||||||
|  | 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||||||
|  | 				CLANG_WARN_EMPTY_BODY = YES; | ||||||
|  | 				CLANG_WARN_ENUM_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_INFINITE_RECURSION = YES; | ||||||
|  | 				CLANG_WARN_INT_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||||
|  | 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||||
|  | 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||||
|  | 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||||
|  | 				CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||||
|  | 				CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||||
|  | 				CLANG_WARN_UNREACHABLE_CODE = YES; | ||||||
|  | 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||||||
|  | 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||||||
|  | 				COPY_PHASE_STRIP = NO; | ||||||
|  | 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | ||||||
|  | 				ENABLE_NS_ASSERTIONS = NO; | ||||||
|  | 				ENABLE_STRICT_OBJC_MSGSEND = YES; | ||||||
|  | 				GCC_C_LANGUAGE_STANDARD = gnu99; | ||||||
|  | 				GCC_NO_COMMON_BLOCKS = YES; | ||||||
|  | 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||||||
|  | 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||||||
|  | 				GCC_WARN_UNDECLARED_SELECTOR = YES; | ||||||
|  | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||||
|  | 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||||
|  | 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||||
|  | 				IPHONEOS_DEPLOYMENT_TARGET = 9.0; | ||||||
|  | 				MTL_ENABLE_DEBUG_INFO = NO; | ||||||
|  | 				SDKROOT = iphoneos; | ||||||
|  | 				SUPPORTED_PLATFORMS = iphoneos; | ||||||
|  | 				SWIFT_COMPILATION_MODE = wholemodule; | ||||||
|  | 				SWIFT_OPTIMIZATION_LEVEL = "-O"; | ||||||
|  | 				TARGETED_DEVICE_FAMILY = "1,2"; | ||||||
|  | 				VALIDATE_PRODUCT = YES; | ||||||
|  | 			}; | ||||||
|  | 			name = Release; | ||||||
|  | 		}; | ||||||
|  | 		97C147061CF9000F007C117D /* Debug */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||||||
|  | 				DEVELOPMENT_TEAM = 6Z5P8GG96U; | ||||||
|  | 				ENABLE_BITCODE = NO; | ||||||
|  | 				INFOPLIST_FILE = Runner/Info.plist; | ||||||
|  | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
|  | 					"$(inherited)", | ||||||
|  | 					"@executable_path/Frameworks", | ||||||
|  | 				); | ||||||
|  | 				PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoExample; | ||||||
|  | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||||||
|  | 				SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | ||||||
|  | 				SWIFT_VERSION = 5.0; | ||||||
|  | 				VERSIONING_SYSTEM = "apple-generic"; | ||||||
|  | 			}; | ||||||
|  | 			name = Debug; | ||||||
|  | 		}; | ||||||
|  | 		97C147071CF9000F007C117D /* Release */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||||||
|  | 				DEVELOPMENT_TEAM = 6Z5P8GG96U; | ||||||
|  | 				ENABLE_BITCODE = NO; | ||||||
|  | 				INFOPLIST_FILE = Runner/Info.plist; | ||||||
|  | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
|  | 					"$(inherited)", | ||||||
|  | 					"@executable_path/Frameworks", | ||||||
|  | 				); | ||||||
|  | 				PRODUCT_BUNDLE_IDENTIFIER = fr.pointcheval.nativeCryptoExample; | ||||||
|  | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||||||
|  | 				SWIFT_VERSION = 5.0; | ||||||
|  | 				VERSIONING_SYSTEM = "apple-generic"; | ||||||
|  | 			}; | ||||||
|  | 			name = Release; | ||||||
|  | 		}; | ||||||
|  | /* End XCBuildConfiguration section */ | ||||||
|  | 
 | ||||||
|  | /* Begin XCConfigurationList section */ | ||||||
|  | 		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { | ||||||
|  | 			isa = XCConfigurationList; | ||||||
|  | 			buildConfigurations = ( | ||||||
|  | 				97C147031CF9000F007C117D /* Debug */, | ||||||
|  | 				97C147041CF9000F007C117D /* Release */, | ||||||
|  | 				249021D3217E4FDB00AE95B9 /* Profile */, | ||||||
|  | 			); | ||||||
|  | 			defaultConfigurationIsVisible = 0; | ||||||
|  | 			defaultConfigurationName = Release; | ||||||
|  | 		}; | ||||||
|  | 		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { | ||||||
|  | 			isa = XCConfigurationList; | ||||||
|  | 			buildConfigurations = ( | ||||||
|  | 				97C147061CF9000F007C117D /* Debug */, | ||||||
|  | 				97C147071CF9000F007C117D /* Release */, | ||||||
|  | 				249021D4217E4FDB00AE95B9 /* Profile */, | ||||||
|  | 			); | ||||||
|  | 			defaultConfigurationIsVisible = 0; | ||||||
|  | 			defaultConfigurationName = Release; | ||||||
|  | 		}; | ||||||
|  | /* End XCConfigurationList section */ | ||||||
|  | 	}; | ||||||
|  | 	rootObject = 97C146E61CF9000F007C117D /* Project object */; | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								native_crypto/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,7 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <Workspace | ||||||
|  |    version = "1.0"> | ||||||
|  |    <FileRef | ||||||
|  |       location = "self:"> | ||||||
|  |    </FileRef> | ||||||
|  | </Workspace> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>PreviewsEnabled</key> | ||||||
|  | 	<false/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -1,6 +1,6 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <Scheme | <Scheme | ||||||
|    LastUpgradeVersion = "1020" |    LastUpgradeVersion = "1300" | ||||||
|    version = "1.3"> |    version = "1.3"> | ||||||
|    <BuildAction |    <BuildAction | ||||||
|       parallelizeBuildables = "YES" |       parallelizeBuildables = "YES" | ||||||
| @ -27,8 +27,6 @@ | |||||||
|       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" | ||||||
| @ -38,8 +36,8 @@ | |||||||
|             ReferencedContainer = "container:Runner.xcodeproj"> |             ReferencedContainer = "container:Runner.xcodeproj"> | ||||||
|          </BuildableReference> |          </BuildableReference> | ||||||
|       </MacroExpansion> |       </MacroExpansion> | ||||||
|       <AdditionalOptions> |       <Testables> | ||||||
|       </AdditionalOptions> |       </Testables> | ||||||
|    </TestAction> |    </TestAction> | ||||||
|    <LaunchAction |    <LaunchAction | ||||||
|       buildConfiguration = "Debug" |       buildConfiguration = "Debug" | ||||||
| @ -61,8 +59,6 @@ | |||||||
|             ReferencedContainer = "container:Runner.xcodeproj"> |             ReferencedContainer = "container:Runner.xcodeproj"> | ||||||
|          </BuildableReference> |          </BuildableReference> | ||||||
|       </BuildableProductRunnable> |       </BuildableProductRunnable> | ||||||
|       <AdditionalOptions> |  | ||||||
|       </AdditionalOptions> |  | ||||||
|    </LaunchAction> |    </LaunchAction> | ||||||
|    <ProfileAction |    <ProfileAction | ||||||
|       buildConfiguration = "Profile" |       buildConfiguration = "Profile" | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>PreviewsEnabled</key> | ||||||
|  | 	<false/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| 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 |