3

I'm developping an Android App that generates an EC Asymetric key. When my app gets connected to a device, they exchange their public key. They then use ECDH to establish a shared secret. This shared secret is then used to derive an AES session key. All this is working fine.

I'm now working on the storage of the asymetric key. I wanted to put it in the Android KeyStore but I don't see how I can then do the ECDH operation. The key in the key store can be used to sign, decrypt or encrypt but I don't see the possibility to do ECDH operation. Is it possible?

While browsing SO, I have seen this discussion which says that it is not possible. If that's the case, how can I "secure" my asymetric key?

Thanks

OlivierGrenoble
  • 3,803
  • 2
  • 18
  • 25
  • Hi in one of my application I want to perform seame steps as you but I am not able to find good cryptographic library or code for that I want to perform some steps till shared secreat. Do you have any code references for that ? – Gevaria Purva Jul 17 '20 at 06:42
  • @ Gevaria Purva: You can try Conscrypt of Bouncy Castle – OlivierGrenoble Jul 17 '20 at 10:16
  • Will it provide me certificate signing ? I tried a lot libraries but didint find good solution. – Gevaria Purva Jul 20 '20 at 09:39

2 Answers2

4

ECDH is not currently supported by AndroidKeyStore as you can see here https://developer.android.com/training/articles/keystore

The alternative to store securely the key pair into the device is to use an encryption key managed by AndroidKeyStore to encrypt the EC private key.

You can use a RSA or AES key depending on your target version. See how to securely store encryption keys in android?

pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • 1
    For most apps, this is not a secure alternative. The purpose of the keystore is to have a trusted execution environment and protect keys from possible jailbreaks. Use RSA if possible ... until Android supports ECDH properly. Hacking around it will result in key attacks. – Erik Aronesty Oct 23 '18 at 20:52
  • Erik, I've just seen your msg. I'm also having a concern that this might not be secured so I have asked a question here: https://stackoverflow.com/questions/54789464/protection-of-an-ecc-key-in-an-android-application – OlivierGrenoble Feb 20 '19 at 15:10
2

Since Android 9 (API level 28), the ECDH is supported in AndroidKeyStore. See this article and this example:

 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
         KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
 keyPairGenerator.initialize(
         new KeyGenParameterSpec.Builder(
             "eckeypair",
             KeyProperties.PURPOSE_AGREE_KEY)
             .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
             .build());
 KeyPair myKeyPair = keyPairGenerator.generateKeyPair();

 // Exchange public keys with server. A new ephemeral key MUST be used for every message.
 PublicKey serverEphemeralPublicKey; // Ephemeral key received from server.

 // Create a shared secret based on our private key and the other party's public key.
 KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "AndroidKeyStore");
 keyAgreement.init(myKeyPair.getPrivate());
 keyAgreement.doPhase(serverEphemeralPublicKey, true);
 byte[] sharedSecret = keyAgreement.generateSecret();

 // sharedSecret cannot safely be used as a key yet. We must run it through a key derivation
 // function with some other data: "salt" and "info". Salt is an optional random value,
 // omitted in this example. It's good practice to include both public keys and any other
 // key negotiation data in info. Here we use the public keys and a label that indicates
 // messages encrypted with this key are coming from the server.
 byte[] salt = {};
 ByteArrayOutputStream info = new ByteArrayOutputStream();
 info.write("ECDH secp256r1 AES-256-GCM-SIV\0".getBytes(StandardCharsets.UTF_8));
 info.write(myKeyPair.getPublic().getEncoded());
 info.write(serverEphemeralPublicKey.getEncoded());

 // This example uses the Tink library and the HKDF key derivation function.
 AesGcmSiv key = new AesGcmSiv(Hkdf.computeHkdf(
         "HMACSHA256", sharedSecret, salt, info.toByteArray(), 32));
 byte[] associatedData = {};
 return key.decrypt(ciphertext, associatedData);
Fethbita
  • 49
  • 1
  • 8