diegocom
diegocom

Reputation: 338

Secure shared preference android

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

Answers (2)

Adil
Adil

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

Prashant Solanki
Prashant Solanki

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

Related Questions