Securing secret key in Android using Keystore (2024)

Securing secret key in Android using Keystore (3)

At some point in time, we all wanted to keep our data secure from being hacked/reverse engineered. The basic security mechanisms like,

a. ProGuard, ShrinkResources & minifyEnabled
b. Hiding in Manifest
c. Hiding in Build.Gradle
d. Storing in MySQL DB/Room DB/SharedPreference
e. Hiding in Strings.xml.

All these methods fail to provide maximum security. The most common and known logic of securing the key can be bypassed either by reversing and taking it from dex->jar file or by rooting the device and accessing the device storage.

But, there is one more method that beats them all. The mechanism which is generally used by applications for storing very sensitive data like Credit Card details, Bank Account and such.

Keystore is bound to hardware security which is generally used to store cryptographic keys. It becomes incredibly difficult for hackers to get access to it since a Keystore is very specific to every application. More of introduction done let us jump to the code now -

Declare few variables in Cryptor.java

private static final String TRANSFORMATION = “AES/GCM/NoPadding”;
private static final String ANDROID_KEY_STORE = “AndroidKeyStore”;
private byte[] iv;
private KeyStore keyStore;
private static final String SAMPLE_ALIAS = “MYALIAS”;

a. TRANSFORMATION is used for setting the algorithm which will be used for encoding.

b. iv is known as Initialization Vector which is an arbitrary number used along with a secret key for encryption. (It can be stored in public storage like SharedPreference, Room DB or MySQL DB).

c. SAMPLE_ALIAS is used to access the entity stored inside the Keystore.

For encrypting a value with the Keystore, we can do it by,

a. Create an object of the Cryptor class.

b. Use a setIv method to init the cipher using a secret key in Cryptor class.

c. Encrypt the text using an encryption function defined in Cryptor class.

d. Store the Iv and encrypted text (The Iv can be made public and it does not cause any issue) in SharedPreference or Room Database.

In RegistrationActivity.java

Cryptor cryptor = new Cryptor();
try {
cryptor.setIv();
prefs.edit().putString("encryptedKey", cryptor.encryptText("text_to_be_encrypted")).apply();
prefs.edit().putString("keyIv", cryptor.getIv_string()).apply();
Intent intent = new Intent(RegistrationActivity.this, HomeScreen.class);
startActivity(intent);
finish();
} catch (NoSuchPaddingException e) {
unexpectedError();
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
unexpectedError();
e.printStackTrace();
} catch (NoSuchProviderException e) {
unexpectedError();
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
unexpectedError();
e.printStackTrace();
} catch (InvalidKeyException e) {
unexpectedError();
e.printStackTrace();
}

In Cryptor.java, we define the following functions

  1. setIv() method :
public void setIv() throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey_en());
iv = cipher.getIV();
}

2. getSecretKey_en() method :

