diff --git a/dialer/android/app/src/main/kotlin/com/icing/dialer/KeyDeleter.kt b/dialer/android/app/src/main/kotlin/com/icing/dialer/KeyDeleter.kt deleted file mode 100644 index 34390a2..0000000 --- a/dialer/android/app/src/main/kotlin/com/icing/dialer/KeyDeleter.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.icing.dialer - -import java.security.KeyStore - -object KeyDeleterHelper { - - private const val ANDROID_KEYSTORE = "AndroidKeyStore" - - /** - * Deletes the key pair associated with the given alias from the Android Keystore. - * - * @param alias The alias of the key pair to delete. - * @throws Exception if deletion fails. - */ - fun deleteKeyPair(alias: String) { - try { - val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) } - - if (!keyStore.containsAlias(alias)) { - throw Exception("No key found with alias \"$alias\" to delete.") - } - - keyStore.deleteEntry(alias) - } catch (e: Exception) { - throw Exception("Failed to delete key pair: ${e.message}", e) - } - } -} diff --git a/dialer/android/app/src/main/kotlin/com/icing/dialer/KeyGenerator.kt b/dialer/android/app/src/main/kotlin/com/icing/dialer/KeyGenerator.kt deleted file mode 100644 index 343fb39..0000000 --- a/dialer/android/app/src/main/kotlin/com/icing/dialer/KeyGenerator.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.icing.dialer - -import android.security.keystore.KeyGenParameterSpec -import android.security.keystore.KeyProperties -import java.security.KeyPairGenerator -import java.security.KeyStore - -object KeyGeneratorHelper { - - private const val ANDROID_KEYSTORE = "AndroidKeyStore" - - /** - * Generates an ECDSA P-256 key pair and stores it in the Android Keystore. - * - * @param alias Unique identifier for the key pair. - * @throws Exception if key generation fails. - */ - fun generateECKeyPair(alias: String) { - try { - val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) } - - // Check if the key already exists - if (keyStore.containsAlias(alias)) { - throw Exception("Key with alias \"$alias\" already exists.") - } - - val keyPairGenerator = KeyPairGenerator.getInstance( - KeyProperties.KEY_ALGORITHM_EC, - ANDROID_KEYSTORE - ) - - val parameterSpec = KeyGenParameterSpec.Builder( - alias, - KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY - ) - .setAlgorithmParameterSpec(java.security.spec.ECGenParameterSpec("secp256r1")) - .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512) - .setUserAuthenticationRequired(false) // Set to true if you require user authentication - .build() - - keyPairGenerator.initialize(parameterSpec) - keyPairGenerator.generateKeyPair() - } catch (e: Exception) { - throw Exception("Failed to generate EC key pair: ${e.message}", e) - } - } -} diff --git a/dialer/android/app/src/main/kotlin/com/icing/dialer/KeystoreHelper.kt b/dialer/android/app/src/main/kotlin/com/icing/dialer/KeystoreHelper.kt index 8cd0b14..e20e710 100644 --- a/dialer/android/app/src/main/kotlin/com/icing/dialer/KeystoreHelper.kt +++ b/dialer/android/app/src/main/kotlin/com/icing/dialer/KeystoreHelper.kt @@ -1,6 +1,6 @@ package com.icing.dialer -import java.security.PrivateKey +import android.os.Build import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties import android.util.Base64 @@ -8,15 +8,21 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import java.security.KeyPairGenerator import java.security.KeyStore +import java.security.PrivateKey import java.security.Signature +import java.security.spec.ECGenParameterSpec class KeystoreHelper(private val call: MethodCall, private val result: MethodChannel.Result) { private val ANDROID_KEYSTORE = "AndroidKeyStore" fun handleMethodCall() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + result.error("UNSUPPORTED_API", "ED25519 requires Android 11 (API 30) or higher", null) + return + } when (call.method) { - "generateKeyPair" -> generateECKeyPair() + "generateKeyPair" -> generateEDKeyPair() "signData" -> signData() "getPublicKey" -> getPublicKey() "deleteKeyPair" -> deleteKeyPair() @@ -25,7 +31,7 @@ class KeystoreHelper(private val call: MethodCall, private val result: MethodCha } } - private fun generateECKeyPair() { + private fun generateEDKeyPair() { val alias = call.argument("alias") if (alias == null) { result.error("INVALID_ARGUMENT", "Alias is required", null) @@ -44,16 +50,14 @@ class KeystoreHelper(private val call: MethodCall, private val result: MethodCha KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE ) - val parameterSpec = KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY ) - .setAlgorithmParameterSpec(java.security.spec.ECGenParameterSpec("secp256r1")) - .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512) + .setAlgorithmParameterSpec(ECGenParameterSpec("ed25519")) + .setDigests(KeyProperties.DIGEST_SHA256) .setUserAuthenticationRequired(false) .build() - keyPairGenerator.initialize(parameterSpec) keyPairGenerator.generateKeyPair() @@ -73,17 +77,14 @@ class KeystoreHelper(private val call: MethodCall, private val result: MethodCha try { val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) } - val privateKey = keyStore.getKey(alias, null) as? PrivateKey ?: run { result.error("KEY_NOT_FOUND", "Private key not found for alias \"$alias\".", null) return } - - val signature = Signature.getInstance("SHA256withECDSA") + val signature = Signature.getInstance("Ed25519") signature.initSign(privateKey) signature.update(data.toByteArray()) val signedBytes = signature.sign() - val signatureBase64 = Base64.encodeToString(signedBytes, Base64.DEFAULT) result.success(signatureBase64) } catch (e: Exception) { diff --git a/dialer/android/app/src/main/kotlin/com/icing/dialer/PublicKeyRetriever.kt b/dialer/android/app/src/main/kotlin/com/icing/dialer/PublicKeyRetriever.kt deleted file mode 100644 index 719a8e8..0000000 --- a/dialer/android/app/src/main/kotlin/com/icing/dialer/PublicKeyRetriever.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.icing.dialer - -import java.security.KeyStore -import java.security.PublicKey -import android.util.Base64 - -object PublicKeyHelper { - - private const val ANDROID_KEYSTORE = "AndroidKeyStore" - - /** - * Retrieves the public key associated with the given alias. - * - * @param alias The alias of the key pair. - * @return The public key as a Base64-encoded string. - * @throws Exception if retrieval fails. - */ - fun getPublicKey(alias: String): String { - try { - val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) } - - val certificate = keyStore.getCertificate(alias) ?: throw Exception("Certificate not found for alias \"$alias\".") - val publicKey: PublicKey = certificate.publicKey - - return Base64.encodeToString(publicKey.encoded, Base64.DEFAULT) - } catch (e: Exception) { - throw Exception("Failed to retrieve public key: ${e.message}", e) - } - } -} diff --git a/dialer/android/app/src/main/kotlin/com/icing/dialer/Signer.kt b/dialer/android/app/src/main/kotlin/com/icing/dialer/Signer.kt deleted file mode 100644 index e8fd34b..0000000 --- a/dialer/android/app/src/main/kotlin/com/icing/dialer/Signer.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.icing.dialer - -import android.security.keystore.KeyProperties -import java.security.KeyStore -import java.security.Signature -import android.util.Base64 -import java.security.PrivateKey - -object SignerHelper { - - private const val ANDROID_KEYSTORE = "AndroidKeyStore" - - /** - * Signs the provided data using the private key associated with the given alias. - * - * @param alias The alias of the key pair. - * @param data The data to sign. - * @return The signature as a Base64-encoded string. - * @throws Exception if signing fails. - */ - fun signData(alias: String, data: ByteArray): String { - try { - val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) } - - val privateKey = keyStore.getKey(alias, null) as? PrivateKey?: throw Exception("Private key not found for alias \"$alias\".") - - val signature = Signature.getInstance("SHA256withECDSA") - signature.initSign(privateKey) - signature.update(data) - val signedBytes = signature.sign() - - return Base64.encodeToString(signedBytes, Base64.DEFAULT) - } catch (e: Exception) { - throw Exception("Failed to sign data: ${e.message}", e) - } - } -} diff --git a/dialer/lib/domain/services/cryptography/asymmetric_crypto_service.dart b/dialer/lib/domain/services/cryptography/asymmetric_crypto_service.dart index 07c2964..d270288 100644 --- a/dialer/lib/domain/services/cryptography/asymmetric_crypto_service.dart +++ b/dialer/lib/domain/services/cryptography/asymmetric_crypto_service.dart @@ -10,7 +10,7 @@ class AsymmetricCryptoService { final String _aliasPrefix = 'icing_'; final Uuid _uuid = Uuid(); - /// Generates an ECDSA P-256 key pair with a unique alias and stores its metadata. + /// Generates an ED25519 key pair with a unique alias and stores its metadata. Future generateKeyPair({String? label}) async { try { // Generate a unique identifier for the key