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
Building Blocks: the future is multichain - CityAM
Federal Student Aid
Toa Guide Osrs
How To Fix Epson Printer Error Code 0x9e
Somboun Asian Market
Palm Coast Permits Online
Craigslist Mpls Mn Apartments
Air Canada bullish about its prospects as recovery gains steam
<i>1883</i>'s Isabel May Opens Up About the <i>Yellowstone</i> Prequel
Https Www E Access Att Com Myworklife
Cape Cod | P Town beach
Es.cvs.com/Otchs/Devoted
Things To Do In Atlanta Tomorrow Night
Sarpian Cat
David Turner Evangelist Net Worth
Cooktopcove Com
Tracking Your Shipments with Maher Terminal
Craigslist Edmond Oklahoma
Hollywood Bowl Section H
91 East Freeway Accident Today 2022
Everything you need to know about Costco Travel (and why I love it) - The Points Guy
Craigslist Prescott Az Free Stuff
Amazing deals for Abercrombie & Fitch Co. on Goodshop!
Drift Boss 911
Qhc Learning
Myhr North Memorial
Www.craigslist.com Savannah Ga
Dragonvale Valor Dragon
25 Best Things to Do in Palermo, Sicily (Italy)
Sherburne Refuge Bulldogs
Papa Johns Mear Me
Dr Seuss Star Bellied Sneetches Pdf
Leben in Japan &#8211; das muss man wissen - Lernen Sie Sprachen online bei italki
Jail Roster Independence Ks
Purdue Timeforge
Cbs Trade Value Chart Week 10
LEGO Star Wars: Rebuild the Galaxy Review - Latest Animated Special Brings Loads of Fun With An Emotional Twist
Texters Wish You Were Here
Chris Provost Daughter Addie
Craigs List Jonesboro Ar
Planet Fitness Lebanon Nh
Daily Times-Advocate from Escondido, California
Miracle Shoes Ff6
Blackstone Launchpad Ucf
Vons Credit Union Routing Number
Windshield Repair & Auto Glass Replacement in Texas| Safelite
Natasha Tosini Bikini
Expendables 4 Showtimes Near Malco Tupelo Commons Cinema Grill
Big Reactors Best Coolant
Costco The Dalles Or
Zom 100 Mbti
Renfield Showtimes Near Regal The Loop & Rpx
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.