@NonNull
private SecretKey getSecretKey_en() throws NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {
final KeyGenerator keyGenerator;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(Cryptor.SAMPLE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
return keyGenerator.generateKey();
} else {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(Cryptor.SAMPLE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
return keyGenerator.generateKey();
}
}

3. encryptText(String string_to_encrypt) :

public String encryptText(String string_to_encrypt) { try {
final byte[] encryptedText = encryptData(string_to_encrypt);
return Base64.encodeToString(encryptedText, Base64.DEFAULT);
} catch (NoSuchAlgorithmException | NoSuchProviderException |
NoSuchPaddingException | InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException |
IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
return "";
}

4. encryptData(String text_to_encrypt) :

private byte[] encryptData(final String textToEncrypt)
throws NoSuchAlgorithmException,
NoSuchProviderException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, BadPaddingException,
IllegalBlockSizeException {
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey_en());
iv = cipher.getIV(); return (cipher.doFinal(textToEncrypt.getBytes(StandardCharsets.UTF_8)));
}

5. getIv_string() :

public String getIv_string() {
return Base64.encodeToString(iv, Base64.DEFAULT);
}

Explanation: We generate a secret key using the keyStore with specific algorithms and the ALIAS. the secret key which is generated is used to init the cipher and get the IV. The encrypt text function uses the text and the iv to encrypt the text in the Keystore and gives the encrypted text which can be stored in any general storage medium.

For decrypting a value with the Keystore, we can do it by,

a. Create an object of the Cryptor class.

b. Initialize the KeyStore instance.

c. Use the decrypt function by passing the encrypted text and the iv (stored in SharedPreference or Room Database).

In HomeScreen.java

String iv = prefs.getString("keyIv", "null");
String encrypted = prefs.getString("encryptedKey", "");
try {
Cryptor cryptor = new Cryptor();
cryptor.initKeyStore();
String decrypted = cryptor.decryptText(encrypted, iv);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

In Cryptor.java, add the following functions

  1. initKeyStore() :
public void initKeyStore() throws KeyStoreException, CertificateException,
NoSuchAlgorithmException, IOException {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
keyStore.load(null);
}

2. decryptText(String encrypted_string, String iv) :

public String decryptText(String encrypted, String iv) {
try {
return decryptData(encrypted, Base64.decode(iv,Base64.DEFAULT));
} catch (UnrecoverableEntryException | NoSuchAlgorithmException |
KeyStoreException | NoSuchPaddingException | InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return "";
}

3. decryptData(String encrypted_string, byte[] Iv) :

private String decryptData(String encrypted, final byte[] encryptionIv)
throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException,
NoSuchPaddingException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey_de(), spec);
byte[] encryptedData = Base64.decode(encrypted,Base64.DEFAULT); return new String(cipher.doFinal(encryptedData), StandardCharsets.UTF_8);
}

Explanation: While decrypting, we get the stored Iv and encrypted text stored in our one of the storage medium. We initialize the Keystore using the ANDROID_KEY_STORE and decrypt the text using the Iv and by the init and doFinal method of the Cipher.

So, with the above implementation, secrets are now safe in the KeyStore. Why it is probably the best method is because KeyStore is very specific to the application. It cannot be retrieved and hence the text cannot be decrypted without it. Many applications which stores the Credit Card and other sensitive data of the users use this encryption method to keep it safe.

For the entire code, you can look into my GitHub repository.

Explaining the code, I have defined files like — Cryptor.java, RegistrationActivity.java and HomeScreen.java. I have also used Room Database (launched by Google in I/O 2018) which provides high-level security than SQLLite (can be accessed if the device is rooted) to store the username and password to authenticate the registered users.

Securing secret key in Android using Keystore (2024)
Top Articles
How To Make Money in College: 17 Strategies To Earn Cash (2024) - Shopify
What Is Delisting of Share & Why Does It Occur? | 5paisa
English Bulldog Puppies For Sale Under 1000 In Florida
Sound Of Freedom Showtimes Near Governor's Crossing Stadium 14
Weeminuche Smoke Signal
Pinellas County Jail Mugshots 2023
RuneScape guide: Capsarius soul farming made easy
Poplar | Genus, Description, Major Species, & Facts
United Dual Complete Providers
Ecers-3 Cheat Sheet Free
Katie Boyle Dancer Biography
What is IXL and How Does it Work?
Culver's Flavor Of The Day Monroe
Craigslist Free Grand Rapids
Transformers Movie Wiki
Uhcs Patient Wallet
Echo & the Bunnymen - Lips Like Sugar Lyrics
Dutchess Cleaners Boardman Ohio
No Hard Feelings Showtimes Near Cinemark At Harlingen
Gdp E124
Katherine Croan Ewald
1-833-955-4522
Vintage Stock Edmond Ok
Days Until Oct 8
Tinker Repo
Epguides Strange New Worlds
Heart Ring Worth Aj
Scheuren maar: Ford Sierra Cosworth naar de veiling
Lost Pizza Nutrition
How to Make Ghee - How We Flourish
Dexter Gomovies
Obituaries, 2001 | El Paso County, TXGenWeb
Things to do in Pearl City: Honolulu, HI Travel Guide by 10Best
Airg Com Chat
Fbsm Greenville Sc
Wasmo Link Telegram
Prima Healthcare Columbiana Ohio
The Mad Merchant Wow
Bimar Produkte Test & Vergleich 09/2024 » GUT bis SEHR GUT
Henry County Illuminate
Bernie Platt, former Cherry Hill mayor and funeral home magnate, has died at 90
Fifty Shades Of Gray 123Movies
Best Restaurants West Bend
Paul Shelesh
2013 Honda Odyssey Serpentine Belt Diagram
3500 Orchard Place
Motorcycles for Sale on Craigslist: The Ultimate Guide - First Republic Craigslist
Laura Houston Wbap
What Time Do Papa John's Pizza Close
Fallout 76 Fox Locations
Publix Store 840
WHAT WE CAN DO | Arizona Tile
Latest Posts
Article information

Author: Dean Jakubowski Ret

Last Updated:

Views: 5678

Rating: 5 / 5 (70 voted)

Reviews: 85% of readers found this page helpful

Author information

Name: Dean Jakubowski Ret

Birthday: 1996-05-10

Address: Apt. 425 4346 Santiago Islands, Shariside, AK 38830-1874

Phone: +96313309894162

Job: Legacy Sales Designer

Hobby: Baseball, Wood carving, Candle making, Jigsaw puzzles, Lacemaking, Parkour, Drawing

Introduction: My name is Dean Jakubowski Ret, I am a enthusiastic, friendly, homely, handsome, zealous, brainy, elegant person who loves writing and wants to share my knowledge and understanding with you.