How to implement encrypted sharepreferences - java

How to implement encrypted sharepreferences in my android java apps using https://developer.android.google.cn/reference/androidx/security/crypto/EncryptedSharedPreferences? I dont know how to implement it, anyone can help?

I was using a similar code to what #Chirag wrote but after I applied new updates to my Android Studio 4.0 project, I was getting a warning that MasterKeys class is deprecated.
So I found this answer and it did the trick. Here is the code in a fragment. If you want to use it in your MainActivity, change getContext() to this
MasterKey getMasterKey() {
try {
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"_androidx_security_master_key_",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build();
return new MasterKey.Builder(getContext())
.setKeyGenParameterSpec(spec)
.build();
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "Error on getting master key", e);
}
return null;
}
private SharedPreferences getEncryptedSharedPreferences() {
try {
return EncryptedSharedPreferences.create(
Objects.requireNonNull(getContext()),
"Your preference file name",
getMasterKey(), // calling the method above for creating MasterKey
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "Error on getting encrypted shared preferences", e);
}
return null;
}
Then you can use the above like this:
public void someFunction(){
SharedPreferences sharedPreferences = getEncryptedSharedPreferences();
//Used to add new entries and save changes
SharedPreferences.Editor editor = sharedPreferences.edit();
//To add entry to your shared preferences file
editor.putString("Name", "Value");
editor.putBoolean("Name", false);
//Apply changes and commit
editor.apply();
editor.commit();
//To clear all keys from your shared preferences file
editor.clear().apply();
//To get a value from your shared preferences file
String returnedValue = sharedPreferences.getString("Name", "Default value if null is returned or the key doesn't exist");
}

As per the documentation example, you can init EncryptedSharedPreferences like this.
public SharedPreferences getEncryptedSharedPreferences(){
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs_file",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
return sharedPreferences;
}
Save Data
getEncryptedSharedPreferences().edit()
.putString("key", value)
.apply()
Get Data
getEncryptedSharedPreferences().getString("key", "defaultValue");
Make sure your app API version is 23+ and you need to add this dependency
implementation "androidx.security:security-crypto:1.0.0-alpha02" //Use latest version

Related

Clear shared preference having dynamic keys

I'm creating a SharedPreferences in my app using a dyanmic key generated using a combination of some fixed String and id(unique id for each item).
Get values from shared preference
public static int getSharedPref(Context context, String keyName) {
SharedPreferences betaPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
return betaPref.getInt("getShare" + keyName, 0);
}
Save value in shared preference
public static void saveSharedPref(Context context, int value, String keyName) {
try {
SharedPreferences betaPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = betaPref.edit();
editor.putInt("getShare" + keyName, value);
editor.apply();
} catch (Exception e) {
LogUtil.e("getShare" + keyName, Log.getStackTraceString(e), e);
}
}
So far it works good, but now I also want to delete these shared preference when user logout from the app.
I know we can use
preferences.edit().remove("getShare").commit();
to remove a particular shared preference, but being a dynamic keys I don't have a exact name to delete it.
Query : Is there any way I can delete all shared preference containing a particular keyword? Or fetch all the keywords used in shared preference and filter them to delete on specific ones
Removing all preferences:
SharedPreferences sharedPreferences = context.getSharedPreferences("name", Context.MODE_PRIVATE);
sharedPreferences.edit().clear().commit();
Removing single preference:
SharedPreferences sharedPreferences = context.getSharedPreferences("name", Context.MODE_PRIVATE);
sharedPreferences.edit().remove("key_name").commit();
SharedPreferences has the method getAll() that returns a Map<String, ?> . From the Map you can retrieve easily the keys with keySet() and the key/value mappings with entrySet():
Map<String, ?> allEntries = prefA.getAll();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
Log.d("map values", entry.getKey() + ": " + entry.getValue().toString());
}

How to store a set of ArrayList values using sharedpreference

