public final class AndroidKeysetManager extends Object
KeysetManager
that supports reading/writing Keyset
to/from private shared preferences on Android.
This class reads and writes to shared preferences, thus is best not to run on the UI thread.
// One-time operations, should be done when the application is starting up.
// Instead of repeatedly instantiating these crypto objects, instantiate them once and save for
// later use.
AndroidKeysetManager manager = AndroidKeysetManager.Builder()
.withSharedPref(getApplicationContext(), "my_keyset_name", "my_pref_file_name")
.withKeyTemplate(AesGcmHkfStreamingKeyManager.aes128GcmHkdf4KBTemplate())
.build();
StreamingAead streamingAead = manager.getKeysetHandle().getPrimitive(StreamingAead.class);
This will read a keyset stored in the my_keyset_name
preference of the my_pref_file_name
preferences file. If the preference file name is null, it uses the default
preferences file.
IOException
is thrown. The most common
cause is when you decrypted a keyset with a wrong master key. In this case, an InvalidProtocolBufferException
would be thrown. This is an irrecoverable error. You'd have
to delete the keyset in Shared Preferences and all existing data encrypted with it.
KeyTemplate
is set with AndroidKeysetManager.Builder.withKeyTemplate(com.google.crypto.tink.KeyTemplate)
, a fresh
keyset is generated and is written to the my_keyset_name
preference of the my_pref_file_name
shared preferences file.
The resulting manager supports all operations supported by KeysetManager
. For example
to rotate the keyset, you can do:
manager.rotate(AesGcmHkfStreamingKeyManager.aes128GcmHkdf1MBTemplate());
All operations that manipulate the keyset would automatically persist the new keyset to permanent storage.
If a master key URI is set with AndroidKeysetManager.Builder.withMasterKeyUri(java.lang.String)
, the
keyset may be encrypted with a key generated and stored in Android Keystore.
Android Keystore is only available on Android M or newer. Since it has been found that Android
Keystore is unreliable on certain devices. Tink runs a self-test to detect such problems and
disables Android Keystore accordingly, even if a master key URI is set. You can check whether
Android Keystore is in use with isUsingKeystore()
.
When Android Keystore is disabled or otherwise unavailable, keysets will be stored in cleartext. This is not as bad as it sounds because keysets remain inaccessible to any other apps running on the same device. Moreover, as of July 2020, most active Android devices support either full-disk encryption or file-based encryption, which provide strong security protection against key theft even from attackers with physical access to the device. Android Keystore is only useful when you want to require user authentication for key use, which should be done if and only if you're absolutely sure that Android Keystore is working properly on your target devices.
The master key URI must start with android-keystore://
. The remaining of the URI is
used as a key ID when calling Android Keystore. If the master key doesn't exist, a fresh one is
generated. If the master key already exists but is unusable, a KeyStoreException
is
thrown.
This class is thread-safe.
Modifier and Type | Class and Description |
---|---|
static class |
AndroidKeysetManager.Builder
A builder for
AndroidKeysetManager . |
Modifier and Type | Method and Description |
---|---|
AndroidKeysetManager |
add(KeyTemplate keyTemplate)
Deprecated.
This method takes a KeyTemplate proto, which is an internal implementation detail.
Please use the add method that takes a
KeyTemplate POJO. |
AndroidKeysetManager |
add(KeyTemplate keyTemplate)
Generates and adds a fresh key generated using
keyTemplate . |
AndroidKeysetManager |
delete(int keyId)
Deletes the key with
keyId . |
AndroidKeysetManager |
destroy(int keyId)
Destroys the key material associated with the
keyId . |
AndroidKeysetManager |
disable(int keyId)
Disables the key with
keyId . |
AndroidKeysetManager |
enable(int keyId)
Enables the key with
keyId . |
KeysetHandle |
getKeysetHandle() |
boolean |
isUsingKeystore()
Returns whether Android Keystore is being used to wrap Tink keysets.
|
AndroidKeysetManager |
promote(int keyId)
Deprecated.
use
setPrimary |
AndroidKeysetManager |
rotate(KeyTemplate keyTemplate)
Deprecated.
Please use
add(com.google.crypto.tink.proto.KeyTemplate) . This method adds a new key and immediately promotes it to
primary. However, when you do keyset rotation, you almost never want to make the new key
primary, because old binaries don't know the new key yet. |
AndroidKeysetManager |
setPrimary(int keyId)
Sets the key with
keyId as primary. |
public KeysetHandle getKeysetHandle() throws GeneralSecurityException
KeysetHandle
of the managed keysetGeneralSecurityException
@CanIgnoreReturnValue @Deprecated public AndroidKeysetManager rotate(KeyTemplate keyTemplate) throws GeneralSecurityException
add(com.google.crypto.tink.proto.KeyTemplate)
. This method adds a new key and immediately promotes it to
primary. However, when you do keyset rotation, you almost never want to make the new key
primary, because old binaries don't know the new key yet.keyTemplate
, and sets the new key as the
primary key.GeneralSecurityException
- if cannot find any KeyManager
that can handle keyTemplate
@CanIgnoreReturnValue @Deprecated public AndroidKeysetManager add(KeyTemplate keyTemplate) throws GeneralSecurityException
KeyTemplate
POJO.keyTemplate
.GeneralSecurityException
- if cannot find any KeyManager
that can handle keyTemplate
@CanIgnoreReturnValue public AndroidKeysetManager add(KeyTemplate keyTemplate) throws GeneralSecurityException
keyTemplate
.GeneralSecurityException
- if cannot find any KeyManager
that can handle keyTemplate
@CanIgnoreReturnValue public AndroidKeysetManager setPrimary(int keyId) throws GeneralSecurityException
keyId
as primary.GeneralSecurityException
- if the key is not found or not enabled@InlineMe(replacement="this.setPrimary(keyId)") @CanIgnoreReturnValue @Deprecated public AndroidKeysetManager promote(int keyId) throws GeneralSecurityException
setPrimary
keyId
as primary.GeneralSecurityException
- if the key is not found or not enabled@CanIgnoreReturnValue public AndroidKeysetManager enable(int keyId) throws GeneralSecurityException
keyId
.GeneralSecurityException
- if the key is not found@CanIgnoreReturnValue public AndroidKeysetManager disable(int keyId) throws GeneralSecurityException
keyId
.GeneralSecurityException
- if the key is not found or it is the primary key@CanIgnoreReturnValue public AndroidKeysetManager delete(int keyId) throws GeneralSecurityException
keyId
.GeneralSecurityException
- if the key is not found or it is the primary key@CanIgnoreReturnValue public AndroidKeysetManager destroy(int keyId) throws GeneralSecurityException
keyId
.GeneralSecurityException
- if the key is not found or it is the primary keypublic boolean isUsingKeystore()