| page.title=Android Keystore System |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#SecurityFeatures">Security Features</a></li> |
| <li><a href="#WhichShouldIUse">Choosing Between a Keychain or the Android Keystore Provider</a></li> |
| <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider</a> |
| <ol> |
| <li><a href="#GeneratingANewPrivateKey">Generating a New Private Key</a></li> |
| <li><a href="#WorkingWithKeyStoreEntries">Working with Keystore Entries</a></li> |
| <li><a href="#ListingEntries">Listing Entries</a></li> |
| <li><a href="#SigningAndVerifyingData">Signing and Verifying Data</a></li> |
| </ol> |
| </li> |
| <li><a href="#SupportedAlgorithms">Supported Algorithms</a></li> |
| </ol> |
| |
| <h2>Blog articles</h2> |
| <ol> |
| <li><a |
| href="http://android-developers.blogspot.com/2012/03/unifying-key-store-access-in-ics.html"> |
| <h4>Unifying Key Store Access in ICS</h4> |
| </a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <style type="text/css"> |
| tr.deprecated { |
| background-color: #ccc; |
| color: #999; |
| font-style: italic; |
| } |
| </style> |
| |
| <p>The Android Keystore system lets you store cryptographic keys in a container |
| to make it more difficult to extract from the device. Once keys are in the |
| keystore, they can be used for cryptographic operations with the key material |
| remaining non-exportable. Moreover, it offers facilities to restrict when and |
| how keys can be used, such as requiring user authentication for key use or |
| restricting keys to be used only in certain cryptographic modes. See |
| <a href="#SecurityFeatures">Security Features</a> section for more information.</p> |
| |
| <p>The Keystore system is used by the {@link |
| android.security.KeyChain} API as well as the Android |
| Keystore provider feature that was introduced in Android 4.3 |
| (API level 18). This document goes over when and how to use the |
| Android Keystore provider.</p> |
| |
| |
| <h2 id="SecurityFeatures">Security Features</h2> |
| |
| Android Keystore system protects key material from unauthorized use. Firstly, Android Keystore |
| mitigates unauthorized use of key material outside of the Android device by preventing extraction of |
| the key material from application processes and from the Android device as a whole. Secondly, |
| Android KeyStore mitigates unauthorized use of key material on the Android device by making apps |
| specify authorized uses of their keys and then enforcing these restrictions outside of the apps' |
| processes. |
| |
| <h3 id="ExtractionPrevention">Extraction Prevention</h3> |
| |
| Key material of Android Keystore keys is protected from extraction using two security measures: |
| <ul> |
| <li>Key material never enters the application process. When an application performs cryptographic |
| operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to |
| be signed or verified are fed to a system process which carries out the cryptographic operations. |
| If the app's process is compromised, the attacker may be able to use the app's keys but will not |
| be able to extract their key material (for example, to be used outside of the Android device). |
| </li> |
| <li>Key material may be bound to the secure hardware (e.g., Trusted Execution Environment (TEE), |
| Secure Element (SE)) of the Android device. When this feature is enabled for a key, its key |
| material is never exposed outside of secure hardware. If the Android OS is compromised or an |
| attacker can read the device's internal storage, the attacker may be able to use any app's Android |
| Keystore keys on the Android device, but not extract them from the device. This feature is enabled |
| only if the device's secure hardware supports the particular combination of key algorithm, block |
| modes, padding schemes, and digests with which the key is authorized to be used. To check whether |
| the feature is enabled for a key, obtain a {@link android.security.keystore.KeyInfo} for the key |
| and inspect the return value of |
| {@link android.security.keystore.KeyInfo#isInsideSecureHardware() KeyInfo.isInsideSecurityHardware()}. |
| </li> |
| </ul> |
| |
| <h3 id="KeyUseAuthorizations">Key Use Authorizations</h3> |
| |
| To mitigate unauthorized use of keys on the Android device, Android Keystore lets apps specify |
| authorized uses of their keys when generating or importing the keys. Once a key is generated or |
| imported, its authorizations can not be changed. Authorizations are then enforced by the Android |
| Keystore whenever the key is used. This is an advanced security feature which is generally useful |
| only if your requirements are that a compromise of your application process after key |
| generation/import (but not before or during) cannot lead to unauthorized uses of the key. |
| |
| <p>Supported key use authorizations fall into the following categories: |
| <ul> |
| <li><em>cryptography</em>: authorized key algorithm, operations or purposes (encrypt, decrypt, sign, |
| verify), padding schemes, block modes, digests with which the key can be used;</li> |
| <li><em>temporal validity interval</em>: interval of time during which the key is authorized for |
| use;</li> |
| <li><em>user authentication</em>: the key can only be used if the user has been authenticated |
| recently enough. See <a href="#UserAuthentication">Requiring User Authentication For Key Use</a>. |
| </li> |
| </ul> |
| |
| <p>As an additional security measure, for keys whose key material is inside secure hardware (see |
| {@link android.security.keystore.KeyInfo#isInsideSecureHardware() KeyInfo.isInsideSecurityHardware()}) |
| some key use authorizations may be enforced by secure hardware, depending on the Android device. |
| Cryptographic and user authentication authorizations are likely to be enforced by secure hardware. |
| Temporal validity interval authorizations are unlikely to be enforced by the secure hardware |
| because it normally does not have an independent secure real-time clock. |
| |
| <p>Whether a key's user authentication authorization is enforced by the secure hardware can be |
| queried using |
| {@link android.security.keystore.KeyInfo#isUserAuthenticationRequirementEnforcedBySecureHardware() KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()}. |
| |
| <h2 id="WhichShouldIUse">Choosing Between a Keychain or the |
| Android Keystore Provider</h2> |
| |
| <p>Use the {@link android.security.KeyChain} API when you want |
| system-wide credentials. When an app requests the use of any credential |
| through the {@link android.security.KeyChain} API, users get to |
| choose, through a system-provided UI, which of the installed credentials |
| an app can access. This allows several apps to use the |
| same set of credentials with user consent.</p> |
| |
| <p>Use the Android Keystore provider to let an individual app store its own |
| credentials that only the app itself can access. |
| This provides a way for apps to manage credentials that are usable |
| only by itself while providing the same security benefits that the |
| {@link android.security.KeyChain} API provides for system-wide |
| credentials. This method requires no user interaction to select the credentials.</p> |
| |
| <h2 id="UsingAndroidKeyStore">Using Android Keystore Provider</h2> |
| |
| <p> |
| To use this feature, you use the standard {@link java.security.KeyStore} |
| and {@link java.security.KeyPairGenerator} or |
| {@link javax.crypto.KeyGenerator} classes along with the |
| {@code AndroidKeyStore} provider introduced in Android 4.3 (API level 18).</p> |
| |
| <p>{@code AndroidKeyStore} is registered as a {@link |
| java.security.KeyStore} type for use with the {@link |
| java.security.KeyStore#getInstance(String) KeyStore.getInstance(type)} |
| method and as a provider for use with the {@link |
| java.security.KeyPairGenerator#getInstance(String, String) |
| KeyPairGenerator.getInstance(algorithm, provider)} and {@link |
| javax.crypto.KeyGenerator#getInstance(String, String) |
| KeyGenerator.getInstance(algorithm, provider)} methods.</p> |
| |
| <h3 id="GeneratingANewPrivateKey">Generating a New Private Key</h3> |
| |
| <p>Generating a new {@link java.security.PrivateKey} requires that |
| you also specify the initial X.509 attributes that the self-signed |
| certificate will have. You can replace the certificate at a later |
| time with a certificate signed by a Certificate Authority.</p> |
| |
| <p>To generate the key, use a {@link java.security.KeyPairGenerator} |
| with {@link android.security.KeyPairGeneratorSpec}:</p> |
| |
| {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java generate} |
| |
| <h3 id="GeneratingANewSecretKey">Generating a New Secret Key</h3> |
| |
| <p>To generate the key, use a {@link javax.crypto.KeyGenerator} with |
| {@link android.security.keystore.KeyGenParameterSpec}. |
| |
| <h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3> |
| |
| <p>Using the {@code AndroidKeyStore} provider takes place through |
| all the standard {@link java.security.KeyStore} APIs.</p> |
| |
| <h4 id="ListingEntries">Listing Entries</h4> |
| |
| <p>List entries in the keystore by calling the {@link |
| java.security.KeyStore#aliases()} method:</p> |
| |
| {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java list} |
| |
| <h4 id="SigningAndVerifyingData">Signing and Verifying Data</h4> |
| |
| <p>Sign data by fetching the {@link |
| java.security.KeyStore.Entry} from the keystore and using the |
| {@link java.security.Signature} APIs, such as {@link |
| java.security.Signature#sign()}:</p> |
| |
| {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java sign} |
| |
| <p>Similarly, verify data with the {@link java.security.Signature#verify(byte[])} method:</p> |
| |
| {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java verify} |
| |
| <h3 id="UserAuthentication">Requiring User Authentication For Key Use</h3> |
| |
| <p>When generating or importing a key into the {@code AndroidKeyStore} you can specify that the key |
| is only authorized to be used if the user has been authenticated. The user is authenticated using a |
| subset of their secure lock screen credentials (pattern/PIN/password, fingerprint). |
| |
| <p>This is an advanced security feature which is generally useful only if your requirements are that |
| a compromise of your application process after key generation/import (but not before or during) |
| cannot bypass the requirement for the user to be authenticated to use the key. |
| |
| <p>When a key is authorized to be used only if the user has been authenticated, it is configured to |
| operate in one of the two modes: |
| <ul> |
| <li>User authentication authorizes the use of keys for a duration of time. All keys in this mode are |
| authorized for use as soon as the user unlocks the secure lock screen or confirms their secure |
| lock screen credential using the |
| {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence) KeyguardManager.createConfirmDeviceCredentialIntent} |
| flow. The duration for which the authorization remains valid is specific to each key, as specified |
| using {@code setUserAuthenticationValidityDurationSeconds} during key generation or import. Such |
| keys can only be generated or imported if the secure lock screen is enabled (see |
| {@link android.app.KeyguardManager#isDeviceSecure() KeyguardManager.isDeviceSecure()}). These keys |
| become permanently invalidated once the secure lock screen is disabled (reconfigured to None, |
| Swipe or other mode which does not authenticate the user) or forcibly reset (e.g. by a Device |
| Administrator).</li> |
| <li>User authentication authorizes a specific cryptographic operation associated with one key. In |
| this mode, each operation involving such a key must be individually authorized by the user. |
| Currently, the only means of such authorization is fingerprint authentication: |
| {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler) FingerprintManager.authenticate}. |
| Such keys can only be generated or imported if at least one fingerprint is enrolled (see |
| {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}). |
| These keys become permanently invalidated once a new fingerprint is enrolled or all fingerprints |
| are unenrolled.</li> |
| </ul> |
| |
| <h2 id="SupportedAlgorithms">Supported Algorithms</h2> |
| |
| <ul> |
| <li><a href="#SupportedCiphers">{@code Cipher}</a></li> |
| <li><a href="#SupportedKeyGenerators">{@code KeyGenerator}</a></li> |
| <li><a href="#SupportedKeyFactories">{@code KeyFactory}</a></li> |
| <li><a href="#SupportedKeyPairGenerators">{@code KeyPairGenerator}</a></li> |
| <li><a href="#SupportedMacs">{@code Mac}</a></li> |
| <li><a href="#SupportedSignatures">{@code Signature}</a></li> |
| <li><a href="#SupportedSecretKeyFactories">{@code SecretKeyFactory}</a></li> |
| </ul> |
| |
| <h3 id="SupportedCiphers">Cipher</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>AES/CBC/NoPadding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>AES/CBC/PKCS7Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>AES/CTR/NoPadding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>AES/ECB/NoPadding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>AES/ECB/PKCS7Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>AES/GCM/NoPadding</td> |
| <td>23+</td> |
| <td>Only 12-byte long IVs supported.</td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/NoPadding</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/PKCS1Padding</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/OAEPWithSHA-1AndMGF1Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/OAEPWithSHA-224AndMGF1Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/OAEPWithSHA-256AndMGF1Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/OAEPWithSHA-384AndMGF1Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/OAEPWithSHA-512AndMGF1Padding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>RSA/ECB/OAEPPadding</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <h3 id="SupportedKeyGenerators">KeyGenerator</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>AES</td> |
| <td>23+</td> |
| <td>Supported sizes: 128, 192, 256</td> |
| </tr> |
| <tr> |
| <td>HmacSHA1</td> |
| <td>23+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li> |
| <li>Default size: 160</li> |
| <ul> |
| </td> |
| </tr> |
| <tr> |
| <td>HmacSHA224</td> |
| <td>23+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li> |
| <li>Default size: 224</li> |
| <ul> |
| </td> |
| </tr> |
| <tr> |
| <td>HmacSHA256</td> |
| <td>23+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li> |
| <li>Default size: 256</li> |
| <ul> |
| </td> |
| </tr> |
| <tr> |
| <td>HmacSHA384</td> |
| <td>23+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li> |
| <li>Default size: 384</li> |
| <ul> |
| </td> |
| </tr> |
| <tr> |
| <td>HmacSHA512</td> |
| <td>23+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li> |
| <li>Default size: 512</li> |
| <ul> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <h3 id="SupportedKeyFactories">KeyFactory</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>EC</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo} (private key only), |
| {@link java.security.spec.ECPublicKeySpec} (public key only), |
| {@link java.security.spec.X509EncodedKeySpec} (public key only) |
| </td> |
| </tr> |
| <tr> |
| <td>RSA</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo} (private key only), |
| {@link java.security.spec.RSAPublicKeySpec} (public key only), |
| {@link java.security.spec.X509EncodedKeySpec} (public key only) |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <h3 id="SupportedKeyStoreKeys">KeyStore</h3> |
| KeyStore supports the same key types as |
| <a href="#SupportedKeyPairGenerators">{@code KeyPairGenerator}</a> and |
| <a href="#SupportedKeyGenerators">{@code KeyGenerator}</a>. |
| |
| <h3 id="SupportedKeyPairGenerators">KeyPairGenerator</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr class="deprecated"> |
| <td>DSA</td> |
| <td>19–22</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>EC</td> |
| <td>23+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 224, 256, 384, 521</li> |
| <li>Supported named curves: P-224 (secp256r1), P-256 (aka secp256r1 and prime256v1), P-384 |
| (aka secp384r1), P-521 (aka secp521r1)</li> |
| </ul> |
| |
| <p>Prior to API Level 23, EC keys can be generated using KeyPairGenerator of algorithm "RSA" |
| initialized {@link android.security.KeyPairGeneratorSpec} whose key type is set to "EC" |
| using {@link android.security.KeyPairGeneratorSpec.Builder#setKeyType(String)}. EC curve |
| name cannot be specified using this method -- a NIST P-curve is automatically chosen based |
| on the requested key size. |
| </td> |
| </tr> |
| <tr> |
| <td>RSA</td> |
| <td>18+</td> |
| <td> |
| <ul> |
| <li>Supported sizes: 512, 768, 1024, 2048, 3072, 4096</li> |
| <li>Supported public exponents: 3, 65537</li> |
| <li>Default public exponent: 65537</li> |
| </ul> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <h3 id="SupportedMacs">Mac</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>HmacSHA1</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>HmacSHA224</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>HmacSHA256</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>HmacSHA384</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>HmacSHA512</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <h3 id="SupportedSignatures">Signature</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>MD5withRSA</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>NONEwithECDSA</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>NONEwithRSA</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr class="deprecated"> |
| <td>SHA1withDSA</td> |
| <td>19–22</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA1withECDSA</td> |
| <td>19+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA1withRSA</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA1withRSA/PSS</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr class="deprecated"> |
| <td>SHA224withDSA</td> |
| <td>20–22</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA224withECDSA</td> |
| <td>20+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA224withRSA</td> |
| <td>20+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA224withRSA/PSS</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr class="deprecated"> |
| <td>SHA256withDSA</td> |
| <td>19–22</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA256withECDSA</td> |
| <td>19+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA256withRSA</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA256withRSA/PSS</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr class="deprecated"> |
| <td>SHA384withDSA</td> |
| <td>19–22</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA384withECDSA</td> |
| <td>19+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA384withRSA</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA384withRSA/PSS</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| <tr class="deprecated"> |
| <td>SHA512withDSA</td> |
| <td>19–22</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA512withECDSA</td> |
| <td>19+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA512withRSA</td> |
| <td>18+</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>SHA512withRSA/PSS</td> |
| <td>23+</td> |
| <td></td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <h3 id="SupportedSecretKeyFactories">SecretKeyFactory</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>Algorithm</th> |
| <th>Supported (API Levels)</th> |
| <th>Notes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>AES</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td> |
| </tr> |
| <tr> |
| <td>HmacSHA1</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td> |
| </tr> |
| <tr> |
| <td>HmacSHA224</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td> |
| </tr> |
| <tr> |
| <td>HmacSHA256</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td> |
| </tr> |
| <tr> |
| <td>HmacSHA384</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td> |
| </tr> |
| <tr> |
| <td>HmacSHA512</td> |
| <td>23+</td> |
| <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td> |
| </tr> |
| </tbody> |
| </table> |