The code below retrieves multiple selected contacts and stores it in the form of ArrayList but once I close the application and open the selected contact list is removed ,so the data should be stored so that once I close and open the app the data remains until the data is removed. Can anyone please help me to store the ArrayList values using shared preference .
private void chooseContact() {
Intent intentContactPick = new Intent(MainActivity.this,ContactsPickerActivity.class);
MainActivity.this.startActivityForResult(intentContactPick,CONTACT_PICK_REQUEST);
}
#Override
public void onActivityResult(int requestCode,int resultCode,Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == CONTACT_PICK_REQUEST && resultCode == RESULT_OK){
ArrayList<Contact> selectedContacts = data.getParcelableArrayListExtra("SelectedContacts");
String display="";
for(int i=0;i<selectedContacts.size();i++){
display += (i+1)+". "+selectedContacts.get(i).toString()+"\n";
}
contactsDisplay.setText("Selected Contacts : \n\n"+display);
}
}
}
the below code is the ArrayList which holds the selected contact values.
ArrayList<Contact> selectedContacts = data.getParcelableArrayListExtra("SelectedContacts");
You have different options.
Use a service and run it on background so data will not lost on close.
Write the data to an object and save it as file and read the object when you need the data.
Write object to shared preference.
Convert your array or object to Json with Gson library and store your data as String in json format.
Save;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
Editor editor = sharedPrefs.edit();
Gson gson = new Gson();
String json = gson.toJson(arrayList);
editor.putString(TAG, json);
editor.commit();
Read;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
Gson gson = new Gson();
String json = sharedPrefs.getString(TAG, null);
Type type = new TypeToken<ArrayList<ArrayObject>>() {}.getType();
ArrayList<ArrayObject> arrayList = gson.fromJson(json, type);
use import java.lang.reflect.Type for avoiding errors.
See this.
Store
public void storeData(Context context,List<Contact> offlineData){
SharedPreferences preferences=context.getSharedPreferences("contact_prefs",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
Gson gson=new Gson();
editor.putString("data",gson.toJson(offlineData));
editor.apply();
}
Read
public List<Contact> getData(Context context){
SharedPreferences preferences=context.getSharedPreferences("contact_prefs",Context.MODE_PRIVATE);
Gson gson = new Gson();
return gson.fromJson(preferences.getString("data",null), new TypeToken<List<Photo>>() {
}.getType());
}
To save a key value pair to the shared preferences :
SharedPreferences sharedPreference = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreference.edit();
editor.putString(key, value);
editor.apply();
context : Pass the calling context or Base Context or Application Context (getContext() in Fragments or getBaseContext() in Activity)
Ranjith KP answer is great. dont forget to add dependecy:
compile 'com.google.code.gson:gson:2.8.0'
for the context u can pass ur activity (just use 'this' instead).
TAG - thats just a string, add
String TAG = "tag";
on your activity's members.

How to store all keys from a specific value from SharedPreferences

In my android app, I have a custom listview of installed apps with a checkbox next to it. I am using SharedPreferences to store the boolean true for checked and false for unchecked. The key value is the packagename of the app and the value is a boolean, true or false.
I am trying to store all the keys (packagenames) with the value-- true, all together and so then I can use the packagenames in another class for a specific task. However, I want the data structure that stores all the keys to stay the same and hold all the checked packagename keys even when the app is killed.
Currently, I am using code like this:
String findKey(SharedPreferences sharedPreferences, String value) {
for (Map.Entry<String, ?> entry: sharedPreferences.getAll()) {
if (value.equals(entry.getValue())) {
return entry.getKey();
}
}
return null; // not found
}
I have tried researching but still unable to produce a solution.
Get all SharedPreferences names and all their keys?
Gather all Strings from SharedPreference getAll() Method?
How would I implement this correctly to get all my packagenames in a data structure that I can use in another class and have it stored with the same stuff even when the app is killed?
This is my code in my adapter class:
for(int i= 0; i<packageList.size(); i++){
PACKAGE_NAME = packageInfo.packageName;
sharedPrefs = context.getSharedPreferences(PACKAGE_NAME, Context.MODE_PRIVATE);
holder.ck1.setChecked(sharedPrefs.getBoolean(PACKAGE_NAME,false));
}
holder.ck1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
SharedPreferences.Editor editor = context.getSharedPreferences(packageInfo.packageName, Context.MODE_PRIVATE).edit();
if (holder.ck1.isChecked()) {
itemChecked[position] = true;
holder.ck1.setChecked(true);
editor.putBoolean(packageInfo.packageName, true);
editor.apply();
} else {
itemChecked[position] = false;
holder.ck1.setChecked(false);
editor.putBoolean(packageInfo.packageName, false);
editor.apply();
}
}
});
Just extending from my comment.Here have a look.
final String CHECKBOX_DATA="CHECKBOX_DATA";
JSONObject js=new JSONObject();
js.put("package.name1", true);
js.put("package.name2", false);
js.put("package.name3", true);
js.put("package.name4", true);
SharePreferences prefs=context.getSharedPreferences(context.getPackageName(),Context.MODE_PRIVATE);
prefs.edit().putString(CHECKBOX_DATA, js.toString()).commit();
And then retrieve the same as
SharedPreferences prefs = context.getSharedPreferences(
context.getPackageName(), Context.MODE_PRIVATE);
String json=prefs.getString(CHECKBOX_DATA, null);
JSONObject jsobj=new JSONObject(json);
Iterator<String> iter = jsobj.keys();
while (iter.hasNext()) {
String key = iter.next();//This is your packagename
try {
boolean value = jsobj.getBoolean(key);
} catch (JSONException e) {
// Something went wrong!
}
}
Sorry, now I understand your question.
In Android >=3.0 (API 11), you can store package name array by putStringSet (String key, Set values)
In Android <3.0, you can combine all package name into one string, separate by "," because the package name cannot have ",".
For an example:
String allPackageName = "com.app1,com.app2,com.app3";
After that, save allPackageName in SharedPreference with a key:
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("key_app_checked", allPackageName );
editor.commit();
Get all package name and split to an String array:
String packageNameChecked = sharedPref.getString("allPackageName");
if(packageNameChecked !=null){
String [] arrPackageNameChecked = packageNameChecked.split(",");
//Do somethings with arrPackageNameChecked ...
}
According your post, i don't know what exactly what do you want. Because SharedPreferences save many value in xml file, so you can access it in every where in your app and it not lost when the app is killed.
I saw some issue when you use SharedPref:
When save value:
It must have editor.commit() after you change or store value.
I think your code store each value in one SharedPreference file. It NOT necessary. You should save all value in one file with difference key.
You should read this post, it will help you understand more about SharedPrefercence.

