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);