diff options
author | Alex Klyubin <klyubin@google.com> | 2015-05-07 17:34:24 -0700 |
---|---|---|
committer | Alex Klyubin <klyubin@google.com> | 2015-05-08 10:01:55 -0700 |
commit | eedda45ad7d829b4d65936d33e8aa6fa9c9c1ecd (patch) | |
tree | c5f15c2aeb10bbb78817bcfc6f7255ca82649f00 | |
parent | 3974fb239392099608f969254c4d86e7d13ab32d (diff) | |
download | frameworks_base-eedda45ad7d829b4d65936d33e8aa6fa9c9c1ecd.zip frameworks_base-eedda45ad7d829b4d65936d33e8aa6fa9c9c1ecd.tar.gz frameworks_base-eedda45ad7d829b4d65936d33e8aa6fa9c9c1ecd.tar.bz2 |
More Javadocs for AndroidKeyStore public classes.
This adds more detailed class-level Javadocs (incl. examples) for the
following public API of Android KeyStore facility:
* KeyPairGeneratorSpec,
* KeyGeneratorSpec,
* KeyStoreParameter,
* KeyStoreKeySpec.
This also clarifies what encryption at rest means.
Bug: 18088752
Change-Id: I9951a528c34dea322534763b596902a2b6ac64f9
-rw-r--r-- | keystore/java/android/security/KeyGeneratorSpec.java | 66 | ||||
-rw-r--r-- | keystore/java/android/security/KeyPairGeneratorSpec.java | 101 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreKeySpec.java | 39 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreParameter.java | 103 |
4 files changed, 251 insertions, 58 deletions
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java index 729646d..5a10a0a 100644 --- a/keystore/java/android/security/KeyGeneratorSpec.java +++ b/keystore/java/android/security/KeyGeneratorSpec.java @@ -16,6 +16,7 @@ package android.security; +import android.app.KeyguardManager; import android.content.Context; import android.text.TextUtils; @@ -24,19 +25,53 @@ import java.util.Date; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; /** - * {@link AlgorithmParameterSpec} for initializing a {@code KeyGenerator} that works with - * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. + * {@link AlgorithmParameterSpec} for initializing a {@link KeyGenerator} of the + * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class + * specifies whether user authentication is required for using the key, what uses the key is + * authorized for (e.g., only in {@code CBC} mode), whether the key should be encrypted at rest, the + * key's and validity start and end dates. * - * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API using the - * {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up some UI to - * ask the user to unlock or initialize the Android KeyStore facility. + * <p>To generate a key, create an instance of this class using the {@link Builder}, initialize a + * {@code KeyGenerator} of the desired key type (e.g., {@code AES} or {@code HmacSHA256}) from the + * {@code AndroidKeyStore} provider with the {@code KeyGeneratorSpec} instance, and then generate a + * key using {@link KeyGenerator#generateKey()}. * - * <p>After generation, the {@code keyStoreAlias} is used with the - * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)} - * interface to retrieve the {@link SecretKey}. + * <p>The generated key will be returned by the {@code KeyGenerator} and also stored in the Android + * KeyStore under the alias specified in this {@code KeyGeneratorSpec}. To obtain the key from the + * Android KeyStore use + * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or + * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}. + * + * <p>NOTE: The key material of the keys generating using the {@code KeyGeneratorSpec} is not + * accessible. + * + * <p><h3>Example</h3> + * The following example illustrates how to generate an HMAC key in the Android KeyStore under alias + * {@code key1} authorized to be used only for HMAC with SHA-256 digest and only if the user has + * been authenticated within the last five minutes. + * <pre> {@code + * KeyGenerator keyGenerator = KeyGenerator.getInstance( + * KeyStoreKeyProperties.Algorithm.HMAC_SHA256, + * "AndroidKeyStore"); + * keyGenerator.initialize( + * new KeyGeneratorSpec.Builder(context) + * .setAlias("key1") + * .setPurposes(KeyStoreKeyProperties.Purpose.SIGN + * | KeyStoreKeyProperties.Purpose.VERIFY) + * // Only permit this key to be used if the user authenticated + * // within the last five minutes. + * .setUserAuthenticationRequired(true) + * .setUserAuthenticationValidityDurationSeconds(5 * 60) + * .build()); + * SecretKey key = keyGenerator.generateKey(); + * + * // The key can also be obtained from the Android KeyStore any time as follows: + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * SecretKey key = (SecretKey) keyStore.getKey("key1", null); + * }</pre> */ public class KeyGeneratorSpec implements AlgorithmParameterSpec { @@ -207,7 +242,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** - * Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}. + * Returns {@code true} if the key must be encrypted at rest. This will protect the key with the + * secure lock screen credential (e.g., password, PIN, or pattern). */ public boolean isEncryptionRequired() { return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; @@ -266,9 +302,13 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** - * Indicates that this key must be encrypted at rest on storage. Note that enabling this - * will require that the user enable a strong lock screen (e.g., PIN, password) before - * creating or using the generated key is successful. + * Indicates that this key must be encrypted at rest. This will protect the key with the + * secure lock screen credential (e.g., password, PIN, or pattern). + * + * <p>Note that this feature requires that the secure lock screen (e.g., password, PIN, + * pattern) is set up. Otherwise key generation will fail. + * + * @see KeyguardManager#isDeviceSecure() */ public Builder setEncryptionRequired(boolean required) { if (required) { diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index 25c61fd..1fcb355 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -16,10 +16,12 @@ package android.security; +import android.app.KeyguardManager; import android.content.Context; import android.text.TextUtils; import java.math.BigInteger; +import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; @@ -29,26 +31,64 @@ import java.util.Date; import javax.security.auth.x500.X500Principal; /** - * This provides the required parameters needed for initializing the - * {@code KeyPairGenerator} that works with - * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore - * facility</a>. The Android KeyStore facility is accessed through a - * {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore} - * provider. The {@code context} passed in may be used to pop up some UI to ask - * the user to unlock or initialize the Android KeyStore facility. - * <p> - * After generation, the {@code keyStoreAlias} is used with the - * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)} - * interface to retrieve the {@link PrivateKey} and its associated - * {@link Certificate} chain. - * <p> - * The KeyPair generator will create a self-signed certificate with the subject - * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer - * Distinguished Name along with the other parameters specified with the - * {@link Builder}. - * <p> - * The self-signed X.509 certificate may be replaced at a later time by a - * certificate signed by a real Certificate Authority. + * {@link AlgorithmParameterSpec} for initializing a {@link KeyPairGenerator} of the + * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class + * specifies whether user authentication is required for using the private key, what uses the + * private key is authorized for (e.g., only for signing -- decryption not permitted), whether the + * private key should be encrypted at rest, the private key's and validity start and end dates. + * + * <p>To generate a key pair, create an instance of this class using the {@link Builder}, initialize + * a {@code KeyPairGenerator} of the desired key type (e.g., {@code EC} or {@code RSA}) from the + * {@code AndroidKeyStore} provider with the {@code KeyPairGeneratorSpec} instance, and then + * generate a key pair using {@link KeyPairGenerator#generateKeyPair()}. + * + * <p>The generated key pair will be returned by the {@code KeyPairGenerator} and also stored in the + * Android KeyStore under the alias specified in this {@code KeyPairGeneratorSpec}. To obtain the + * private key from the Android KeyStore use + * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or + * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}. + * To obtain the public key from the Android KeyStore use + * {@link java.security.KeyStore#getCertificate(String)} and then + * {@link Certificate#getPublicKey()}. + * + * <p>A self-signed X.509 certificate will be also generated and stored in the Android KeyStore. + * This is because the {@link java.security.KeyStore} abstraction does not support storing key pairs + * without a certificate. The subject, serial number, and validity dates of the certificate can be + * specified in this {@code KeyPairGeneratorSpec}. The self-signed certificate may be replaced at a + * later time by a certificate signed by a Certificate Authority (CA). + * + * <p>NOTE: The key material of the private keys generating using the {@code KeyPairGeneratorSpec} + * is not accessible. The key material of the public keys is accessible. + * + * <p><h3>Example</h3> + * The following example illustrates how to generate an EC key pair in the Android KeyStore under + * alias {@code key2} authorized to be used only for signing using SHA-256, SHA-384, or SHA-512 + * digest and only if the user has been authenticated within the last five minutes. + * <pre> {@code + * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( + * KeyStoreKeyProperties.Algorithm.EC, + * "AndroidKeyStore"); + * keyPairGenerator.initialize( + * new KeyGeneratorSpec.Builder(context) + * .setAlias("key2") + * .setPurposes(KeyStoreKeyProperties.Purpose.SIGN + * | KeyStoreKeyProperties.Purpose.VERIFY) + * .setDigests(KeyStoreKeyProperties.Digest.SHA256 + * | KeyStoreKeyProperties.Digest.SHA384 + * | KeyStoreKeyProperties.Digest.SHA512) + * // Only permit this key to be used if the user authenticated + * // within the last five minutes. + * .setUserAuthenticationRequired(true) + * .setUserAuthenticationValidityDurationSeconds(5 * 60) + * .build()); + * KeyPair keyPair = keyPairGenerator.generateKey(); + * + * // The key pair can also be obtained from the Android KeyStore any time as follows: + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * PrivateKey privateKey = (PrivateKey) keyStore.getKey("key2", null); + * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey(); + * }</pre> */ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { @@ -307,8 +347,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Returns {@code true} if this parameter will require generated keys to be - * encrypted in the {@link java.security.KeyStore}. + * Returns {@code true} if the key must be encrypted at rest. This will protect the key pair + * with the secure lock screen credential (e.g., password, PIN, or pattern). */ public boolean isEncryptionRequired() { return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; @@ -614,10 +654,13 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Indicates that this key must be encrypted at rest on storage. Note - * that enabling this will require that the user enable a strong lock - * screen (e.g., PIN, password) before creating or using the generated - * key is successful. + * Indicates that this key must be encrypted at rest. This will protect the key pair with + * the secure lock screen credential (e.g., password, PIN, or pattern). + * + * <p>Note that this feature requires that the secure lock screen (e.g., password, PIN, + * pattern) is set up. Otherwise key pair generation will fail. + * + * @see KeyguardManager#isDeviceSecure() */ public Builder setEncryptionRequired() { mFlags |= KeyStore.FLAG_ENCRYPTED; @@ -689,6 +732,12 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * <p>This must be specified for all keys. There is no default. * + * <p>If the set of purposes for which the key can be used does not contain + * {@link KeyStoreKeyProperties.Purpose#SIGN}, the self-signed certificate generated by + * {@link KeyPairGenerator} of {@code AndroidKeyStore} provider will contain an invalid + * signature. This is OK if the certificate is only used for obtaining the public key from + * Android KeyStore. + * * <p><b>NOTE: This has currently no effect. */ public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java index a630a0a..0a9acbb 100644 --- a/keystore/java/android/security/KeyStoreKeySpec.java +++ b/keystore/java/android/security/KeyStoreKeySpec.java @@ -16,12 +16,49 @@ package android.security; +import java.security.PrivateKey; import java.security.spec.KeySpec; import java.util.Date; +import javax.crypto.SecretKey; + /** * Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android - * KeyStore</a>. + * KeyStore</a>. This class describes whether the key material is available in + * plaintext outside of secure hardware, whether user authentication is required for using the key + * and whether this requirement is enforced by secure hardware, the key's origin, what uses the key + * is authorized for (e.g., only in {@code CBC} mode, or signing only), whether the key should be + * encrypted at rest, the key's and validity start and end dates. + * + * <p><h3>Example: Symmetric Key</h3> + * The following example illustrates how to obtain a {@link KeyStoreKeySpec} describing the provided + * Android KeyStore {@link SecretKey}. + * <pre> {@code + * SecretKey key = ...; // Android KeyStore key + * + * SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore"); + * KeyStoreKeySpec spec; + * try { + * spec = (KeyStoreKeySpec) factory.getKeySpec(key, KeyStoreKeySpec.class); + * } catch (InvalidKeySpecException e) { + * // Not an Android KeyStore key. + * } + * }</pre> + * + * <p><h3>Example: Private Key</h3> + * The following example illustrates how to obtain a {@link KeyStoreKeySpec} describing the provided + * Android KeyStore {@link PrivateKey}. + * <pre> {@code + * PrivateKey key = ...; // Android KeyStore key + * + * KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore"); + * KeyStoreKeySpec spec; + * try { + * spec = factory.getKeySpec(key, KeyStoreKeySpec.class); + * } catch (InvalidKeySpecException e) { + * // Not an Android KeyStore key. + * } + * }</pre> */ public class KeyStoreKeySpec implements KeySpec { private final String mKeystoreAlias; diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java index 8d7a19f..ea5ca71 100644 --- a/keystore/java/android/security/KeyStoreParameter.java +++ b/keystore/java/android/security/KeyStoreParameter.java @@ -16,27 +16,89 @@ package android.security; +import android.app.KeyguardManager; import android.content.Context; import java.security.Key; import java.security.KeyStore.ProtectionParameter; +import java.security.cert.Certificate; import java.util.Date; import javax.crypto.Cipher; /** - * Parameters specifying how to secure and restrict the use of a key being - * imported into the - * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore - * facility</a>. The Android KeyStore facility is accessed through a - * {@link java.security.KeyStore} API using the {@code AndroidKeyStore} - * provider. The {@code context} passed in may be used to pop up some UI to ask - * the user to unlock or initialize the Android KeyStore facility. - * <p> - * Any entries placed in the {@code KeyStore} may be retrieved later. Note that - * there is only one logical instance of the {@code KeyStore} per application - * UID so apps using the {@code sharedUid} facility will also share a - * {@code KeyStore}. + * Parameters specifying how to secure and restrict the use of a key or key pair being imported into + * the <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class + * specifies whether user authentication is required for using the key, what uses the key is + * authorized for (e.g., only in {@code CTR} mode, or only for signing -- decryption not permitted), + * whether the key should be encrypted at rest, the key's and validity start and end dates. + * + * <p>To import a key or key pair into the Android KeyStore, create an instance of this class using + * the {@link Builder} and pass the instance into {@link java.security.KeyStore#setEntry(String, java.security.KeyStore.Entry, ProtectionParameter) KeyStore.setEntry} + * with the key or key pair being imported. + * + * <p>To obtain the secret/symmetric or private key from the Android KeyStore use + * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or + * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}. + * To obtain the public key from the Android KeyStore use + * {@link java.security.KeyStore#getCertificate(String)} and then + * {@link Certificate#getPublicKey()}. + * + * <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible. + * + * <p><h3>Example: Symmetric Key</h3> + * The following example illustrates how to import an AES key into the Android KeyStore under alias + * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 + * padding. The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format. + * <pre> {@code + * SecretKey key = ...; // AES key + * + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * keyStore.setEntry( + * "key1", + * new KeyStore.SecretKeyEntry(key), + * new KeyStoreParameter.Builder(context) + * .setPurposes(KeyStoreKeyProperties.Purpose.ENCRYPT + * | KeyStoreKeyProperties.Purpose.DECRYPT) + * .setBlockMode(KeyStoreKeyProperties.BlockMode.CBC) + * .setEncryptionPaddings( + * KeyStoreKeyProperties.EncryptionPaddings.PKCS7) + * .build()); + * // Key imported, obtain a reference to it. + * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null); + * // The original key can now be thrown away. + * }</pre> + * + * <p><h3>Example: Asymmetric Key Pair</h3> + * The following example illustrates how to import an EC key pair into the Android KeyStore under + * alias {@code key2} authorized to be used only for signing with SHA-256 digest and only if + * the user has been authenticated within the last ten minutes. Both the private and the public key + * must export their key material via {@link Key#getEncoded()} in {@code PKCS#8} and {@code X.509} + * format respectively. + * <pre> {@code + * PrivateKey privateKey = ...; // EC private key + * Certificate[] certChain = ...; // Certificate chain with the first certificate + * // containing the corresponding EC public key. + * + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * keyStore.setEntry( + * "key2", + * new KeyStore.PrivateKeyEntry(privateKey, certChain), + * new KeyStoreParameter.Builder(context) + * .setPurposes(KeyStoreKeyProperties.Purpose.SIGN) + * .setDigests(KeyStoreKeyProperties.Digest.SHA256) + * // Only permit this key to be used if the user + * // authenticated within the last ten minutes. + * .setUserAuthenticationRequired(true) + * .setUserAuthenticationValidityDurationSeconds(10 * 60) + * .build()); + * // Key pair imported, obtain a reference to it. + * PrivateKey keyStorePrivateKey = (PrivateKey) keyStore.getKey("key2", null); + * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey(); + * // The original private key can now be thrown away. + * }</pre> */ public final class KeyStoreParameter implements ProtectionParameter { private final Context mContext; @@ -107,8 +169,9 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** - * Returns {@code true} if this parameter requires entries to be encrypted - * on the disk. + * Returns {@code true} if the {@link java.security.KeyStore} entry must be encrypted at rest. + * This will protect the entry with the secure lock screen credential (e.g., password, PIN, or + * pattern). */ public boolean isEncryptionRequired() { return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; @@ -275,10 +338,14 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** - * Indicates that this key must be encrypted at rest on storage. Note - * that enabling this will require that the user enable a strong lock - * screen (e.g., PIN, password) before creating or using the generated - * key is successful. + * Indicates that this {@link java.security.KeyStore} entry must be encrypted at rest. This + * will protect the entry with the secure lock screen credential (e.g., password, PIN, or + * pattern). + * + * <p>Note that enabling this feature requires that the secure lock screen (e.g., password, + * PIN, pattern) is set up. Otherwise setting the {@code KeyStore} entry will fail. + * + * @see KeyguardManager#isDeviceSecure() */ public Builder setEncryptionRequired(boolean required) { if (required) { |