Android - Storing information about User on login in JSON

In my application, a user logs in on the LoginActivity, upon which a login session is created using a SessionManager class I created (I have a SharedPreferences object in it, for which I put the user's email in and put a boolean isLoggedIn to true).
Now, what I really want to do is put the User's JSONObject that I get from the server in the LoginActivity upon login, into the SharedPreferences. Basically I want to be able to access the JSON document from anywhere in the application while the user is logged in.
However, I realize I can't put a JSONObject into the editor. What is the correct way to implement the functionality I'm describing though?
If relevant... this is my SessionManager class which has a SharedPreferences object in it (I don't know if this is the best way to do it):
package com.xxx.xxxx;
import java.util.HashMap;
import com.xxxx.auth.LoginActivity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class SessionManager {
// Shared Preferences
SharedPreferences pref;
// Editor for Shared preferences
Editor editor;
// Context
Context _context;
// Shared pref mode
int PRIVATE_MODE = 0;
// Sharedpref file name
private static final String PREF_NAME = "PREFS";
// All Shared Preferences Keys
private static final String IS_LOGIN = "IsLoggedIn";
// Email address
public static final String KEY_EMAIL = "email";
// Constructor
public SessionManager(Context context) {
this._context = context;
pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
editor = pref.edit();
}
/** Create login session */
public void createLoginSession(String email){
// Storing login value as TRUE
editor.putBoolean(IS_LOGIN, true);
// Storing email in pref
editor.putString(KEY_EMAIL, email);
// I WANTED TO STORE THE JSON HERE AFTER PASSING IT AS A PARAMETER
// IN THE METHOD
// commit changes
editor.commit();
}
/**
* Get stored session data
* */
public HashMap<String, String> getUserDetails(){
HashMap<String, String> user = new HashMap<String, String>();
// user email id
user.put(KEY_EMAIL, pref.getString(KEY_EMAIL, null));
// return user
return user;
}
/**
* Clear session details
* */
public void logoutUser(){
// Clearing all data from Shared Preferences
editor.clear();
editor.commit();
redirect();
}
public void redirect() {
//redirect user to Login Activity
Intent i = new Intent(_context, LoginActivity.class);
// Closing all the Activities
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Add new Flag to start new Activity
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Staring Login Activity
_context.startActivity(i);
}
// Get Login State
public boolean isLoggedIn() {
return pref.getBoolean(IS_LOGIN, false);
}
}
You can store only simple types in Preferences http://developer.android.com/reference/android/content/SharedPreferences.Editor.html. If you really want to save JSON, save it as String and parse it with GSON (https://code.google.com/p/google-gson/) or some other JSON mapper.
You can serialize JSONObject in a file inside SD Card. SharedPreferences is not designed to handle it. But don't add sensitive data inside the file. If the JSONObject size is little, then you can try the below code. You need Gson library to do this.
public static void setJSONObject(Context context, YourObject obj){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("YOUR_OBJECT",new Gson().toJson(obj));
editor.commit();
}
public static YourObject getJSONObject (Context context){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String stringobj = preferences.getString("YOUR_OBJECT", "");
if(stringobj.equals(""))return null;
else return new Gson().fromJson(stringobj, YourObject.class);
}
You can use gson library (https://code.google.com/p/google-gson/) to convert json object to and from String.
Usage:
(Serialization)
UserInfo obj = new UserInfo();
Gson gson = new Gson();
String json = gson.toJson(obj);
==> json is {"value1":1,"value2":"abc"}
You can save the json string in SharedPreferences.
Later, to get back the json object do a de-serialization.
(Deserialization)
UserInfo user = gson.fromJson(json, UserInfo.class);
==> user is just like obj
Hope this helps.
Use sqlite to store information.
OR
Write JSONObject in file on your phone memory.
Try not to store your JSON in the SharedPreferences - SharedPreferences wasn't designed to store small amounts of data and is relatively slow to read from.
The best thing you can do is to store your JSON in a private file and read from that file. You can create and write your JSON to a private file by doing the following (taken from Android developer docs):
String FILENAME = "hello_file";
String json = my_json_data.toString();
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(json.getBytes());
fos.close();
You can read from this file by calling openFileInput() and passing in FILENAME.
Store the JSONObject as String.
Create another Key
public static final String KEY_JSON = "user_json";
Modify your createLoginSession method
public void createLoginSession(String email, JSONObject user_data){
// Storing login value as TRUE
editor.putBoolean(IS_LOGIN, true);
// Storing email in pref
editor.putString(KEY_EMAIL, email);
// I WANTED TO STORE THE JSON HERE AFTER PASSING IT AS A PARAMETER
// IN THE METHOD
editor.putString(KEY_JSON, user_data.toString());
// commit changes
editor.commit();
}
I hope that helps.

SharedPefs seeminly wiped even though I use them to auto login

I am trying to save to my apps shared preferences, I save the Username and password.
on successful login, these get stored fine. When I kill the app, then re-open it, it auto logs in as it should using the shared prefs.
however when I navigate to the account management activity and try access the prefs again the keys for the username and password can't be found and the default value is returned. I'm definetly using the right key values as it works perfectly fine when a manual login is required if there are no user/password prefs stored on first startup.
This really confuses me as the username and password keys clearly exist otherwise the it wouldn't auto-login.
Some code:
This is my account management activity:
public class AccManagement extends Activity
{
TextView textName;
TextView textEmail;
String SharedUsername;
String SharedPassword;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_acc_management);
textName = (TextView)findViewById(R.id.textviewName);
textEmail = (TextView)findViewById(R.id.textviewEmail);
//these return null, as if there are no shared prefs stored.
SharedUsername= SharedPrefsWrapper.getFromPrefs(this, "USERNAME", null);
SharedPassword= SharedPrefsWrapper.getFromPrefs(this, "PASSWORD", null);
}
I made a wrapper class for shared prefs which gets and puts key/value pairs into the shared prefs.
This is how I check if a user exists in my main activity:
public void Checker()
{
String SharedUsername= SharedPrefsWrapper.getFromPrefs(this, "USERNAME", null);
String SharedPassword= SharedPrefsWrapper.getFromPrefs(this, "PASSWORD", null);
if(SharedUsername== null || SharedPassword== null)
{
setContentView(R.layout.activity_main);
}
else
{
Login(url);
}
}
Login executes an http request and this method is called on completion:
public void onTaskCompleted(String data)
{
if(data.contains("name")) //a successful login will return a json string with "name".
{
Intent intent = new Intent(this, MenuActivity.class);
SharedPrefsWrapper.saveToPref(this, "USERNAME", textusername);
SharedPrefsWrapper.saveToPref(this, "PASSWORD", textpassword);
startActivity(intent);
}
}
On successful login the user is taken a menu which contains the account management button, and on click are taken to account management, which displays the username and password. Though this is where my problem occurs. It can't find the shared prefs I saved on login. It only happens when the app auto logs in using the shared prefs. If it's a first time login it seems to work fine and the shared prefs still seem to be there when I try get them from my account activity.
Thanks for any help
and sorry if the question simply doesn't make sense!
:)
EDITS:
SharedPrefs class methods:
public static void saveToPref(Context context, String key, String value)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editor = prefs.edit();
editor.putString(key, value);
editor.commit();
}
public static String getFromPrefs(Context context, String key, String defValue)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
try
{
return prefs.getString(key, defValue);
}
catch(Exception ex)
{
return defValue;
}
}
When auto loging, textusername and textpassword are empty, so this wipes out your prefs.
Try to respect java naming conventions, your code is hard to read.

Categories