Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
ed07022916 |
@ -5,7 +5,7 @@
|
||||
An Epitech Innovation Project
|
||||
|
||||
*By*
|
||||
**Bartosz Michalak - Alexis Danlos - Florian Griffon - Stéphane Corbière**
|
||||
**Bartosz Michalak - Alexis Danlos - Florian Griffon - Ange Duhayon - Stéphane Corbière**
|
||||
|
||||
---
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String>("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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String> generateKeyPair({String? label}) async {
|
||||
try {
|
||||
// Generate a unique identifier for the key
|
||||
|
@ -3,7 +3,7 @@
|
||||
An Epitech Innovation Project
|
||||
|
||||
*By*
|
||||
**Bartosz Michalak - Alexis Danlos - Florian Griffon - Stéphane Corbière**
|
||||
**Bartosz Michalak - Alexis Danlos - Florian Griffon - Ange Duhayon - Stéphane Corbière**
|
||||
|
||||
---
|
||||
|
||||
@ -17,25 +17,13 @@ An Epitech Innovation Project
|
||||
|
||||
## Introduction to Icing
|
||||
|
||||
Icing is the name of our project, which is divided in **three interconnected goals**:
|
||||
1. Build a mutual-authentication and end-to-end encryption protocol, NAAP, for half and full-duplex audio communication, network agnostic. Network Agnostic Authentication Protocol.
|
||||
2. Provide a reference implementation in the form of an **Android Package**, that anybody can use to implement the protocol into their application.
|
||||
3. Provide a reference implementation in the form of an **Android Dialer**, that uses the android package, and that could seamlessly replace any Android user's default dialer.
|
||||
Icing is the name of our project, which is divided in **two interconnected goals**:
|
||||
1. Provide an end-to-end (E2E) encryption **code library**, based on Eliptic Curve Cryptography (ECC), to encrypt phone-calls on an **analog audio** level.
|
||||
2. Provide a reference implementation in the form of a totally seamless Android **smartphone dialer** application, that anybody could use without being aware of its encryption feature.
|
||||
|
||||
This idea came naturally to our minds, when we remarked the lack of such tool.
|
||||
|
||||
### Setting a new security standard
|
||||
|
||||
#### ***"There is no way to create a backdoor that only the good guys can walk through"***
|
||||
> (*Meredith Whittaker - President of Signal Fundation - July 2023, Channel 4*)
|
||||
|
||||
Enabling strong authentication on the phone network, either cellular or cable, would change the way we use our phone.
|
||||
|
||||
Reduced phone-related scams, simplified and safer banking or government services interactions, reduced dependency to the internet, and more, are the benefits both consumers and organizations would enjoy.
|
||||
|
||||
Encrypting the data end-to-end increases security globally by a considerable factor, particularly in low-bandwidth / no internet areas, and the added privacy would benefit everyone.
|
||||
|
||||
|
||||
---
|
||||
Where "private messaging" and other "encrypted communication" apps flourish, nowadays, they **all** require an internet access to work.
|
||||
|
||||
### Privacy and security in telecoms should not depend on internet availability.
|
||||
|
||||
@ -47,6 +35,21 @@ So in a real-world, stressful and harsh condition, affording privacy or security
|
||||
Our solution is for the every-man that is not even aware of its smart phone weakness, as well as for the activists or journalists surviving in hostile environment around the globe.
|
||||
|
||||
|
||||
### Setting a new security standard
|
||||
|
||||
#### ***"There is no way to create a backdoor that only the good guys can walk through"***
|
||||
> (*Meredith Whittaker - President of Signal Fundation - July 2023, Channel 4*)
|
||||
|
||||
If the police can listen to your calls with a mandate, hackers can, without mandate.
|
||||
|
||||
Many online platforms, such as online bank accounts, uses phone calls, or voicemails to drop security codes needed for authentication. The idea is to bring extra security, by requiring a second factor to authenticate the user, but most voicemails security features have been obsolete for a long time now.
|
||||
|
||||
**But this could change with globalized end-to-end encryption.**
|
||||
|
||||
This not only enables obfuscation of the transmitted audio data, but also hard peer authentication.
|
||||
This means that if you are in an important call, where you could communicate sensitive information such as passwords, or financial orders, using Icing protocol you and your peer would know that there is no man in the middle, listening and stealing information, and that your correspondent really is who it says.
|
||||
|
||||
---
|
||||
|
||||
### Icing's strategy
|
||||
|
||||
|
@ -2,6 +2,10 @@
|
||||
<a href="https://github.com/AlexisDanlos" target="_blank">Alexis DANLOS</a>
|
||||
{{end}}
|
||||
|
||||
{{define "ange"}}
|
||||
<a href="https://yw5n.com" target="_blank">Ange DUHAYON</a>
|
||||
{{end}}
|
||||
|
||||
{{define "bartosz"}}
|
||||
<a href="https://github.com/Bartoszkk" target="_blank">Bartosz MICHALAK</a>
|
||||
{{end}}
|
||||
|
Loading…
Reference in New Issue
Block a user