diff options
-rw-r--r-- | keystore/java/android/security/keystore/KeyGenParameterSpec.java | 41 | ||||
-rw-r--r-- | keystore/java/android/security/keystore/KeyProperties.java | 9 |
2 files changed, 50 insertions, 0 deletions
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index e92eaca2b6e9..2b0d7e53b749 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -236,6 +236,47 @@ import javax.security.auth.x500.X500Principal; * keyStore.load(null); * key = (SecretKey) keyStore.getKey("key2", null); * }</pre> + * + * <p><h3 id="example:ecdh">Example: EC key for ECDH key agreement</h3> + * This example illustrates how to generate an elliptic curve key pair, used to establish a shared + * secret with another party using ECDH key agreement. + * <pre> {@code + * 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); + * } */ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs { diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java index 3ebca6ad302d..293ab05e0b10 100644 --- a/keystore/java/android/security/keystore/KeyProperties.java +++ b/keystore/java/android/security/keystore/KeyProperties.java @@ -100,6 +100,15 @@ public abstract class KeyProperties { /** * Purpose of key: creating a shared ECDH secret through key agreement. + * + * <p>A key having this purpose can be combined with the elliptic curve public key of another + * party to establish a shared secret over an insecure channel. It should be used as a + * parameter to {@link javax.crypto.KeyAgreement#init(java.security.Key)} (a complete example is + * available <a + * href="{@docRoot}reference/android/security/keystore/KeyGenParameterSpec#example:ecdh" + * >here</a>). + * See <a href="https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman">this + * article</a> for a more detailed explanation. */ public static final int PURPOSE_AGREE_KEY = 1 << 6; |