From 21e4e2db70326bee3092c21760ca4a737fef6362 Mon Sep 17 00:00:00 2001 From: ahmadrezadev-pc Date: Sat, 9 Aug 2025 02:21:42 +0330 Subject: [PATCH 1/2] Refactors build.gradle to streamline configuration and update SDK versions --- cryptography_flutter/android/build.gradle | 49 +++++++++-------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/cryptography_flutter/android/build.gradle b/cryptography_flutter/android/build.gradle index 6b37889..bdf73ab 100644 --- a/cryptography_flutter/android/build.gradle +++ b/cryptography_flutter/android/build.gradle @@ -1,51 +1,42 @@ group 'dev.dint.cryptography_flutter' version '1.0-SNAPSHOT' -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' - dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } +repositories { + google() + mavenCentral() } -allprojects { - repositories { - google() - mavenCentral() - } -} +android { + // MUST match the package in android/src/main/AndroidManifest.xml + namespace "dev.dint.cryptography_flutter" -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' + // Use a modern compile SDK compatible with AGP 8.x + compileSdkVersion 34 -android { - compileSdkVersion 31 + defaultConfig { + minSdkVersion 21 + } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + // AGP 8.x expects Java 17 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' } sourceSets { main.java.srcDirs += 'src/main/kotlin' } - - defaultConfig { - minSdkVersion 21 - } } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + // Rely on the root project's Kotlin version; stdlib only + implementation "org.jetbrains.kotlin:kotlin-stdlib" implementation "androidx.security:security-crypto:1.1.0-alpha05" -} \ No newline at end of file +} From fe20caf3918754247275d25272e2039b6c13a789 Mon Sep 17 00:00:00 2001 From: ahmadrezadev-pc Date: Sat, 9 Aug 2025 02:39:12 +0330 Subject: [PATCH 2/2] Refactors CryptographyFlutterPlugin.kt for improved code clarity and organization --- .../CryptographyFlutterPlugin.kt | 447 +++++++----------- 1 file changed, 171 insertions(+), 276 deletions(-) diff --git a/cryptography_flutter/android/src/main/kotlin/dev/dint/cryptography_flutter/CryptographyFlutterPlugin.kt b/cryptography_flutter/android/src/main/kotlin/dev/dint/cryptography_flutter/CryptographyFlutterPlugin.kt index f37d14e..a013894 100644 --- a/cryptography_flutter/android/src/main/kotlin/dev/dint/cryptography_flutter/CryptographyFlutterPlugin.kt +++ b/cryptography_flutter/android/src/main/kotlin/dev/dint/cryptography_flutter/CryptographyFlutterPlugin.kt @@ -3,7 +3,6 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -14,34 +13,68 @@ package dev.dint.cryptography_flutter -import android.os.Build -import androidx.annotation.RequiresApi 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 import java.math.BigInteger -import java.security.* -import java.security.interfaces.* -import java.security.spec.* -import javax.crypto.* -import javax.crypto.spec.* - -/** CryptographyFlutterPlugin */ +import java.security.AlgorithmParameters +import java.security.KeyFactory +import java.security.KeyPairGenerator +import java.security.Provider +import java.security.Security +import java.security.Signature +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.ECPublicKey +import java.security.spec.ECGenParameterSpec +import java.security.spec.ECParameterSpec +import java.security.spec.ECPoint +import java.security.spec.ECPrivateKeySpec +import java.security.spec.ECPublicKeySpec +import javax.crypto.AEADBadTagException +import javax.crypto.Cipher +import javax.crypto.KeyAgreement +import javax.crypto.Mac +import javax.crypto.SecretKeyFactory +import javax.crypto.spec.GCMParameterSpec +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.PBEKeySpec +import javax.crypto.spec.SecretKeySpec + +/** + * Flutter plugin for Android cryptography helpers used by the Dart package. + * + * This class uses the Android embedding v2 API (FlutterPlugin + MethodChannel). + * No v1 Registrar is used or imported anymore. + */ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { + + /** Channel used to communicate with Dart side. */ private lateinit var channel: MethodChannel - override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cryptography_flutter") + /** + * Called when the plugin is attached to a FlutterEngine. + * Sets up the MethodChannel and registers this instance as the handler. + */ + override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { + // NOTE: Channel name must match the Dart side initialization. + // The historical channel name for this plugin is "cryptography_flutter". + channel = MethodChannel(binding.binaryMessenger, "cryptography_flutter") channel.setMethodCallHandler(this) } + /** + * Called when the plugin is detached from a FlutterEngine. + * Cleans up the MethodChannel to avoid leaks. + */ override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { channel.setMethodCallHandler(null) } + /** + * Dispatch method calls coming from Dart. + */ override fun onMethodCall(call: MethodCall, result: Result) { try { when (call.method) { @@ -52,40 +85,45 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "encrypt" -> encrypt(call, result) "decrypt" -> decrypt(call, result) - // Ecdh + // ECDH "Ecdh.newKeyPair" -> ecNewKeyPair(call, result) "Ecdh.sharedSecretKey" -> ecdhSharedSecretKey(call, result) - // Ecdsa + // ECDSA "Ecdsa.newKeyPair" -> ecNewKeyPair(call, result) "Ecdsa.sign" -> ecdsaSign(call, result) "Ecdsa.verify" -> ecdsaVerify(call, result) - // Ed25519 - "Ed25519.newKeyPair" -> ed25519NewKeyPair(call, result) - "Ed25519.sign" -> ed25519Sign(call, result) - "Ed25519.verify" -> ed25519Verify(call, result) + // Ed25519 (not implemented on Android in this plugin) + "Ed25519.newKeyPair", + "Ed25519.sign", + "Ed25519.verify" -> result.error("UNSUPPORTED_ALGORITHM", null, null) - // X25519 - "X25519.newKeyPair" -> x25519NewKeyPair(call, result) - "X25519.sign" -> x25519SharedSecretKey(call, result) + // X25519 (not implemented on Android in this plugin) + "X25519.newKeyPair", + "X25519.sign" /* historical name for shared secret */ , + "X25519.sharedSecretKey" -> result.error("UNSUPPORTED_ALGORITHM", null, null) - // Other + // HMAC / PBKDF2 "hmac" -> hmac(call, result) "pbkdf2" -> pbkdf2(call, result) - else -> { - result.notImplemented() - } + + else -> result.notImplemented() } } catch (e: Throwable) { result.error( "CAUGHT_ERROR", - "Unexpected error ${e}: ${e.message}\nCause: ${e.cause}\nStack stace:\n${e.stackTraceToString()}", + "Unexpected error $e: ${e.message}\nCause: ${e.cause}\nStack trace:\n${e.stackTraceToString()}", null ) } } + // --------------------------------------------------------------------- + // Providers + // --------------------------------------------------------------------- + + /** Returns a list of installed security providers and their services. */ private fun androidCryptoProviders(call: MethodCall, result: Result) { val providers = Security.getProviders() val list = mutableListOf>() @@ -111,49 +149,47 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { result.success(list) } - + /** Dynamically add a provider by class name (advanced usage). */ private fun androidCryptoProvidersAdd(call: MethodCall, result: Result) { val provider = Class.forName(call.arguments as String).getConstructor().newInstance() Security.addProvider(provider as Provider) + result.success(null) } - private fun androidCipherAlgo(dartAlgo: String?): String? { - return when (dartAlgo) { + // --------------------------------------------------------------------- + // Symmetric Ciphers (AES-GCM, ChaCha20-Poly1305) + // --------------------------------------------------------------------- + + /** Maps Dart algorithm names to Android transformation names. */ + private fun androidCipherAlgo(dartAlgo: String?): String? = + when (dartAlgo) { "AES_GCM" -> "AES/GCM/NoPadding" "CHACHA20_POLY1305_AEAD" -> "ChaCha20/Poly1305/NoPadding" else -> null } - } - private fun cipherMacLength(dartMacAlgo: String?): Int? { - return when (dartMacAlgo) { + /** Returns MAC length in bytes for the given AEAD algorithm. */ + private fun cipherMacLength(dartMacAlgo: String?): Int? = + when (dartMacAlgo) { "AES_GCM" -> 16 "CHACHA20_POLY1305_AEAD" -> 16 else -> null } - } + /** Decrypts data using AES-GCM or ChaCha20-Poly1305. */ private fun decrypt(call: MethodCall, result: Result) { val dartAlgo = call.argument("algo") val androidAlgo = androidCipherAlgo(dartAlgo) val macLength = cipherMacLength(dartAlgo) if (androidAlgo == null || macLength == null) { - result.error( - "UNSUPPORTED_ALGORITHM", - "cryptography_flutter does not support algorithm ${dartAlgo} in Android.", - null - ) + result.error("UNSUPPORTED_ALGORITHM", "Unsupported algorithm $dartAlgo", null) return } - var cipher: Cipher; - try { - cipher = Cipher.getInstance(androidAlgo) - } catch (error: NoSuchAlgorithmException) { - result.error( - "UNSUPPORTED_ALGORITHM", - "Your version of Android does not support ${androidAlgo}.", - null - ) + + val cipher = try { + Cipher.getInstance(androidAlgo) + } catch (_: Throwable) { + result.error("UNSUPPORTED_ALGORITHM", "Your Android version does not support $androidAlgo.", null) return } @@ -161,112 +197,61 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { val secretKey = call.argument("key")!! val nonce = call.argument("nonce")!! val aad = call.argument("aad") - var mac = call.argument("mac") - val params = if (dartAlgo == "AES_GCM") { - GCMParameterSpec(16 * 8, nonce) - } else { - IvParameterSpec(nonce) - } - cipher.init( - Cipher.DECRYPT_MODE, - SecretKeySpec(secretKey, androidAlgo), - params, - ) + val mac = call.argument("mac") + val params = if (dartAlgo == "AES_GCM") GCMParameterSpec(16 * 8, nonce) else IvParameterSpec(nonce) - // AAD - if (aad != null) { - cipher.updateAAD(aad) - } + cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(secretKey, androidAlgo), params) + if (aad != null) cipher.updateAAD(aad) cipher.update(cipherText) try { val clearText = cipher.doFinal(mac) - result.success( - hashMapOf( - "clearText" to clearText, - ) - ) + result.success(hashMapOf("clearText" to clearText)) } catch (e: AEADBadTagException) { - result.error( - "INCORRECT_MAC", - "Caught error when decrypting ${androidAlgo}: ${e.message}", - null - ) - } catch (e: BadPaddingException) { - result.error( - "INCORRECT_PADDING", - "Caught error when decrypting ${androidAlgo}: ${e.message}", - null - ) + result.error("INCORRECT_MAC", "AEAD tag verification failed: ${e.message}", null) } catch (e: Throwable) { - result.error( - "CAUGHT_ERROR", - "Caught error when decrypting ${androidAlgo}: ${e.message}", - null - ) + result.error("CAUGHT_ERROR", "Decrypt error for $androidAlgo: ${e.message}", null) } } + /** Encrypts data using AES-GCM or ChaCha20-Poly1305 and splits ciphertext/MAC. */ private fun encrypt(call: MethodCall, result: Result) { val dartAlgo = call.argument("algo") val androidAlgo = androidCipherAlgo(dartAlgo) val macLength = cipherMacLength(dartAlgo) if (androidAlgo == null || macLength == null) { - result.error( - "UNSUPPORTED_ALGORITHM", - "cryptography_flutter does not support algorithm ${dartAlgo} in Android.", - null - ) + result.error("UNSUPPORTED_ALGORITHM", "Unsupported algorithm $dartAlgo", null) return } - var cipher: Cipher; - try { - cipher = Cipher.getInstance(androidAlgo) - } catch (error: NoSuchAlgorithmException) { - result.error( - "UNSUPPORTED_ALGORITHM", - "Your version of Android does not support ${androidAlgo}.", - null - ) + + val cipher = try { + Cipher.getInstance(androidAlgo) + } catch (_: Throwable) { + result.error("UNSUPPORTED_ALGORITHM", "Your Android version does not support $androidAlgo.", null) return } val clearText = call.argument("data")!! - val secretKey = call.argument("key") - val nonce = call.argument("nonce") + val secretKey = call.argument("key")!! + val nonce = call.argument("nonce")!! val aad = call.argument("aad") - val dartMacAlgo = call.argument("macAlgo") - val params = if (dartAlgo == "AES_GCM") { - GCMParameterSpec(macLength * 8, nonce) - } else { - IvParameterSpec(nonce) - } - cipher.init( - Cipher.ENCRYPT_MODE, - SecretKeySpec(secretKey, androidAlgo), - params, - ) + val params = if (dartAlgo == "AES_GCM") GCMParameterSpec(macLength * 8, nonce) else IvParameterSpec(nonce) + cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(secretKey, androidAlgo), params) + if (aad != null) cipher.updateAAD(aad) - // AAD - if (aad != null) { - cipher.updateAAD(aad) - } val cipherTextAndMac = cipher.doFinal(clearText) val cipherTextEnd = cipherTextAndMac.size - macLength val cipherText = cipherTextAndMac.copyOfRange(0, cipherTextEnd) val mac = cipherTextAndMac.copyOfRange(cipherTextEnd, cipherTextAndMac.size) - result.success( - hashMapOf( - "cipherText" to cipherText, - "mac" to mac, - ) - ) + result.success(hashMapOf("cipherText" to cipherText, "mac" to mac)) } - // - // ECDH - // + // --------------------------------------------------------------------- + // ECDH / ECDSA + // --------------------------------------------------------------------- + + /** Generates a new EC key pair for the requested curve. */ private fun ecNewKeyPair(call: MethodCall, result: Result) { val dartAlgo = call.argument("curve")!! val curve = when (dartAlgo) { @@ -274,16 +259,14 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "p384" -> "secp384r1" "p521" -> "secp521r1" else -> null + } ?: run { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } - if (curve == null) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return - } + val provider = call.argument("androidProvider") - val generator = when (provider) { - null -> KeyPairGenerator.getInstance("EC") - else -> KeyPairGenerator.getInstance("EC", provider) - } + val generator = if (provider == null) KeyPairGenerator.getInstance("EC") + else KeyPairGenerator.getInstance("EC", provider) + generator.initialize(ECGenParameterSpec(curve)) val keyPair = generator.generateKeyPair() val privateKey = keyPair.private as ECPrivateKey @@ -298,6 +281,7 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { ) } + /** Computes an ECDH shared secret from local private and remote public keys. */ private fun ecdhSharedSecretKey(call: MethodCall, result: Result) { val dartCurve = call.argument("curve")!! val curve = when (dartCurve) { @@ -305,56 +289,38 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "p384" -> "secp384r1" "p521" -> "secp521r1" else -> null + } ?: run { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } - if (curve == null) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return - } + val d = call.argument("localD")!! - val x = call.argument("localX")!! - val y = call.argument("localY")!! + val remoteX = call.argument("remoteX")!! + val remoteY = call.argument("remoteY")!! val provider = call.argument("androidProvider") - val parameters = when (provider) { - null -> AlgorithmParameters.getInstance("EC") - else -> AlgorithmParameters.getInstance("EC", provider) - } + val parameters = if (provider == null) AlgorithmParameters.getInstance("EC") + else AlgorithmParameters.getInstance("EC", provider) parameters.init(ECGenParameterSpec(curve)) val ecParameters = parameters.getParameterSpec(ECParameterSpec::class.java) - val privateKeySpec = ECPrivateKeySpec( - BigInteger(d), - ecParameters - ) - val remoteX = call.argument("remoteX")!! - val remoteY = call.argument("remoteY")!! + val privateKeySpec = ECPrivateKeySpec(BigInteger(d), ecParameters) val remotePublicPoint = ECPoint(BigInteger(remoteX), BigInteger(remoteY)) val remotePublicKeySpec = ECPublicKeySpec(remotePublicPoint, ecParameters) - val keyFactory = when (provider) { - null -> KeyFactory.getInstance("EC") - else -> KeyFactory.getInstance("EC", provider) - } + val keyFactory = if (provider == null) KeyFactory.getInstance("EC") + else KeyFactory.getInstance("EC", provider) val privateKey = keyFactory.generatePrivate(privateKeySpec) as ECPrivateKey val remotePublicKey = keyFactory.generatePublic(remotePublicKeySpec) as ECPublicKey - val keyAgreement = when (provider) { - null -> KeyAgreement.getInstance("ECDH") - else -> KeyAgreement.getInstance("ECDH", provider) - } + val keyAgreement = if (provider == null) KeyAgreement.getInstance("ECDH") + else KeyAgreement.getInstance("ECDH", provider) keyAgreement.init(privateKey) keyAgreement.doPhase(remotePublicKey, true) val secretKey = keyAgreement.generateSecret() - result.success( - hashMapOf( - "bytes" to secretKey, - ) - ) + result.success(hashMapOf("bytes" to secretKey)) } - // - // ECDSA - // + /** Signs a message with an EC private key (ECDSA). */ private fun ecdsaSign(call: MethodCall, result: Result) { val dartCurve = call.argument("curve")!! val curve = when (dartCurve) { @@ -362,10 +328,8 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "p384" -> "secp384r1" "p521" -> "secp521r1" else -> null - } - if (curve == null) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return + } ?: run { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } val signatureName = when (dartCurve) { "p256" -> "SHA256withECDSA" @@ -376,41 +340,27 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { val message = call.argument("data")!! val d = call.argument("d")!! - val x = call.argument("x")!! - val y = call.argument("y")!! val provider = call.argument("androidProvider") - val parameters = when (provider) { - null -> AlgorithmParameters.getInstance("EC") - else -> AlgorithmParameters.getInstance("EC", provider) - } + val parameters = if (provider == null) AlgorithmParameters.getInstance("EC") + else AlgorithmParameters.getInstance("EC", provider) parameters.init(ECGenParameterSpec(curve)) val ecParameters = parameters.getParameterSpec(ECParameterSpec::class.java) - val privateKeySpec = ECPrivateKeySpec( - BigInteger(d), - ecParameters - ) + val privateKeySpec = ECPrivateKeySpec(BigInteger(d), ecParameters) - val keyFactory = when (provider) { - null -> KeyFactory.getInstance("EC") - else -> KeyFactory.getInstance("EC", provider) - } + val keyFactory = if (provider == null) KeyFactory.getInstance("EC") + else KeyFactory.getInstance("EC", provider) val privateKey = keyFactory.generatePrivate(privateKeySpec) as ECPrivateKey - val signature = when (provider) { - null -> Signature.getInstance(signatureName) - else -> Signature.getInstance(signatureName, provider) - } + val signature = if (provider == null) Signature.getInstance(signatureName) + else Signature.getInstance(signatureName, provider) signature.initSign(privateKey) signature.update(message) val signatureBytes = signature.sign() - result.success( - hashMapOf( - "signature" to signatureBytes, - ) - ) + result.success(hashMapOf("signature" to signatureBytes)) } + /** Verifies an ECDSA signature with a public key (x,y). */ private fun ecdsaVerify(call: MethodCall, result: Result) { val dartCurve = call.argument("curve")!! val curve = when (dartCurve) { @@ -418,10 +368,8 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "p384" -> "secp384r1" "p521" -> "secp521r1" else -> null - } - if (curve == null) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return + } ?: run { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } val signatureName = when (dartCurve) { "p256" -> "SHA256withECDSA" @@ -436,65 +384,31 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { val verifiedSignatureBytes = call.argument("signature")!! val provider = call.argument("androidProvider") - val parameters = when (provider) { - null -> AlgorithmParameters.getInstance("EC") - else -> AlgorithmParameters.getInstance("EC", provider) - } + val parameters = if (provider == null) AlgorithmParameters.getInstance("EC") + else AlgorithmParameters.getInstance("EC", provider) parameters.init(ECGenParameterSpec(curve)) val ecParameters = parameters.getParameterSpec(ECParameterSpec::class.java) val publicKeyPoint = ECPoint(x, y) val publicKeySpec = ECPublicKeySpec(publicKeyPoint, ecParameters) - val keyFactory = when (provider) { - null -> KeyFactory.getInstance("EC") - else -> KeyFactory.getInstance("EC", provider) - } + val keyFactory = if (provider == null) KeyFactory.getInstance("EC") + else KeyFactory.getInstance("EC", provider) val publicKey = keyFactory.generatePublic(publicKeySpec) as ECPublicKey - val signature = when (provider) { - null -> Signature.getInstance(signatureName) - else -> Signature.getInstance(signatureName, provider) - } + val signature = if (provider == null) Signature.getInstance(signatureName) + else Signature.getInstance(signatureName, provider) signature.initVerify(publicKey) signature.update(message) val ok = signature.verify(verifiedSignatureBytes) - result.success( - hashMapOf( - "result" to ok, - ) - ) - } - - // - // ED25519 - // - private fun ed25519NewKeyPair(call: MethodCall, result: Result) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - } - - private fun ed25519Sign(call: MethodCall, result: Result) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - } - - private fun ed25519Verify(call: MethodCall, result: Result) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - } - - // - // X25519 - // - private fun x25519NewKeyPair(call: MethodCall, result: Result) { - result.error("UNSUPPORTED_ALGORITHM", null, null) + result.success(hashMapOf("result" to ok)) } - private fun x25519SharedSecretKey(call: MethodCall, result: Result) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - } + // --------------------------------------------------------------------- + // HMAC / PBKDF2 + // --------------------------------------------------------------------- - // - // HMAC - // + /** Computes HMAC using one of SHA-1/224/256/384/512. */ private fun hmac(call: MethodCall, result: Result) { val hash = call.argument("hash")!! val instanceId = when (hash) { @@ -504,26 +418,18 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "SHA-384" -> "HmacSHA384" "SHA-512" -> "HmacSHA512" else -> null - } - if (instanceId == null) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return + } ?: run { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } val key = call.argument("key")!! val data = call.argument("data")!! - val instance = Mac.getInstance(instanceId); - instance.init(SecretKeySpec(key, instanceId)); - val mac = instance.doFinal(data); - result.success( - hashMapOf( - "mac" to mac, - ) - ) + val instance = Mac.getInstance(instanceId) + instance.init(SecretKeySpec(key, instanceId)) + val mac = instance.doFinal(data) + result.success(hashMapOf("mac" to mac)) } - // - // PBKDF2 - // + /** Computes PBKDF2 with HMAC-* (SHA1/224/256/384/512). */ private fun pbkdf2(call: MethodCall, result: Result) { val mac = call.argument("mac")!! val instanceId = when (mac) { @@ -533,34 +439,23 @@ class CryptographyFlutterPlugin : FlutterPlugin, MethodCallHandler { "HMAC-SHA384" -> "PBKDF2WithHmacSHA384" "HMAC-SHA512" -> "PBKDF2WithHmacSHA512" else -> null - } - if (instanceId==null) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return + } ?: run { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } val bits = call.argument("bits")!! val iterations = call.argument("iterations")!! val password = call.argument("password")!! val nonce = call.argument("nonce")!! - var secretKeyFactory: SecretKeyFactory - try { - secretKeyFactory = SecretKeyFactory.getInstance(instanceId) - } catch (e: NoSuchAlgorithmException) { - result.error("UNSUPPORTED_ALGORITHM", null, null) - return + + val secretKeyFactory = try { + SecretKeyFactory.getInstance(instanceId) + } catch (_: Throwable) { + result.error("UNSUPPORTED_ALGORITHM", null, null); return } + val secretKey = secretKeyFactory.generateSecret( - PBEKeySpec( - password.toCharArray(), - nonce, - iterations, - bits - ) - ) - result.success( - hashMapOf( - "hash" to secretKey.getEncoded(), - ) + PBEKeySpec(password.toCharArray(), nonce, iterations, bits) ) + result.success(hashMapOf("hash" to secretKey.encoded)) } }