how to securely store encryption keys in android?
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
How to protect my encryption key in Android?
You can use Andriod Keystore to encrypt your SQLCipher password.
I had the same issue while ago, where SQLCipher was used to secure data, but password itself was not. This allowed a security flaw where a simple decompilation would reveal the password as it was in the form of string constant.
My solution was:
- Generate a random number when app starts at first. (You can change this behaviour for whatever suits you)
- Encrypt this number using Android Keystore.
- The original form of the number is gone once its encrypted.
- Save this in Prefs.
- Now, whenever SQLCipher needs password, it will decrypt it and use it.
- Since Android Keystore is providing keys at runtime, and keys are strictly app specific, it will be hard to break this database.
- Although everything can be broken but this approach will make it a lot harder for the attacker to retrieve data from DB, or DB password.
Here is a sample project I made which also has a SQLCipher use case same as yours.
Encryption Helper for Encrypting Passwords
Use case for SQLCipher
Note that the term you are using as encryption key is used as password/number for DB in above discussion.
Easy way to Encrypt/Decrypt string in Android
You can use Cipher
for this.
This class provides the functionality of a cryptographic cipher for encryption and decryption. It forms the core of the Java Cryptographic Extension (JCE) framework.
Sample of encryption and decryption:
public static SecretKey generateKey()
throws NoSuchAlgorithmException, InvalidKeySpecException
{
return secret = new SecretKeySpec(password.getBytes(), "AES");
}
public static byte[] encryptMsg(String message, SecretKey secret)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
{
/* Encrypt the message. */
Cipher cipher = null;
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8"));
return cipherText;
}
public static String decryptMsg(byte[] cipherText, SecretKey secret)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException
{
/* Decrypt the message, given derived encContentValues and initialization vector. */
Cipher cipher = null;
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret);
String decryptString = new String(cipher.doFinal(cipherText), "UTF-8");
return decryptString;
}
To encrypt:
SecretKey secret = generateKey();
EncUtil.encryptMsg(String toEncrypt, secret))
To decrypt:
EncUtil.decryptMsg(byte[] toDecrypt, secret))
PHP and Android Keystore encryption / decryption
Ok, after searching and making sure the issue wasn't the public key stored in the PHP server, I found the answer. It was caused by the way to convert the "base64" string in an actual ByteArray in the App. This worked:
val token = App.encryptionController.decryptAsymmetricData(getDecoder().decode(encryptedToken))
val userID = App.encryptionController.decryptAsymmetricData(getDecoder().decode(encryptedUserId))
This is only working because I do the "base64_encode" in the server, for some (bad) reason I thought it was needed to go back to UTF8 to get the ByteArray in the app.
How can I encrypt the existing Room database with sqlcipher?
Encrypt each record of your database separately , you can use this package encrypt in a function that encrypt each record of your databsae.
Related Topics
How to Convert Rgb Color to Int in Java
What Does Transitive = True in Gradle Exactly Do (W.R.T. Crashlytics)
Enabling Specific Ssl Protocols with Android Webviewclient
How to Fix Install_Parse_Failed_Manifest_Malformed in My Android Application
Why Does My Compare Method Throw Exception -- Comparison Method Violates Its General Contract!
Svg/Vector Graphical Objects Boolean Operations (Union, Intersection, Subtraction)
Calling a Java Servlet from JavaScript
Stack Overflows from Deep Recursion in Java
How to Generate Multiple Lines in PDF Using Apache PDFbox
How to Resume Android Activity Programmatically from Background
Convert a String to a Byte Array and Then Back to the Original String
Binary Xml File Line #0: Error Inflating Class Imageview
Fileuriexposedexception in Android