v2 #12
| @ -47,4 +47,5 @@ android { | |||||||
| 
 | 
 | ||||||
| dependencies { | dependencies { | ||||||
|     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" |     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | ||||||
|  |     implementation 'androidx.documentfile:documentfile:1.0.1' | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| // license that can be found in the LICENSE file or at | // license that can be found in the LICENSE file or at | ||||||
| // https://opensource.org/licenses/MIT. | // https://opensource.org/licenses/MIT. | ||||||
| // -- | // -- | ||||||
| // Autogenerated from Pigeon (v9.0.0), do not edit directly. | // Autogenerated from Pigeon (v9.2.0), do not edit directly. | ||||||
| // See also: https://pub.dev/packages/pigeon | // See also: https://pub.dev/packages/pigeon | ||||||
| 
 | 
 | ||||||
| package fr.pointcheval.native_crypto_android; | package fr.pointcheval.native_crypto_android; | ||||||
| @ -26,15 +26,40 @@ import java.util.List; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
| 
 | 
 | ||||||
| /** Generated class from Pigeon. */ | /** Generated class from Pigeon. */ | ||||||
| @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) | @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) | ||||||
| public class GeneratedAndroidNativeCrypto { | public class GeneratedAndroidNativeCrypto { | ||||||
|  | 
 | ||||||
|  |   /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ | ||||||
|  |   public static class FlutterError extends RuntimeException { | ||||||
|  | 
 | ||||||
|  |     /** The error code. */ | ||||||
|  |     public final String code; | ||||||
|  | 
 | ||||||
|  |     /** The error details. Must be a datatype supported by the api codec. */ | ||||||
|  |     public final Object details; | ||||||
|  | 
 | ||||||
|  |     public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details)  | ||||||
|  |     { | ||||||
|  |       super(message); | ||||||
|  |       this.code = code; | ||||||
|  |       this.details = details; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @NonNull |   @NonNull | ||||||
|   private static ArrayList<Object> wrapError(@NonNull Throwable exception) { |   private static ArrayList<Object> wrapError(@NonNull Throwable exception) { | ||||||
|     ArrayList<Object> errorList = new ArrayList<Object>(3); |     ArrayList<Object> errorList = new ArrayList<Object>(3); | ||||||
|     errorList.add(exception.toString()); |     if (exception instanceof FlutterError) { | ||||||
|     errorList.add(exception.getClass().getSimpleName()); |       FlutterError error = (FlutterError) exception; | ||||||
|     errorList.add( |       errorList.add(error.code); | ||||||
|       "Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception)); |       errorList.add(error.getMessage()); | ||||||
|  |       errorList.add(error.details); | ||||||
|  |     } else { | ||||||
|  |       errorList.add(exception.toString()); | ||||||
|  |       errorList.add(exception.getClass().getSimpleName()); | ||||||
|  |       errorList.add( | ||||||
|  |         "Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception)); | ||||||
|  |     } | ||||||
|     return errorList; |     return errorList; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -1339,16 +1364,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 HashRequest requestArg = (HashRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   HashRequest requestArg = (HashRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   HashResponse output = api.hash(requestArg); |                   HashResponse output = api.hash(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1366,16 +1388,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 HmacRequest requestArg = (HmacRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   HmacRequest requestArg = (HmacRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   HmacResponse output = api.hmac(requestArg); |                   HmacResponse output = api.hmac(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1393,16 +1412,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 GenerateSecureRandomRequest requestArg = (GenerateSecureRandomRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   GenerateSecureRandomRequest requestArg = (GenerateSecureRandomRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   GenerateSecureRandomResponse output = api.generateSecureRandom(requestArg); |                   GenerateSecureRandomResponse output = api.generateSecureRandom(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1420,16 +1436,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 Pbkdf2Request requestArg = (Pbkdf2Request) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   Pbkdf2Request requestArg = (Pbkdf2Request) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   Pbkdf2Response output = api.pbkdf2(requestArg); |                   Pbkdf2Response output = api.pbkdf2(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1447,16 +1460,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 EncryptRequest requestArg = (EncryptRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   EncryptRequest requestArg = (EncryptRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   EncryptResponse output = api.encrypt(requestArg); |                   EncryptResponse output = api.encrypt(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1474,16 +1484,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 DecryptRequest requestArg = (DecryptRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   DecryptRequest requestArg = (DecryptRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   DecryptResponse output = api.decrypt(requestArg); |                   DecryptResponse output = api.decrypt(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1501,16 +1508,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 EncryptFileRequest requestArg = (EncryptFileRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   EncryptFileRequest requestArg = (EncryptFileRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   EncryptFileResponse output = api.encryptFile(requestArg); |                   EncryptFileResponse output = api.encryptFile(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1528,16 +1532,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 DecryptFileRequest requestArg = (DecryptFileRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   DecryptFileRequest requestArg = (DecryptFileRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   DecryptFileResponse output = api.decryptFile(requestArg); |                   DecryptFileResponse output = api.decryptFile(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
| @ -1555,16 +1556,13 @@ public class GeneratedAndroidNativeCrypto { | |||||||
|           channel.setMessageHandler( |           channel.setMessageHandler( | ||||||
|               (message, reply) -> { |               (message, reply) -> { | ||||||
|                 ArrayList<Object> wrapped = new ArrayList<Object>(); |                 ArrayList<Object> wrapped = new ArrayList<Object>(); | ||||||
|  |                 ArrayList<Object> args = (ArrayList<Object>) message; | ||||||
|  |                 EncryptWithIVRequest requestArg = (EncryptWithIVRequest) args.get(0); | ||||||
|                 try { |                 try { | ||||||
|                   ArrayList<Object> args = (ArrayList<Object>) message; |  | ||||||
|                   assert args != null; |  | ||||||
|                   EncryptWithIVRequest requestArg = (EncryptWithIVRequest) args.get(0); |  | ||||||
|                   if (requestArg == null) { |  | ||||||
|                     throw new NullPointerException("requestArg unexpectedly null."); |  | ||||||
|                   } |  | ||||||
|                   EncryptResponse output = api.encryptWithIV(requestArg); |                   EncryptResponse output = api.encryptWithIV(requestArg); | ||||||
|                   wrapped.add(0, output); |                   wrapped.add(0, output); | ||||||
|                 } catch (Error | RuntimeException exception) { |                 } | ||||||
|  |  catch (Throwable exception) { | ||||||
|                   ArrayList<Object> wrappedError = wrapError(exception); |                   ArrayList<Object> wrappedError = wrapError(exception); | ||||||
|                   wrapped = wrappedError; |                   wrapped = wrappedError; | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -0,0 +1,118 @@ | |||||||
|  | package fr.pointcheval.native_crypto_android | ||||||
|  | 
 | ||||||
|  | import android.content.Context | ||||||
|  | import fr.pointcheval.native_crypto_android.ciphers.AES | ||||||
|  | import fr.pointcheval.native_crypto_android.kdf.Pbkdf2 | ||||||
|  | import fr.pointcheval.native_crypto_android.utils.FileParameters | ||||||
|  | import fr.pointcheval.native_crypto_android.utils.HashAlgorithmParser | ||||||
|  | import java.security.SecureRandom | ||||||
|  | 
 | ||||||
|  | class NativeCrypto(private val context: Context) : NativeCryptoAPI { | ||||||
|  |     override fun hash(data: ByteArray, algorithm: HashAlgorithm): ByteArray? { | ||||||
|  |         val md = HashAlgorithmParser.getMessageDigest(algorithm) | ||||||
|  | 
 | ||||||
|  |         return md.digest(data) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun hmac(data: ByteArray, key: ByteArray, algorithm: HashAlgorithm): ByteArray? { | ||||||
|  |         val mac = HashAlgorithmParser.getMac(algorithm) | ||||||
|  |         val secretKey = javax.crypto.spec.SecretKeySpec(key, mac.algorithm) | ||||||
|  |         mac.init(secretKey) | ||||||
|  | 
 | ||||||
|  |         return mac.doFinal(data) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun generateSecureRandom(length: Long): ByteArray { | ||||||
|  |         val bytes = ByteArray(length.toInt()) | ||||||
|  |         SecureRandom.getInstanceStrong().nextBytes(bytes) | ||||||
|  | 
 | ||||||
|  |         return bytes | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun pbkdf2( | ||||||
|  |         password: ByteArray, | ||||||
|  |         salt: ByteArray, | ||||||
|  |         length: Long, | ||||||
|  |         iterations: Long, | ||||||
|  |         algorithm: HashAlgorithm | ||||||
|  |     ): ByteArray? { | ||||||
|  |         val pbkdf2 = Pbkdf2(length.toInt(), iterations.toInt(), algorithm) | ||||||
|  |         pbkdf2.init(password, salt) | ||||||
|  | 
 | ||||||
|  |         return pbkdf2.derive() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun encrypt( | ||||||
|  |         plainText: ByteArray, | ||||||
|  |         key: ByteArray, | ||||||
|  |         algorithm: CipherAlgorithm | ||||||
|  |     ): ByteArray { | ||||||
|  |         // For now, only AES is supported | ||||||
|  |         val aes = AES() | ||||||
|  | 
 | ||||||
|  |         return aes.encrypt(plainText, key, null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun encryptWithIV( | ||||||
|  |         plainText: ByteArray, | ||||||
|  |         iv: ByteArray, | ||||||
|  |         key: ByteArray, | ||||||
|  |         algorithm: CipherAlgorithm | ||||||
|  |     ): ByteArray { | ||||||
|  |         // For now, only AES is supported | ||||||
|  |         val aes = AES() | ||||||
|  | 
 | ||||||
|  |         return aes.encrypt(plainText, key, iv) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun decrypt( | ||||||
|  |         cipherText: ByteArray, | ||||||
|  |         key: ByteArray, | ||||||
|  |         algorithm: CipherAlgorithm | ||||||
|  |     ): ByteArray { | ||||||
|  |         // For now, only AES is supported | ||||||
|  |         val aes = AES() | ||||||
|  | 
 | ||||||
|  |         return aes.decrypt(cipherText, key) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun encryptFile( | ||||||
|  |         plainTextPath: String, | ||||||
|  |         cipherTextPath: String, | ||||||
|  |         key: ByteArray, | ||||||
|  |         algorithm: CipherAlgorithm | ||||||
|  |     ): Boolean { | ||||||
|  |         // For now, only AES is supported | ||||||
|  |         val aes = AES() | ||||||
|  |         val params = FileParameters(context, plainTextPath, cipherTextPath) | ||||||
|  | 
 | ||||||
|  |         return aes.encryptFile(params, key, null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun encryptFileWithIV( | ||||||
|  |         plainTextPath: String, | ||||||
|  |         cipherTextPath: String, | ||||||
|  |         iv: ByteArray, | ||||||
|  |         key: ByteArray, | ||||||
|  |         algorithm: CipherAlgorithm | ||||||
|  |     ): Boolean { | ||||||
|  |         // For now, only AES is supported | ||||||
|  |         val aes = AES() | ||||||
|  |         val params = FileParameters(context, plainTextPath, cipherTextPath) | ||||||
|  | 
 | ||||||
|  |         return aes.encryptFile(params, key, iv) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun decryptFile( | ||||||
|  |         cipherTextPath: String, | ||||||
|  |         plainTextPath: String, | ||||||
|  |         key: ByteArray, | ||||||
|  |         algorithm: CipherAlgorithm | ||||||
|  |     ): Boolean { | ||||||
|  |         // For now, only AES is supported | ||||||
|  |         val aes = AES() | ||||||
|  |         val params = FileParameters(context, plainTextPath, cipherTextPath) | ||||||
|  | 
 | ||||||
|  |         return aes.decryptFile(params, key) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,160 +1,19 @@ | |||||||
| package fr.pointcheval.native_crypto_android | package fr.pointcheval.native_crypto_android | ||||||
| 
 | 
 | ||||||
| import androidx.annotation.NonNull |  | ||||||
| import fr.pointcheval.native_crypto_android.interfaces.Cipher |  | ||||||
| import fr.pointcheval.native_crypto_android.kdf.Pbkdf2 |  | ||||||
| import fr.pointcheval.native_crypto_android.keys.SecretKey |  | ||||||
| import fr.pointcheval.native_crypto_android.utils.CipherAlgorithm |  | ||||||
| import fr.pointcheval.native_crypto_android.utils.Constants |  | ||||||
| import fr.pointcheval.native_crypto_android.utils.HashAlgorithm |  | ||||||
| import fr.pointcheval.native_crypto_android.utils.Task |  | ||||||
| import io.flutter.embedding.engine.plugins.FlutterPlugin | 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 java.util.* |  | ||||||
| 
 | 
 | ||||||
| /** NativeCryptoAndroidPlugin */ | /** NativeCryptoAndroidPlugin */ | ||||||
| class NativeCryptoAndroidPlugin : FlutterPlugin, MethodCallHandler { | class NativeCryptoAndroidPlugin : FlutterPlugin { | ||||||
|     /// The MethodChannel that will the communication between Flutter and native Android |     private var nativeCrypto: NativeCrypto? = null | ||||||
|     /// |  | ||||||
|     /// This local reference serves to register the plugin with the Flutter Engine and unregister it |  | ||||||
|     /// when the Flutter Engine is detached from the Activity |  | ||||||
|     private lateinit var channel: MethodChannel |  | ||||||
|     private val name = "plugins.hugop.cl/native_crypto" |  | ||||||
| 
 | 
 | ||||||
|     private var cipherInstance: Cipher? = null |     override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||||||
| 
 |         val context = flutterPluginBinding.applicationContext | ||||||
|     override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { |         nativeCrypto = NativeCrypto(context) | ||||||
|         channel = MethodChannel(flutterPluginBinding.binaryMessenger, name) |         NativeCryptoAPI.setUp(flutterPluginBinding.binaryMessenger, nativeCrypto) | ||||||
|         channel.setMethodCallHandler(this) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { |     override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { | ||||||
|         channel.setMethodCallHandler(null) |         NativeCryptoAPI.setUp(binding.binaryMessenger, null) | ||||||
|     } |         nativeCrypto = null | ||||||
| 
 |  | ||||||
|     override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { |  | ||||||
|         lateinit var methodCallTask: Task<*> |  | ||||||
| 
 |  | ||||||
|         when (call.method) { |  | ||||||
|             "digest" -> methodCallTask = handleDigest(call.arguments()) |  | ||||||
|             "generateSecretKey" -> methodCallTask = handleGenerateSecretKey(call.arguments()) |  | ||||||
|             "pbkdf2" -> methodCallTask = handlePbkdf2(call.arguments()) |  | ||||||
|             "encryptAsList" -> methodCallTask = handleEncryptAsList(call.arguments()) |  | ||||||
|             "decryptAsList" -> methodCallTask = handleDecryptAsList(call.arguments()) |  | ||||||
|             "encrypt" -> methodCallTask = handleCrypt(call.arguments(), true) |  | ||||||
|             "decrypt" -> methodCallTask = handleCrypt(call.arguments(), false) |  | ||||||
|             else -> result.notImplemented() |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         methodCallTask.call() |  | ||||||
| 
 |  | ||||||
|         methodCallTask.finalize { task -> |  | ||||||
|             if (task.isSuccessful()) { |  | ||||||
|                 result.success(task.getResult()) |  | ||||||
|             } else { |  | ||||||
|                 val exception: Exception = task.getException() |  | ||||||
|                 val message = exception.message |  | ||||||
|                 result.error("native_crypto", message, null) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun handleDigest(arguments: Map<String, Any>?): Task<ByteArray> { |  | ||||||
|         return Task { |  | ||||||
|             val data: ByteArray = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as ByteArray |  | ||||||
|             val algorithm: String = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String |  | ||||||
|             HashAlgorithm.digest(data, algorithm) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun handleGenerateSecretKey(arguments: Map<String, Any>?): Task<ByteArray> { |  | ||||||
|         return Task { |  | ||||||
|             val bitsCount: Int = Objects.requireNonNull(arguments?.get(Constants.BITS_COUNT)) as Int |  | ||||||
|             SecretKey.fromSecureRandom(bitsCount).bytes |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun handlePbkdf2(arguments: Map<String, Any>?): Task<ByteArray> { |  | ||||||
|         return Task { |  | ||||||
|             val password: String = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.PASSWORD)) as String |  | ||||||
|             val salt: String = Objects.requireNonNull(arguments?.get(Constants.SALT)) as String |  | ||||||
|             val keyBytesCount: Int = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.KEY_BYTES_COUNT)) as Int |  | ||||||
|             val iterations: Int = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.ITERATIONS)) as Int |  | ||||||
|             val algorithm: String = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String |  | ||||||
| 
 |  | ||||||
|             val pbkdf2: Pbkdf2 = Pbkdf2(keyBytesCount, iterations, HashAlgorithm.valueOf(algorithm)) |  | ||||||
|             pbkdf2.init(password, salt) |  | ||||||
| 
 |  | ||||||
|             pbkdf2.derive().bytes |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun lazyLoadCipher(cipherAlgorithm: CipherAlgorithm) { |  | ||||||
|         if (cipherInstance == null) { |  | ||||||
|             cipherInstance = cipherAlgorithm.getCipher() |  | ||||||
|         } else { |  | ||||||
|             if (cipherInstance!!.algorithm != cipherAlgorithm) { |  | ||||||
|                 cipherInstance = cipherAlgorithm.getCipher() |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun handleEncryptAsList(arguments: Map<String, Any>?): Task<List<ByteArray>> { |  | ||||||
|         return Task { |  | ||||||
|             val data: ByteArray = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as ByteArray |  | ||||||
|             val key: ByteArray = Objects.requireNonNull(arguments?.get(Constants.KEY)) as ByteArray |  | ||||||
|             val algorithm: String = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String |  | ||||||
| 
 |  | ||||||
|             val cipherAlgorithm: CipherAlgorithm = CipherAlgorithm.valueOf(algorithm) |  | ||||||
|             lazyLoadCipher(cipherAlgorithm) |  | ||||||
| 
 |  | ||||||
|             cipherInstance!!.encryptAsList(data, key) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun handleDecryptAsList(arguments: Map<String, Any>?): Task<ByteArray> { |  | ||||||
|         return Task { |  | ||||||
|             val data: List<ByteArray> = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as List<ByteArray> |  | ||||||
|             val key: ByteArray = Objects.requireNonNull(arguments?.get(Constants.KEY)) as ByteArray |  | ||||||
|             val algorithm: String = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String |  | ||||||
| 
 |  | ||||||
|             val cipherAlgorithm: CipherAlgorithm = CipherAlgorithm.valueOf(algorithm) |  | ||||||
|             lazyLoadCipher(cipherAlgorithm) |  | ||||||
| 
 |  | ||||||
|             cipherInstance!!.decryptAsList(data, key) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // **EN**Crypt and **DE**Crypt |  | ||||||
|     private fun handleCrypt(arguments: Map<String, Any>?, forEncryption: Boolean): Task<ByteArray> { |  | ||||||
|         return Task { |  | ||||||
|             val data: ByteArray = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.DATA)) as ByteArray |  | ||||||
|             val key: ByteArray = Objects.requireNonNull(arguments?.get(Constants.KEY)) as ByteArray |  | ||||||
|             val algorithm: String = |  | ||||||
|                 Objects.requireNonNull(arguments?.get(Constants.ALGORITHM)) as String |  | ||||||
| 
 |  | ||||||
|             val cipherAlgorithm: CipherAlgorithm = CipherAlgorithm.valueOf(algorithm) |  | ||||||
|             lazyLoadCipher(cipherAlgorithm) |  | ||||||
| 
 |  | ||||||
|             if (forEncryption) { |  | ||||||
|                 cipherInstance!!.encrypt(data, key) |  | ||||||
|             } else { |  | ||||||
|                 cipherInstance!!.decrypt(data, key) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,300 @@ | |||||||
|  | // Copyright 2019-2023 Hugo Pointcheval | ||||||
|  | //  | ||||||
|  | // Use of this source code is governed by an MIT-style | ||||||
|  | // license that can be found in the LICENSE file or at | ||||||
|  | // https://opensource.org/licenses/MIT. | ||||||
|  | // -- | ||||||
|  | // Autogenerated from Pigeon (v9.2.0), do not edit directly. | ||||||
|  | // See also: https://pub.dev/packages/pigeon | ||||||
|  | 
 | ||||||
|  | package fr.pointcheval.native_crypto_android | ||||||
|  | 
 | ||||||
|  | import android.util.Log | ||||||
|  | import io.flutter.plugin.common.BasicMessageChannel | ||||||
|  | import io.flutter.plugin.common.BinaryMessenger | ||||||
|  | import io.flutter.plugin.common.MessageCodec | ||||||
|  | import io.flutter.plugin.common.StandardMessageCodec | ||||||
|  | import java.io.ByteArrayOutputStream | ||||||
|  | import java.nio.ByteBuffer | ||||||
|  | 
 | ||||||
|  | private fun wrapResult(result: Any?): List<Any?> { | ||||||
|  |   return listOf(result) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | private fun wrapError(exception: Throwable): List<Any?> { | ||||||
|  |   if (exception is FlutterError) { | ||||||
|  |     return listOf( | ||||||
|  |       exception.code, | ||||||
|  |       exception.message, | ||||||
|  |       exception.details | ||||||
|  |     ) | ||||||
|  |   } else { | ||||||
|  |     return listOf( | ||||||
|  |       exception.javaClass.simpleName, | ||||||
|  |       exception.toString(), | ||||||
|  |       "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Error class for passing custom error details to Flutter via a thrown PlatformException. | ||||||
|  |  * @property code The error code. | ||||||
|  |  * @property message The error message. | ||||||
|  |  * @property details The error details. Must be a datatype supported by the api codec. | ||||||
|  |  */ | ||||||
|  | class FlutterError ( | ||||||
|  |   val code: String, | ||||||
|  |   override val message: String? = null, | ||||||
|  |   val details: Any? = null | ||||||
|  | ) : Throwable() | ||||||
|  | 
 | ||||||
|  | enum class HashAlgorithm(val raw: Int) { | ||||||
|  |   SHA256(0), | ||||||
|  |   SHA384(1), | ||||||
|  |   SHA512(2); | ||||||
|  | 
 | ||||||
|  |   companion object { | ||||||
|  |     fun ofRaw(raw: Int): HashAlgorithm? { | ||||||
|  |       return values().firstOrNull { it.raw == raw } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | enum class CipherAlgorithm(val raw: Int) { | ||||||
|  |   AES(0); | ||||||
|  | 
 | ||||||
|  |   companion object { | ||||||
|  |     fun ofRaw(raw: Int): CipherAlgorithm? { | ||||||
|  |       return values().firstOrNull { it.raw == raw } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ | ||||||
|  | interface NativeCryptoAPI { | ||||||
|  |   fun hash(data: ByteArray, algorithm: HashAlgorithm): ByteArray? | ||||||
|  |   fun hmac(data: ByteArray, key: ByteArray, algorithm: HashAlgorithm): ByteArray? | ||||||
|  |   fun generateSecureRandom(length: Long): ByteArray? | ||||||
|  |   fun pbkdf2(password: ByteArray, salt: ByteArray, length: Long, iterations: Long, algorithm: HashAlgorithm): ByteArray? | ||||||
|  |   fun encrypt(plainText: ByteArray, key: ByteArray, algorithm: CipherAlgorithm): ByteArray? | ||||||
|  |   fun encryptWithIV(plainText: ByteArray, iv: ByteArray, key: ByteArray, algorithm: CipherAlgorithm): ByteArray? | ||||||
|  |   fun decrypt(cipherText: ByteArray, key: ByteArray, algorithm: CipherAlgorithm): ByteArray? | ||||||
|  |   fun encryptFile(plainTextPath: String, cipherTextPath: String, key: ByteArray, algorithm: CipherAlgorithm): Boolean? | ||||||
|  |   fun encryptFileWithIV(plainTextPath: String, cipherTextPath: String, iv: ByteArray, key: ByteArray, algorithm: CipherAlgorithm): Boolean? | ||||||
|  |   fun decryptFile(cipherTextPath: String, plainTextPath: String, key: ByteArray, algorithm: CipherAlgorithm): Boolean? | ||||||
|  | 
 | ||||||
|  |   companion object { | ||||||
|  |     /** The codec used by NativeCryptoAPI. */ | ||||||
|  |     val codec: MessageCodec<Any?> by lazy { | ||||||
|  |       StandardMessageCodec() | ||||||
|  |     } | ||||||
|  |     /** Sets up an instance of `NativeCryptoAPI` to handle messages through the `binaryMessenger`. */ | ||||||
|  |     @Suppress("UNCHECKED_CAST") | ||||||
|  |     fun setUp(binaryMessenger: BinaryMessenger, api: NativeCryptoAPI?) { | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.hash", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val dataArg = args[0] as ByteArray | ||||||
|  |             val algorithmArg = HashAlgorithm.ofRaw(args[1] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.hash(dataArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.hmac", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val dataArg = args[0] as ByteArray | ||||||
|  |             val keyArg = args[1] as ByteArray | ||||||
|  |             val algorithmArg = HashAlgorithm.ofRaw(args[2] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.hmac(dataArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.generateSecureRandom", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val lengthArg = args[0].let { if (it is Int) it.toLong() else it as Long } | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.generateSecureRandom(lengthArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.pbkdf2", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val passwordArg = args[0] as ByteArray | ||||||
|  |             val saltArg = args[1] as ByteArray | ||||||
|  |             val lengthArg = args[2].let { if (it is Int) it.toLong() else it as Long } | ||||||
|  |             val iterationsArg = args[3].let { if (it is Int) it.toLong() else it as Long } | ||||||
|  |             val algorithmArg = HashAlgorithm.ofRaw(args[4] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.pbkdf2(passwordArg, saltArg, lengthArg, iterationsArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.encrypt", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val plainTextArg = args[0] as ByteArray | ||||||
|  |             val keyArg = args[1] as ByteArray | ||||||
|  |             val algorithmArg = CipherAlgorithm.ofRaw(args[2] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.encrypt(plainTextArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.encryptWithIV", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val plainTextArg = args[0] as ByteArray | ||||||
|  |             val ivArg = args[1] as ByteArray | ||||||
|  |             val keyArg = args[2] as ByteArray | ||||||
|  |             val algorithmArg = CipherAlgorithm.ofRaw(args[3] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.encryptWithIV(plainTextArg, ivArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.decrypt", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val cipherTextArg = args[0] as ByteArray | ||||||
|  |             val keyArg = args[1] as ByteArray | ||||||
|  |             val algorithmArg = CipherAlgorithm.ofRaw(args[2] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.decrypt(cipherTextArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.encryptFile", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val plainTextPathArg = args[0] as String | ||||||
|  |             val cipherTextPathArg = args[1] as String | ||||||
|  |             val keyArg = args[2] as ByteArray | ||||||
|  |             val algorithmArg = CipherAlgorithm.ofRaw(args[3] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.encryptFile(plainTextPathArg, cipherTextPathArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.encryptFileWithIV", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val plainTextPathArg = args[0] as String | ||||||
|  |             val cipherTextPathArg = args[1] as String | ||||||
|  |             val ivArg = args[2] as ByteArray | ||||||
|  |             val keyArg = args[3] as ByteArray | ||||||
|  |             val algorithmArg = CipherAlgorithm.ofRaw(args[4] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.encryptFileWithIV(plainTextPathArg, cipherTextPathArg, ivArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       run { | ||||||
|  |         val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.NativeCryptoAPI.decryptFile", codec) | ||||||
|  |         if (api != null) { | ||||||
|  |           channel.setMessageHandler { message, reply -> | ||||||
|  |             val args = message as List<Any?> | ||||||
|  |             val cipherTextPathArg = args[0] as String | ||||||
|  |             val plainTextPathArg = args[1] as String | ||||||
|  |             val keyArg = args[2] as ByteArray | ||||||
|  |             val algorithmArg = CipherAlgorithm.ofRaw(args[3] as Int)!! | ||||||
|  |             var wrapped: List<Any?> | ||||||
|  |             try { | ||||||
|  |               wrapped = listOf<Any?>(api.decryptFile(cipherTextPathArg, plainTextPathArg, keyArg, algorithmArg)) | ||||||
|  |             } catch (exception: Throwable) { | ||||||
|  |               wrapped = wrapError(exception) | ||||||
|  |             } | ||||||
|  |             reply.reply(wrapped) | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           channel.setMessageHandler(null) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,55 +1,146 @@ | |||||||
| package fr.pointcheval.native_crypto_android.ciphers | package fr.pointcheval.native_crypto_android.ciphers | ||||||
| 
 | 
 | ||||||
| import fr.pointcheval.native_crypto_android.interfaces.Cipher | import fr.pointcheval.native_crypto_android.interfaces.Cipher | ||||||
| import fr.pointcheval.native_crypto_android.utils.CipherAlgorithm | import fr.pointcheval.native_crypto_android.utils.FileParameters | ||||||
| import javax.crypto.SecretKey | import javax.crypto.CipherOutputStream | ||||||
| import javax.crypto.spec.GCMParameterSpec | import javax.crypto.spec.GCMParameterSpec | ||||||
| import javax.crypto.spec.IvParameterSpec |  | ||||||
| import javax.crypto.spec.SecretKeySpec | import javax.crypto.spec.SecretKeySpec | ||||||
| 
 | 
 | ||||||
| class AES : Cipher { | class AES : Cipher { | ||||||
|     override val algorithm: CipherAlgorithm |    private var cipherInstance: javax.crypto.Cipher? = null | ||||||
|         get() = CipherAlgorithm.aes |  | ||||||
| 
 | 
 | ||||||
|     var cipherInstance: javax.crypto.Cipher? = null; |     private fun lazyLoadCipher() { | ||||||
| 
 |  | ||||||
|     fun lazyLoadCipher() { |  | ||||||
|         if (cipherInstance == null) { |         if (cipherInstance == null) { | ||||||
|             cipherInstance = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") |             cipherInstance = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // native.crypto cipherText representation = [NONCE(12) || CIPHERTEXT(n-28) || TAG(16)] |  | ||||||
|     // javax.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)] |  | ||||||
|     override fun encrypt(data: ByteArray, key: ByteArray): ByteArray { |  | ||||||
|         val list : List<ByteArray> = encryptAsList(data, key) |  | ||||||
|         return list.first().plus(list.last()) |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // native.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)] |     // native.crypto cipherText representation = [NONCE(12) || CIPHERTEXT(n-28) || TAG(16)] | ||||||
|     // javax.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)] |     override fun encrypt(data: ByteArray, key: ByteArray, predefinedIV: ByteArray?): ByteArray { | ||||||
|     override fun encryptAsList(data: ByteArray, key: ByteArray): List<ByteArray> { |         // Initialize secret key spec | ||||||
|         val sk = SecretKeySpec(key, "AES") |         val sk = SecretKeySpec(key, "AES") | ||||||
|  | 
 | ||||||
|  |         // Initialize cipher (if not already done) | ||||||
|         lazyLoadCipher() |         lazyLoadCipher() | ||||||
|         cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) | 
 | ||||||
|  |         // If predefinedIV is not null, use it | ||||||
|  |         if (predefinedIV != null && predefinedIV.isNotEmpty()) { | ||||||
|  |             // Here we use the predefinedIV as the nonce (12 bytes) | ||||||
|  |             // And we set the tag length to 16 bytes (128 bits) | ||||||
|  |             val gcmParameterSpec = GCMParameterSpec(16*8, predefinedIV) | ||||||
|  |             cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk, gcmParameterSpec) | ||||||
|  |         } else { | ||||||
|  |             // If predefinedIV is null, we generate a new one | ||||||
|  |             cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Encrypt data | ||||||
|         val bytes: ByteArray = cipherInstance!!.doFinal(data) |         val bytes: ByteArray = cipherInstance!!.doFinal(data) | ||||||
|         val iv: ByteArray = cipherInstance!!.iv |         val iv: ByteArray = cipherInstance!!.iv | ||||||
|         return listOf(iv, bytes) | 
 | ||||||
|  |         return iv.plus(bytes) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun encryptFile(fileParameters: FileParameters, key: ByteArray, predefinedIV: ByteArray?): Boolean { | ||||||
|  |         // Initialize secret key spec | ||||||
|  |         val sk = SecretKeySpec(key, "AES") | ||||||
|  | 
 | ||||||
|  |         // Initialize cipher (if not already done) | ||||||
|  |         lazyLoadCipher() | ||||||
|  | 
 | ||||||
|  |         // If predefinedIV is not null, use it | ||||||
|  |         if (predefinedIV != null && predefinedIV.isNotEmpty()) { | ||||||
|  |             // Here we use the predefinedIV as the nonce (12 bytes) | ||||||
|  |             // And we set the tag length to 16 bytes (128 bits) | ||||||
|  |             val gcmParameterSpec = GCMParameterSpec(16*8, predefinedIV) | ||||||
|  |             cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk, gcmParameterSpec) | ||||||
|  |         } else { | ||||||
|  |             // If predefinedIV is null, we generate a new one | ||||||
|  |             cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         var len: Int? | ||||||
|  |         val buffer = ByteArray(8192) | ||||||
|  |         val inputFile = fileParameters.getFileInputStream() | ||||||
|  |         val outputFile = fileParameters.getFileOutputStream() | ||||||
|  |         val iv: ByteArray? = cipherInstance!!.iv | ||||||
|  | 
 | ||||||
|  |         outputFile?.write(iv) | ||||||
|  |         outputFile?.flush() | ||||||
|  | 
 | ||||||
|  |         val encryptedStream = CipherOutputStream(outputFile!!, cipherInstance) | ||||||
|  |         while(true) { | ||||||
|  |             len = inputFile?.read(buffer) | ||||||
|  |             if (len != null && len > 0) { | ||||||
|  |                 encryptedStream.write(buffer,0,len) | ||||||
|  |             } else { | ||||||
|  |                 break | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         encryptedStream.flush() | ||||||
|  |         encryptedStream.close() | ||||||
|  |         inputFile?.close() | ||||||
|  |         outputFile.close() | ||||||
|  | 
 | ||||||
|  |         return fileParameters.outputExists() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun decrypt(data: ByteArray, key: ByteArray): ByteArray { |     override fun decrypt(data: ByteArray, key: ByteArray): ByteArray { | ||||||
|  |         // Extract the IV from the cipherText | ||||||
|         val iv: ByteArray = data.take(12).toByteArray() |         val iv: ByteArray = data.take(12).toByteArray() | ||||||
|         val payload: ByteArray = data.drop(12).toByteArray() |         val payload: ByteArray = data.drop(12).toByteArray() | ||||||
|         return decryptAsList(listOf(iv, payload), key) |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     override fun decryptAsList(data: List<ByteArray>, key: ByteArray): ByteArray { |         // Initialize secret key spec | ||||||
|         val sk = SecretKeySpec(key, "AES") |         val sk = SecretKeySpec(key, "AES") | ||||||
|         val payload: ByteArray = data.last() | 
 | ||||||
|         val iv: ByteArray = data.first() |         // Initialize GCMParameterSpec | ||||||
|         val gcmSpec = GCMParameterSpec(16 * 8, iv) |         val gcmParameterSpec = GCMParameterSpec(16 * 8, iv) | ||||||
|  | 
 | ||||||
|  |         // Initialize cipher (if not already done) | ||||||
|         lazyLoadCipher() |         lazyLoadCipher() | ||||||
|         cipherInstance!!.init(javax.crypto.Cipher.DECRYPT_MODE, sk, gcmSpec) |         cipherInstance!!.init(javax.crypto.Cipher.DECRYPT_MODE, sk, gcmParameterSpec) | ||||||
|  | 
 | ||||||
|  |         // Decrypt data | ||||||
|         return cipherInstance!!.doFinal(payload) |         return cipherInstance!!.doFinal(payload) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     override fun decryptFile(fileParameters: FileParameters, key: ByteArray): Boolean { | ||||||
|  |         val iv = ByteArray(12) | ||||||
|  |         val inputFile = fileParameters.getFileInputStream() ?: throw Exception("Error while reading IV") | ||||||
|  | 
 | ||||||
|  |         // Read the first 12 bytes from the file | ||||||
|  |         for (i in 0 until 12) { | ||||||
|  |             iv[i] = inputFile.read().toByte() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Initialize secret key spec | ||||||
|  |         val sk = SecretKeySpec(key, "AES") | ||||||
|  | 
 | ||||||
|  |         // Initialize GCMParameterSpec | ||||||
|  |         val gcmParameterSpec = GCMParameterSpec(16 * 8, iv) | ||||||
|  | 
 | ||||||
|  |         // Initialize cipher (if not already done) | ||||||
|  |         lazyLoadCipher() | ||||||
|  | 
 | ||||||
|  |         cipherInstance!!.init(javax.crypto.Cipher.DECRYPT_MODE, sk, gcmParameterSpec) | ||||||
|  | 
 | ||||||
|  |         var len: Int? | ||||||
|  |         val buffer = ByteArray(8192) | ||||||
|  |         val outputFile = fileParameters.getFileOutputStream() | ||||||
|  |         val decryptedStream = CipherOutputStream(outputFile!!, cipherInstance) | ||||||
|  |         while (true) { | ||||||
|  |             len = inputFile.read(buffer) | ||||||
|  |             if(len > 0){ | ||||||
|  |                 decryptedStream.write(buffer,0, len) | ||||||
|  |             } else { | ||||||
|  |                 break | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         decryptedStream.flush() | ||||||
|  |         decryptedStream.close() | ||||||
|  |         inputFile.close() | ||||||
|  | 
 | ||||||
|  |         return fileParameters.outputExists() | ||||||
|  |     } | ||||||
| } | } | ||||||
| @ -1,12 +1,10 @@ | |||||||
| package fr.pointcheval.native_crypto_android.interfaces | package fr.pointcheval.native_crypto_android.interfaces | ||||||
| 
 | 
 | ||||||
| import fr.pointcheval.native_crypto_android.utils.CipherAlgorithm | import fr.pointcheval.native_crypto_android.utils.FileParameters | ||||||
| 
 | 
 | ||||||
| interface Cipher { | interface Cipher { | ||||||
|     val algorithm: CipherAlgorithm |     fun encrypt(data: ByteArray, key: ByteArray, predefinedIV: ByteArray?): ByteArray | ||||||
| 
 |  | ||||||
|     fun encrypt(data: ByteArray, key: ByteArray): ByteArray |  | ||||||
|     fun decrypt(data: ByteArray, key: ByteArray): ByteArray |     fun decrypt(data: ByteArray, key: ByteArray): ByteArray | ||||||
|     fun encryptAsList(data: ByteArray, key: ByteArray): List<ByteArray> |     fun encryptFile(fileParameters: FileParameters, key: ByteArray, predefinedIV: ByteArray?): Boolean | ||||||
|     fun decryptAsList(data: List<ByteArray>, key: ByteArray): ByteArray |     fun decryptFile(fileParameters: FileParameters, key: ByteArray): Boolean | ||||||
| } | } | ||||||
| @ -1,5 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.interfaces |  | ||||||
| 
 |  | ||||||
| interface Key { |  | ||||||
|     val bytes: ByteArray |  | ||||||
| } |  | ||||||
| @ -1,10 +1,5 @@ | |||||||
| package fr.pointcheval.native_crypto_android.interfaces | package fr.pointcheval.native_crypto_android.interfaces | ||||||
| 
 | 
 | ||||||
| import fr.pointcheval.native_crypto_android.keys.SecretKey |  | ||||||
| import fr.pointcheval.native_crypto_android.utils.KdfAlgorithm |  | ||||||
| 
 |  | ||||||
| interface KeyDerivation { | interface KeyDerivation { | ||||||
|     val algorithm: KdfAlgorithm |     fun derive(): ByteArray? | ||||||
| 
 |  | ||||||
|     fun derive(): SecretKey |  | ||||||
| } | } | ||||||
| @ -1,39 +1,43 @@ | |||||||
| package fr.pointcheval.native_crypto_android.kdf | package fr.pointcheval.native_crypto_android.kdf | ||||||
| 
 | 
 | ||||||
|  | import fr.pointcheval.native_crypto_android.HashAlgorithm | ||||||
| import fr.pointcheval.native_crypto_android.interfaces.KeyDerivation | import fr.pointcheval.native_crypto_android.interfaces.KeyDerivation | ||||||
| import fr.pointcheval.native_crypto_android.keys.SecretKey | import fr.pointcheval.native_crypto_android.utils.HashAlgorithmParser | ||||||
| import fr.pointcheval.native_crypto_android.utils.HashAlgorithm |  | ||||||
| import fr.pointcheval.native_crypto_android.utils.KdfAlgorithm |  | ||||||
| import javax.crypto.SecretKeyFactory | import javax.crypto.SecretKeyFactory | ||||||
| import javax.crypto.spec.PBEKeySpec | import javax.crypto.spec.PBEKeySpec | ||||||
| 
 | 
 | ||||||
| class Pbkdf2( | class Pbkdf2( | ||||||
|     private val keyBytesCount: Int, private val iterations: Int, |     private val length: Int, private val iterations: Int, | ||||||
|     private val hash: HashAlgorithm = HashAlgorithm.sha256 |     private val hashAlgorithm: HashAlgorithm | ||||||
| ) : KeyDerivation { | ) : KeyDerivation { | ||||||
| 
 | 
 | ||||||
|     private var password: String? = null |     private var password: CharArray? = null | ||||||
|     private var salt: String? = null |     private var salt: ByteArray? = null | ||||||
| 
 | 
 | ||||||
|     fun init(password: String, salt: String) { |     fun init(password: ByteArray, salt: ByteArray) { | ||||||
|         this.password = password |         // Transform the password to a char array | ||||||
|  |         val passwordCharArray = CharArray(password.size) | ||||||
|  |         for (i in password.indices) { | ||||||
|  |             passwordCharArray[i] = password[i].toInt().toChar() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.password = passwordCharArray | ||||||
|         this.salt = salt |         this.salt = salt | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override val algorithm: KdfAlgorithm |     override fun derive(): ByteArray? { | ||||||
|         get() = KdfAlgorithm.pbkdf2 |  | ||||||
| 
 |  | ||||||
|     override fun derive(): SecretKey { |  | ||||||
|         if (password == null || salt == null) { |         if (password == null || salt == null) { | ||||||
|             throw Exception("Password and Salt must be initialized.") |             throw Exception("Password and Salt must be initialized.") | ||||||
|         } |         } | ||||||
|         val spec = PBEKeySpec( |         val spec = PBEKeySpec( | ||||||
|             password!!.toCharArray(), |             password!!, | ||||||
|             salt!!.toByteArray(), |             salt!!, | ||||||
|             iterations, |             iterations, | ||||||
|             keyBytesCount * 8 |             length * 8 | ||||||
|         ) |         ) | ||||||
|         val skf: SecretKeyFactory = SecretKeyFactory.getInstance(hash.pbkdf2String()) |         val skf: SecretKeyFactory = | ||||||
|         return SecretKey(skf.generateSecret(spec).encoded) |             SecretKeyFactory.getInstance(HashAlgorithmParser.getPbkdf2String(hashAlgorithm)) | ||||||
|  | 
 | ||||||
|  |         return skf.generateSecret(spec).encoded | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1,14 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.keys |  | ||||||
| 
 |  | ||||||
| import fr.pointcheval.native_crypto_android.interfaces.Key |  | ||||||
| import java.security.SecureRandom |  | ||||||
| 
 |  | ||||||
| class SecretKey(override val bytes: ByteArray) : Key { |  | ||||||
|     companion object { |  | ||||||
|         fun fromSecureRandom(bitsCount: Int): SecretKey { |  | ||||||
|             val bytes = ByteArray(bitsCount / 8) |  | ||||||
|             SecureRandom.getInstanceStrong().nextBytes(bytes) |  | ||||||
|             return SecretKey(bytes) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,14 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.utils |  | ||||||
| 
 |  | ||||||
| import fr.pointcheval.native_crypto_android.ciphers.AES |  | ||||||
| import fr.pointcheval.native_crypto_android.interfaces.Cipher |  | ||||||
| 
 |  | ||||||
| enum class CipherAlgorithm { |  | ||||||
|     aes; |  | ||||||
| 
 |  | ||||||
|     fun getCipher(): Cipher { |  | ||||||
|         return when (this) { |  | ||||||
|             aes -> AES() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,14 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.utils |  | ||||||
| 
 |  | ||||||
| object Constants { |  | ||||||
|     const val ALGORITHM = "algorithm" |  | ||||||
|     const val BITS_COUNT = "bitsCount" |  | ||||||
|     const val DATA = "data" |  | ||||||
|     const val PASSWORD = "password" |  | ||||||
|     const val SALT = "salt" |  | ||||||
|     const val KEY = "key" |  | ||||||
|     const val KEY_BYTES_COUNT = "keyBytesCount" |  | ||||||
|     const val ITERATIONS = "iterations" |  | ||||||
|     const val EPHEMERAL_PRIVATE_KEY = "ephemeralPrivateKey" |  | ||||||
|     const val OTHER_PUBLIC_KEY = "otherPublicKey" |  | ||||||
| } |  | ||||||
| @ -0,0 +1,71 @@ | |||||||
|  | package fr.pointcheval.native_crypto_android.utils | ||||||
|  | 
 | ||||||
|  | import android.content.Context | ||||||
|  | import android.content.res.Resources | ||||||
|  | import android.net.Uri | ||||||
|  | import androidx.documentfile.provider.DocumentFile | ||||||
|  | import java.io.* | ||||||
|  | 
 | ||||||
|  | class FileParameters(ctx: Context, input: String, output: String) { | ||||||
|  |     private var context: Context | ||||||
|  | 
 | ||||||
|  |     private var inputPath: String | ||||||
|  |     private var outputPath: String | ||||||
|  | 
 | ||||||
|  |     init { | ||||||
|  |         this.context = ctx | ||||||
|  |         this.inputPath = input | ||||||
|  |         this.outputPath = output | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getUri(): Uri? { | ||||||
|  |         val persistedUriPermissions = context.contentResolver.persistedUriPermissions | ||||||
|  |         if (persistedUriPermissions.size > 0) { | ||||||
|  |             val uriPermission = persistedUriPermissions[0] | ||||||
|  |             return uriPermission.uri | ||||||
|  |         } | ||||||
|  |         return null | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getDocumentFileByPath(path: String): DocumentFile { | ||||||
|  |         var doc = DocumentFile.fromTreeUri(context, getUri()!!) | ||||||
|  |         val parts = path.split("/") | ||||||
|  |         for (i in parts.indices) { | ||||||
|  |             val nextFile = doc?.findFile(parts[i]) | ||||||
|  |             if(nextFile != null){ | ||||||
|  |                 doc = nextFile | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (doc != null){ | ||||||
|  |             return doc | ||||||
|  |         } else { | ||||||
|  |             throw Resources.NotFoundException("File not found") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun getFileOutputStream(): OutputStream? { | ||||||
|  |         val path = outputPath | ||||||
|  |         return try{ | ||||||
|  |             FileOutputStream(path) | ||||||
|  |         } catch(e: IOException){ | ||||||
|  |             val documentFile: DocumentFile = this.getDocumentFileByPath(path) | ||||||
|  |             val documentUri = documentFile.uri | ||||||
|  |             context.contentResolver.openOutputStream(documentUri) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun getFileInputStream(): InputStream? { | ||||||
|  |         val path = inputPath | ||||||
|  |         return try{ | ||||||
|  |             FileInputStream(path) | ||||||
|  |         } catch(e: IOException){ | ||||||
|  |             val documentFile: DocumentFile = this.getDocumentFileByPath(path) | ||||||
|  |             val documentUri = documentFile.uri | ||||||
|  |             context.contentResolver.openInputStream(documentUri) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun outputExists(): Boolean { | ||||||
|  |         return File(outputPath).exists() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,50 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.utils |  | ||||||
| 
 |  | ||||||
| import java.security.MessageDigest |  | ||||||
| 
 |  | ||||||
| @Suppress("EnumEntryName") |  | ||||||
| enum class HashAlgorithm(val bitsCount: Int) { |  | ||||||
|     sha256(256), |  | ||||||
|     sha384(384), |  | ||||||
|     sha512(512); |  | ||||||
| 
 |  | ||||||
|     fun messageDigestString(): String { |  | ||||||
|         return when (this) { |  | ||||||
|             sha256 -> "SHA-256" |  | ||||||
|             sha384 -> "SHA-384" |  | ||||||
|             sha512 -> "SHA-512" |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun hmacString(): String { |  | ||||||
|         return when (this) { |  | ||||||
|             sha256 -> "HmacSHA256" |  | ||||||
|             sha384 -> "HmacSHA384" |  | ||||||
|             sha512 -> "HmacSHA512" |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun pbkdf2String(): String { |  | ||||||
|         return when (this) { |  | ||||||
|             sha256 -> "PBKDF2WithHmacSHA256" |  | ||||||
|             sha384 -> "PBKDF2WithHmacSHA384" |  | ||||||
|             sha512 -> "PBKDF2WithHmacSHA512" |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun digest(data: ByteArray): ByteArray { |  | ||||||
|         val md = MessageDigest.getInstance(messageDigestString()) |  | ||||||
|         return md.digest(data) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     companion object { |  | ||||||
|         fun digest(data: ByteArray, algorithm: String): ByteArray { |  | ||||||
|             for (h in values()) { |  | ||||||
|                 if (h.name == algorithm) { |  | ||||||
|                     return h.digest(data) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             throw Exception("Unknown HashAlgorithm: $algorithm") |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,31 @@ | |||||||
|  | package fr.pointcheval.native_crypto_android.utils | ||||||
|  | 
 | ||||||
|  | import fr.pointcheval.native_crypto_android.HashAlgorithm | ||||||
|  | import java.security.MessageDigest | ||||||
|  | import javax.crypto.Mac | ||||||
|  | 
 | ||||||
|  | object HashAlgorithmParser { | ||||||
|  |     fun getMessageDigest(algorithm: HashAlgorithm): MessageDigest { | ||||||
|  |         return when (algorithm) { | ||||||
|  |             HashAlgorithm.SHA256 -> MessageDigest.getInstance("SHA-256") | ||||||
|  |             HashAlgorithm.SHA384 -> MessageDigest.getInstance("SHA-384") | ||||||
|  |             HashAlgorithm.SHA512 -> MessageDigest.getInstance("SHA-512") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun getMac(algorithm: HashAlgorithm): Mac { | ||||||
|  |         return when (algorithm) { | ||||||
|  |             HashAlgorithm.SHA256 -> Mac.getInstance("HmacSHA256") | ||||||
|  |             HashAlgorithm.SHA384 -> Mac.getInstance("HmacSHA384") | ||||||
|  |             HashAlgorithm.SHA512 -> Mac.getInstance("HmacSHA512") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun getPbkdf2String(algorithm: HashAlgorithm): String { | ||||||
|  |         return when (algorithm) { | ||||||
|  |             HashAlgorithm.SHA256 -> "PBKDF2WithHmacSHA256" | ||||||
|  |             HashAlgorithm.SHA384 -> "PBKDF2WithHmacSHA384" | ||||||
|  |             HashAlgorithm.SHA512 -> "PBKDF2WithHmacSHA512" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,5 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.utils |  | ||||||
| 
 |  | ||||||
| enum class KdfAlgorithm { |  | ||||||
|     pbkdf2 |  | ||||||
| } |  | ||||||
| @ -1,44 +0,0 @@ | |||||||
| package fr.pointcheval.native_crypto_android.utils |  | ||||||
| 
 |  | ||||||
| class Task<T>(private var task: () -> T) { |  | ||||||
| 
 |  | ||||||
|     private var successful = false |  | ||||||
|     private var result: T? = null |  | ||||||
|     private var exception: Exception? = null |  | ||||||
| 
 |  | ||||||
|     fun isSuccessful(): Boolean { |  | ||||||
|         return successful |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun getResult(): T { |  | ||||||
|         if (successful && result != null) { |  | ||||||
|             return result!! |  | ||||||
|         } else { |  | ||||||
|             throw Exception("No result found!") |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun getException(): Exception { |  | ||||||
|         if (exception != null) { |  | ||||||
|             return exception!! |  | ||||||
|         } else { |  | ||||||
|             throw Exception("No exception found!") |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun call() { |  | ||||||
|         try { |  | ||||||
|             result = task() |  | ||||||
|             exception = null |  | ||||||
|             successful = true |  | ||||||
|         } catch (e: Exception) { |  | ||||||
|             exception = e |  | ||||||
|             result = null |  | ||||||
|             successful = false |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fun finalize(callback: (task: Task<T>) -> Unit) { |  | ||||||
|         callback(this) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user