diff options
author | Alex Klyubin <klyubin@google.com> | 2015-08-11 06:41:13 -0700 |
---|---|---|
committer | Alex Klyubin <klyubin@google.com> | 2015-08-11 11:36:09 -0700 |
commit | 72245d7909763dd1ed4cf4082aa1042e0ea61f4d (patch) | |
tree | e5c5d1eec29b46e3d603f5d0f986843cddb60d58 /keystore | |
parent | 4dbb37ae95bdf60d230777c6a5e8d53b932e9d40 (diff) | |
download | frameworks_base-72245d7909763dd1ed4cf4082aa1042e0ea61f4d.zip frameworks_base-72245d7909763dd1ed4cf4082aa1042e0ea61f4d.tar.gz frameworks_base-72245d7909763dd1ed4cf4082aa1042e0ea61f4d.tar.bz2 |
Add more examples of generating/importing keys to Javadocs.
Based on developer feedback, this updates Android Keystore Javadocs
with more examples of generating and importing keys of various
algorithms. This also clarifies that key use authorizations apply to
secret and private key and do no apply to public keys.
Bug: 23102874
Change-Id: If0dc20fda4836fd23b9cd9c92490a04e71b19fc0
Diffstat (limited to 'keystore')
-rw-r--r-- | keystore/java/android/security/keystore/KeyGenParameterSpec.java | 130 | ||||
-rw-r--r-- | keystore/java/android/security/keystore/KeyProtection.java | 135 |
2 files changed, 227 insertions, 38 deletions
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 7605231..f42d750 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -38,27 +38,35 @@ import javax.security.auth.x500.X500Principal; /** * {@link AlgorithmParameterSpec} for initializing a {@link KeyPairGenerator} or a * {@link KeyGenerator} of the <a href="{@docRoot}training/articles/keystore.html">Android Keystore - * system</a>. The spec determines whether user authentication is required for using the key, what - * uses the key is authorized for (e.g., only for signing -- decryption not permitted), the key's - * validity start and end dates. + * system</a>. The spec determines authorized uses of the key, such as whether user authentication + * is required for using the key, what operations are authorized (e.g., signing, but not + * decryption) and with what parameters (e.g., only with a particular padding scheme or digest), the + * key's validity start and end dates. Key use authorizations expressed in the spec apply only to + * secret keys and private keys -- public keys can be used for any supported operations. * * <p>To generate an asymmetric key pair or a symmetric key, create an instance of this class using * the {@link Builder}, initialize a {@code KeyPairGenerator} or a {@code KeyGenerator} of the * desired key type (e.g., {@code EC} or {@code AES} -- see * {@link KeyProperties}.{@code KEY_ALGORITHM} constants) from the {@code AndroidKeyStore} provider - * with the {@code KeyPairGeneratorSpec} instance, and then generate a key or key pair using - * {@link KeyPairGenerator#generateKeyPair()}. + * with the {@code KeyGenParameterSpec} instance, and then generate a key or key pair using + * {@link KeyGenerator#generateKey()} or {@link KeyPairGenerator#generateKeyPair()}. * * <p>The generated key pair or key will be returned by the generator and also stored in the Android - * Keystore system under the alias specified in this spec. To obtain the secret or private key from - * the Android KeyStore use {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} + * Keystore under the alias specified in this spec. To obtain the secret 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 system use + * To obtain the public key from the Android Keystore use * {@link java.security.KeyStore#getCertificate(String)} and then * {@link Certificate#getPublicKey()}. * + * <p>To help obtain algorithm-specific public parameters of key pairs stored in the Android + * Keystore, generated private keys implement {@link java.security.interfaces.ECKey} or + * {@link java.security.interfaces.RSAKey} interfaces whereas public keys implement + * {@link java.security.interfaces.ECPublicKey} or {@link java.security.interfaces.RSAPublicKey} + * interfaces. + * * <p>For asymmetric key pairs, 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 + * 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 customized in this spec. The self-signed certificate may be replaced at * a later time by a certificate signed by a Certificate Authority (CA). @@ -82,27 +90,60 @@ import javax.security.auth.x500.X500Principal; * * <p>Instances of this class are immutable. * - * <p><h3>Example: Asymmetric key pair</h3> - * The following example illustrates how to generate an EC key pair in the Android KeyStore system - * under alias {@code key1} 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. + * <p><h3>Example: NIST P-256 EC key pair for signing/verification using ECDSA</h3> + * This example illustrates how to generate a NIST P-256 (aka secp256r1 aka prime256v1) EC key pair + * in the Android KeyStore system under alias {@code key1} where the private key is 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. The use of public key is unrestricted, thus + * permitting signature verification using any padding schemes and digests, and without user + * authentication. * <pre> {@code * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( - * KeyProperties.KEY_ALGORITHM_EC, - * "AndroidKeyStore"); + * KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); * keyPairGenerator.initialize( * new KeyGenParameterSpec.Builder( * "key1", - * KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) + * KeyProperties.PURPOSE_SIGN) + * .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) * .setDigests(KeyProperties.DIGEST_SHA256, * KeyProperties.DIGEST_SHA384, * KeyProperties.DIGEST_SHA512) - * // Only permit this key to be used if the user authenticated + * // Only permit the private key to be used if the user authenticated * // within the last five minutes. * .setUserAuthenticationRequired(true) * .setUserAuthenticationValidityDurationSeconds(5 * 60) * .build()); * KeyPair keyPair = keyPairGenerator.generateKeyPair(); + * Signature signature = Signature.getInstance("SHA256withECDSA"); + * signature.initSign(keyPair.getPrivate()); + * ... + * + * // 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("key1", null); + * PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey(); + * }</pre> + * + * <p><h3>Example: RSA key pair for signing/verification using RSA-PSS</h3> + * This example illustrates how to generate an RSA key pair in the Android KeyStore system under + * alias {@code key1} authorized to be used only for signing using the RSA-PSS signature padding + * scheme with SHA-256 or SHA-512 digests. The use of public key is unrestricted, thus permitting + * signature verification using any padding schemes and digests. + * <pre> {@code + * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( + * KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); + * keyPairGenerator.initialize( + * new KeyGenParameterSpec.Builder( + * "key1", + * KeyProperties.PURPOSE_SIGN) + * .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) + * .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS) + * .build()); + * KeyPair keyPair = keyPairGenerator.generateKeyPair(); + * Signature signature = Signature.getInstance("SHA256withRSA/PSS"); + * signature.initSign(keyPair.getPrivate()); + * ... * * // The key pair can also be obtained from the Android Keystore any time as follows: * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); @@ -111,14 +152,40 @@ import javax.security.auth.x500.X500Principal; * PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey(); * }</pre> * - * <p><h3>Example: Symmetric key</h3> + * <p><h3>Example: RSA key pair for encryption/decryption using RSA OAEP</h3> + * This example illustrates how to generate an RSA key pair in the Android KeyStore system under + * alias {@code key1} where the private key is authorized to be used only for decryption using RSA + * OAEP encryption padding scheme with SHA-256 or SHA-512 digests. The use of public key is + * unrestricted, thus permitting encryption using any padding schemes and digests. + * <pre> {@code + * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( + * KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); + * keyPairGenerator.initialize( + * new KeyGenParameterSpec.Builder( + * "key1", + * KeyProperties.PURPOSE_DECRYPT) + * .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) + * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP) + * .build()); + * KeyPair keyPair = keyPairGenerator.generateKeyPair(); + * Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); + * cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + * ... + * + * // 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("key1", null); + * PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey(); + * }</pre> + * + * <p><h3>Example: AES key for encryption/decryption in GCM mode</h3> * The following example illustrates how to generate an AES key in the Android KeyStore system under * alias {@code key2} authorized to be used only for encryption/decryption in GCM mode with no * padding. * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( - * KeyProperties.KEY_ALGORITHM_AES, - * "AndroidKeyStore"); + * KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); * keyGenerator.initialize( * new KeyGenParameterSpec.Builder("key2", * KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) @@ -127,6 +194,29 @@ import javax.security.auth.x500.X500Principal; * .build()); * SecretKey key = keyGenerator.generateKey(); * + * Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + * cipher.init(Cipher.ENCRYPT_MODE, key); + * ... + * + * // The key can also be obtained from the Android Keystore any time as follows: + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * key = (SecretKey) keyStore.getKey("key2", null); + * }</pre> + * + * <p><h3>Example: HMAC key for generating a MAC using SHA-256</h3> + * This example illustrates how to generate an HMAC key in the Android KeyStore system under alias + * {@code key2} authorized to be used only for generating an HMAC using SHA-256. + * <pre> {@code + * KeyGenerator keyGenerator = KeyGenerator.getInstance( + * KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore"); + * keyGenerator.initialize( + * new KeyGenParameterSpec.Builder("key2", KeyProperties.PURPOSE_SIGN).build()); + * SecretKey key = keyGenerator.generateKey(); + * Mac mac = Mac.getInstance("HmacSHA256"); + * mac.init(key); + * ... + * * // The key can also be obtained from the Android Keystore any time as follows: * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); * keyStore.load(null); diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index b71dc82..c984439 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -33,28 +33,36 @@ import javax.crypto.Mac; /** * Specification of how a key or key pair is secured when imported into the - * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class - * specifies parameters such as whether user authentication is required for using the key, what uses - * the key is authorized for (e.g., only in {@code GCM} mode, or only for signing -- decryption not - * permitted), the key's and validity start and end dates. + * <a href="{@docRoot}training/articles/keystore.html">Android Keystore system</a>. This class + * specifies authorized uses of the imported key, such as whether user authentication is required + * for using the key, what operations the key is authorized for (e.g., decryption, but not signing) + * and with what parameters (e.g., only with a particular padding scheme or digest), the key's and + * validity start and end dates. Key use authorizations expressed in this class apply only to secret + * keys and private keys -- public keys can be used for any supported operations. * - * <p>To import a key or key pair into the Android KeyStore, create an instance of this class using + * <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 + * <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 + * 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>To help obtain algorithm-specific public parameters of key pairs stored in the Android + * Keystore, its private keys implement {@link java.security.interfaces.ECKey} or + * {@link java.security.interfaces.RSAKey} interfaces whereas its public keys implement + * {@link java.security.interfaces.ECPublicKey} or {@link java.security.interfaces.RSAPublicKey} + * interfaces. + * + * <p>NOTE: The key material of keys stored in the Android Keystore is not accessible. * * <p>Instances of this class are immutable. * - * <p><h3>Example: Symmetric Key</h3> - * The following example illustrates how to import an AES key into the Android KeyStore under alias + * <p><h3>Example: AES key for encryption/decryption in GCM mode</h3> + * This 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 GCM mode with no padding. * The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format. * <pre> {@code @@ -71,15 +79,41 @@ import javax.crypto.Mac; * .build()); * // Key imported, obtain a reference to it. * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null); - * // The original key can now be thrown away. + * // The original key can now be discarded. + * + * Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + * cipher.init(Cipher.ENCRYPT_MODE, keyStoreKey); + * ... * }</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. + * <p><h3>Example: HMAC key for generating MACs using SHA-512</h3> + * This example illustrates how to import an HMAC key into the Android KeyStore under alias + * {@code key1} authorized to be used only for generating MACs using SHA-512 digest. The key must + * export its key material via {@link Key#getEncoded()} in {@code RAW} format. + * <pre> {@code + * SecretKey key = ...; // HMAC key of algorithm "HmacSHA512". + * + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * keyStore.setEntry( + * "key1", + * new KeyStore.SecretKeyEntry(key), + * new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN).build()); + * // Key imported, obtain a reference to it. + * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null); + * // The original key can now be discarded. + * + * Mac mac = Mac.getInstance("HmacSHA512"); + * mac.init(keyStoreKey); + * ... + * }</pre> + * + * <p><h3>Example: EC key pair for signing/verification using ECDSA</h3> + * This example illustrates how to import an EC key pair into the Android KeyStore under alias + * {@code key2} with the private key authorized to be used only for signing with SHA-256 or SHA-512 + * digests. The use of public key is unrestricted, thus permitting signature verification using any + * digests. 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 @@ -91,7 +125,39 @@ import javax.crypto.Mac; * "key2", * new KeyStore.PrivateKeyEntry(privateKey, certChain), * new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN) + * .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) + * .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 discarded. + * + * Signature signature = Signature.getInstance("SHA256withECDSA"); + * signature.initSign(keyStorePrivateKey); + * ... + * }</pre> + * + * <p><h3>Example: RSA key pair for signing/verification using PKCS#1 padding</h3> + * This example illustrates how to import an RSA key pair into the Android KeyStore under alias + * {@code key2} with the private key authorized to be used only for signing using the PKCS#1 + * signature padding scheme with SHA-256 digest and only if the user has been authenticated within + * the last ten minutes. The use of public key is unrestricted, thus permitting signature + * verification using any padding schemes and digests, and without user authentication. 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 = ...; // RSA private key + * Certificate[] certChain = ...; // Certificate chain with the first certificate + * // containing the corresponding RSA public key. + * + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * keyStore.setEntry( + * "key2", + * new KeyStore.PrivateKeyEntry(privateKey, certChain), + * new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN) * .setDigests(KeyProperties.DIGEST_SHA256) + * .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) * // Only permit this key to be used if the user * // authenticated within the last ten minutes. * .setUserAuthenticationRequired(true) @@ -100,7 +166,40 @@ import javax.crypto.Mac; * // 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. + * // The original private key can now be discarded. + * + * Signature signature = Signature.getInstance("SHA256withRSA"); + * signature.initSign(keyStorePrivateKey); + * ... + * }</pre> + * + * <p><h3>Example: RSA key pair for encryption/decryption using PKCS#1 padding</h3> + * This example illustrates how to import an RSA key pair into the Android KeyStore under alias + * {@code key2} with the private key authorized to be used only for decryption using the PKCS#1 + * encryption padding scheme. The use of public key is unrestricted, thus permitting encryption + * using any padding schemes and digests. 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 = ...; // RSA private key + * Certificate[] certChain = ...; // Certificate chain with the first certificate + * // containing the corresponding RSA public key. + * + * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + * keyStore.load(null); + * keyStore.setEntry( + * "key2", + * new KeyStore.PrivateKeyEntry(privateKey, certChain), + * new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) + * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) + * .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 discarded. + * + * Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + * cipher.init(Cipher.DECRYPT_MODE, keyStorePrivateKey); + * ... * }</pre> */ public final class KeyProtection implements ProtectionParameter { |