CryptoSharedPreferences

A wrapper around SharedPreferences that encrypts / decrypts all shared preferences.

Warning - do not assume use of this class will prevent access to shared preferences. If an attacker has enough access to acquire your password store, they have enough access to acquire your source binary and figure out your encryption key.

However, this class will prevent casual investigators from acquiring passwords, and thereby may prevent undesired negative publicity.

Full disclosure: This code was adapted from Michael Burton's response on StackOverflow

To use you must extend the CryptoSharedPreferences abstract class and implement the getSpecialCode() method. Ideally this method would use either user input or an external source to get the password used to encrypt the shared preferences. The demo has the value hard-coded and is significantly less secure as a result.

The demo EncryptedPreferences object is shown below.

public class EncryptedPreferences extends CryptoSharedPreferences {

    public EncryptedPreferences(Context context, SharedPreferences delegate) {
        super(context, delegate);
    }

    /**
     * This should be replaced with a user input pass phrase or an externally
     * retrieved pass phrase if possible.
     *
     * @return
     */
    @Override
    protected char[] getSpecialCode() {
        return "THIS IS MY ENCRYPTING KEY PHRASE@@!".toCharArray();
    }

    @Override
    public Set<String> getStringSet(String s, Set<String> strings) {
        return null;
    }
}

The activity using the EncryptedPreferences object.

public class ObscuredPrefsActivity extends OakDemoActivity {

    private static final String MY_APP_PREFENCES_NAME = "my_app_prefences_name";

    private SharedPreferences mNormalSharedPreferences;
    private EncryptedPreferences mEncryptedPreferences;
    @InjectView(R.id.my_edittext) private EditText mEditText;
    @InjectView(R.id.saved_content) private TextView mTextView;
    @InjectView(R.id.saved_content_decrypted) private TextView mDecryptedText;
    @InjectView(R.id.saved_content_decrypted_desc) private TextView mDecryptedDesc;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.obscured_prefs_demo);

        mNormalSharedPreferences = getSharedPreferences(MY_APP_PREFENCES_NAME, MODE_PRIVATE);

        //EncryptedPreferences is defined by you and extends CryptoSharedPreferences
        mEncryptedPreferences = new EncryptedPreferences(this, mNormalSharedPreferences);
    }

    public void saveEncryptedClicked(View view) {
        //save input as encrypted
        mEncryptedPreferences.edit()
                .putString("first_name", mEditText.getText().toString())
                .commit();

        showRawContents(true);
    }

    public void saveNormallyClicked(View view) {
        //save unencrypted
        mNormalSharedPreferences.edit()
                .putString("first_name", mEditText.getText().toString())
                .commit();

        showRawContents(false);
    }

    private void showRawContents(boolean isEncrypted) {
        //demonstrate what could be viewed by a light-weight hacker
        mTextView.setText(mNormalSharedPreferences.getString("first_name", ""));

        //note: to read encrypted data, you would just use mEncryptedPreferences.getString(...
        if (isEncrypted) {
            mDecryptedDesc.setVisibility(View.VISIBLE);
            mDecryptedText.setText(mEncryptedPreferences.getString("first_name", ""));
            mDecryptedText.setVisibility(View.VISIBLE);
        } else {
            mDecryptedDesc.setVisibility(View.GONE);
            mDecryptedText.setVisibility(View.GONE);
        }
    }
}

Screenshot of demo activity.

Crypto Shared Preferences