External token: The protected keys are not stored in the device. You can use an external token containing a private/public key pair that allows you to encrypt the AES key. The token can be accesed using bluetooth or NFC.
From your comments, you need to encrypt data using a local key for current Android versions and the old ones
Android Keystore is designed to generate and protect your keys. But it is not available for API level below 18 and it has some limitations until API level 23.
You will need a random symmetric encryption key, for example AES. The AES key is used to encrypt and decrypt you data. I'm going to summarize your options to generate and store it safely depending on Android API level.
API Level < 18: Android Keystore not present. Request a password to the user, derive an encryption key from the password, The drawback is that you need to prompt for the password when application starts. The encryption key it is not stored in the device. It is calculated each time when the application is started using the password
API Level >=18 <23: Android Keystore available without AES support. Generate a random AES key using the default cryptographic provider (not using AndroidKeystore). Generate a RSA key pair into Android Keystore, and encrypt the AES key using RSA public key. Store encrypted AES key into Android SharedPreferences. When application starts, decrypt the AES key using RSA private key
API Level >=23: Android Keystore available with AES support. Generate a random AES key using into Android Keystore. You can use it directly.
To encrypt to can use AES/CBC/PKCS7Padding
algorithm. It requires also a random initialization vector (IV) to encrypt your data, but it can be public.
Alternatives:
API level >14: Android Key Chain: KeyChain is a system-wide credential storage. You can install certificates with private keys that can be used by applications. Use a preinstalled key to encrypt/decrypt your AES key as shown in the second case above.
External token: The protected keys are not stored in the device. You can use an external token containing a private/public key pair that allows you to encrypt the AES key. The token can be accesed using bluetooth or NFC
You cannot place the encryption key inside your apk file. You may want to keep it in a remote server and decrypt using server. Or you may make it difficult for others by encoding the key and keeping it in non-obvious places. But there's no bullet proof solution for this.
There is no way to securely save your private api keys into code. But you can use NDK to securely save private keys. It is not trivial to get key from NDK. Secue Key With NDK Example
It sounds like you want EncryptedSharedPreferences or EncryptedFile. Both of these use the AndroidKeyStore. The code snippets below actually answer the question "How do I use the AndroidKeystore to encrypt a file or store a cryptographic key?"
Make sure to include implementation "androidx.security:security-crypto:1.0.0-rc02"
in your app build.gradle
file.
from EncryptedSharedPreferences:
An implementation of SharedPreferences that encrypts keys and values.
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
// use the shared preferences and editor as you normally would
SharedPreferences.Editor editor = sharedPreferences.edit();
You could store an encryption key like this:
// generate random symmetric key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey symkey = keyGen.generateKey();
String alias = "your encryption key";
// store symmetric key
byte[] encodedSymmetricKey = symkey.getEncoded();
SharedPreferences.Editor edit = sharedPreferences.edit();
String base64EncodedSymmetricKey = new String(Base64.getEncoder().encode(encodedSymmetricKey));
edit.putString(alias, base64EncodedSymmetricKey);
edit.commit();
// retrieve symmetric key
String raw = sharedPreferences.getString(alias, null);
byte[] symKey = Base64.getDecoder().decode(raw);
SecretKeySpec spec = new SecretKeySpec(symKey, "AES");
assert(spec.equals(symkey));
// use your encryption key
Although it would be much better to use EncryptedFile.
from EncryptedFile:
Class used to create and read encrypted files.
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
File file = new File(context.getFilesDir(), "secret_data");
EncryptedFile encryptedFile = EncryptedFile.Builder(
file,
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();
// write to the encrypted file
FileOutputStream encryptedOutputStream = encryptedFile.openFileOutput();
// read the encrypted file
FileInputStream encryptedInputStream = encryptedFile.openFileInput();
note:
The master key, once created, is constant. So even after a phone reboot your app will still be able to encrypt/decrypt the file.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With