Reputation: 338
In my app I have to save username,password,token,.. to reuse them. Initially I save this data in normal shared preferences but on rooted device it's easy read all preferences and I think that this isn't a good thing.
Now I'm trying to use SecurePreferences library (this) but if I initialize this preferences in this way:
SharedPreferences prefs = new SecurePreferences(context);
when I open an activity or in a fragment onCreateView the initialize often takes about 2-3 second (I tested it with TraceView) and this slow my activity or fragment opening.
There is a way to put SecurePreferences in a Singleton and instantiate it only one time in all my app? Or there is another best method to save this data and hide them to all external application?
UPDATE #1:
I found this solution. To instantiate only one time the SecurePreferences you should create an App class that extends Application in this way:
public class App extends Application {
private static final String TAG = "secureprefsample";
protected static App instance;
private SecurePreferences mSecurePrefs;
private SecurePreferences mUserPrefs;
public App(){
super();
instance = this;
}
public static App get() {
return instance;
}
/**
* Single point for the app to get the secure prefs object
* @return
*/
public SharedPreferences getSharedPreferences() {
if(mSecurePrefs==null){
mSecurePrefs = new SecurePreferences(this, "", "my_prefs.xml");
SecurePreferences.setLoggingEnabled(true);
}
return mSecurePrefs;
}
/**
* This is just an example of how you might want to create your own key with less iterations 1,000 rather than default 10,000. This makes it quicker but less secure.
* @return
*/
public SharedPreferences getSharedPreferences1000() {
try {
AesCbcWithIntegrity.SecretKeys myKey = AesCbcWithIntegrity.generateKeyFromPassword(Build.SERIAL,AesCbcWithIntegrity.generateSalt(),1000);
SharedPreferences securePrefs1000 = new SecurePreferences(this, myKey, "my_prefs_1000.xml");
return securePrefs1000;
} catch (GeneralSecurityException e) {
Log.e(TAG, "Failed to create custom key for SecurePreferences", e);
}
return null;
}
public SharedPreferences getDefaultSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(this);
}
public SecurePreferences getUserPinBasedSharedPreferences(String password){
if(mUserPrefs==null) {
mUserPrefs = new SecurePreferences(this, password, "user_prefs.xml");
}
return mUserPrefs;
}
public boolean changeUserPrefPassword(String newPassword){
if(mUserPrefs!=null){
try {
mUserPrefs.handlePasswordChange(newPassword, this);
return true;
} catch (GeneralSecurityException e) {
Log.e(TAG, "Error during password change", e);
}
}
return false;
}
}
And then you must get the SecurePreferences in your activity in this way:
SharedPreferences preferences =App.get().getSharedPreferences();
Upvotes: 1
Views: 4162
Reputation: 812
You have to make your own algorithm for security
I have this class
public class AESEncryption {
private static final int KEY_SIZE = 128;
private static final String KEY_GENERATOR_ALGORITHM = "AES";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
public static final byte[] iv = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
private static SecretKey getSecretKey(Context context) throws NoSuchAlgorithmException {
String secretKeyString = PreferenceUtils.getSharedPreferences(context).getString(PreferenceUtils.SECRET_KEY, null);
if (secretKeyString != null) {
byte[] bytes = Base64.decode(secretKeyString, Base64.DEFAULT);
return new SecretKeySpec(bytes, AESEncryption.KEY_GENERATOR_ALGORITHM);
} else {
SecretKey secretKey = newSecretKey();
secretKeyString = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT);
PreferenceUtils.getSharedPreferences(context).edit().putString(PreferenceUtils.SECRET_KEY, secretKeyString).commit();
return secretKey;
}
}
private static SecretKey newSecretKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
keyGenerator.init(KEY_SIZE);
return keyGenerator.generateKey();
}
public static String encrypt(Context context, String data) {
try {
SecretKey secretKey = getSecretKey(context);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
byte[] transformedBytes = cipher.doFinal(data.getBytes());
return Base64.encodeToString(transformedBytes, Base64.DEFAULT);
} catch(NoSuchAlgorithmException e) {
return data;
} catch(NoSuchPaddingException e){
return data;
} catch (InvalidKeyException e) {
return data;
} catch(IllegalBlockSizeException e) {
return data;
} catch(BadPaddingException e) {
return data;
} catch(InvalidAlgorithmParameterException e) {
return data;
}
}
public static String decrypt(Context context, String data) {
byte[] bytes = null;
try {
bytes = Base64.decode(data, Base64.DEFAULT);
} catch(IllegalArgumentException e) {
return data;
}
try {
SecretKey secretKey = getSecretKey(context);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
return new String(cipher.doFinal(bytes));
} catch(NoSuchAlgorithmException e){
return data;
} catch(NoSuchPaddingException e) {
return data;
} catch(IllegalBlockSizeException e) {
return data;
} catch(BadPaddingException e) {
return data;
} catch(InvalidKeyException e) {
return data;
} catch(InvalidAlgorithmParameterException e) {
return data;
}
}
}
then after when we save or get data from shared preference we simply use below //get data
public static String getUser(Context context) {
String encryptedUser = getSharedPreferences(context).getString(USERNAME, null);
return encryptedUser != null ? AESEncryption.decrypt(context, encryptedUser) : null;
}
//save data
public static void setLoginUser(Context context, String user, String password, String nickname) {
String encryptedUser = AESEncryption.encrypt(context, user);
String encryptedPassword = AESEncryption.encrypt(context, password);
getSharedPreferences(context).edit().putString(USERNAME, encryptedUser).putString(PASSWORD, encryptedPassword)
.putString(NICKNAME, nickname).commit();
}
you may change your own key or logic foe algo.
thank you
Upvotes: 0
Reputation: 660
You might wanna try https://prashantsolanki3.github.io/Secure-Pref-Manager/ for easy and secure shared preferences. You can use the given AES encryption or implement your own encryption algorithm.
Sample Code to Add a new Preference:
SecurePrefManager.with(this)
.set("user_name")
.value("LoremIpsum")
.go();
Upvotes: 2