ECDH с ключом в Android Key Store

Я разрабатываю приложение для Android, которое генерирует асимметричный ключ EC. Когда мое приложение подключается к устройству, они обмениваются своим открытым ключом. Затем они используют ECDH для установления общего секрета. Этот общий секрет затем используется для получения сеансового ключа AES. Все это работает нормально.

Я сейчас работаю над хранением асимметричного ключа. Я хотел положить его в Android KeyStore, но я не вижу, как я могу тогда выполнить операцию ECDH. Ключ в хранилище ключей можно использовать для подписи, дешифрования или шифрования, но я не вижу возможности выполнить операцию ECDH. Является ли это возможным?

Просматривая SO, я видел это обсуждение, которое говорит, что это невозможно. Если это так, как я могу "защитить" свой асимметричный ключ?

Спасибо

2 ответа

Решение

ECDH в настоящее время не поддерживается AndroidKeyStore, как вы можете увидеть здесь https://developer.android.com/training/articles/keystore

Альтернативой для безопасного хранения пары ключей в устройстве является использование ключа шифрования, управляемого AndroidKeyStore, для шифрования закрытого ключа EC.

Вы можете использовать ключ RSA или AES в зависимости от вашей целевой версии. Посмотрите, как безопасно хранить ключи шифрования в Android?

Начиная с Android 9 (уровень API 28) ECDH поддерживается в AndroidKeyStore. См. эту статью и этот пример :

       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);
Другие вопросы по тегам