Merge "Add more examples of generating/importing keys to Javadocs." into mnc-dev

This commit is contained in:
Alex Klyubin
2015-08-12 05:42:29 +00:00
committed by Android (Google) Code Review
2 changed files with 227 additions and 38 deletions

View File

@ -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,33 @@ 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");
@ -111,14 +125,67 @@ 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 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");
* keyStore.load(null);
* PrivateKey privateKey = (PrivateKey) keyStore.getKey("key1", null);
* PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey();
* }</pre>
*
* <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);

View File

@ -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 {