summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-05-07 17:34:24 -0700
committerAlex Klyubin <klyubin@google.com>2015-05-08 10:01:55 -0700
commiteedda45ad7d829b4d65936d33e8aa6fa9c9c1ecd (patch)
treec5f15c2aeb10bbb78817bcfc6f7255ca82649f00 /keystore
parent3974fb239392099608f969254c4d86e7d13ab32d (diff)
downloadframeworks_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
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/KeyGeneratorSpec.java66
-rw-r--r--keystore/java/android/security/KeyPairGeneratorSpec.java101
-rw-r--r--keystore/java/android/security/KeyStoreKeySpec.java39
-rw-r--r--keystore/java/android/security/KeyStoreParameter.java103
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 &#123;
+ * spec = (KeyStoreKeySpec) factory.getKeySpec(key, KeyStoreKeySpec.class);
+ * &#125; catch (InvalidKeySpecException e) &#123;
+ * // Not an Android KeyStore key.
+ * &#125;
+ * }</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 &#123;
+ * spec = factory.getKeySpec(key, KeyStoreKeySpec.class);
+ * &#125; catch (InvalidKeySpecException e) &#123;
+ * // Not an Android KeyStore key.
+ * &#125;
+ * }</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) {