Encryption Wrapper for Android SharedPreferences
Danabr - 27/Mar/2013
Danabr - 27/Mar/2013
[SHOWTOGROUPS=4,20]
This article explains why and how you should protect your app's settings from prying eyes
This article presents a wrapper class for Android's Для просмотра ссылки Войдиили Зарегистрируйся interface, which adds a layer of encryption to the persistent storage and retrieval of sensitive key-value pairs of primitive data types.
Why should you care about this as an Android developer? Read on...
Background
Android's Для просмотра ссылки Войдиили Зарегистрируйся interface provides a general framework that allows you to access and modify key-value pairs of primitive data types (booleans, numbers, strings, and more). This data persists across user sessions, even if your application is killed. For more information, see the Для просмотра ссылки Войди или Зарегистрируйся and the Для просмотра ссылки Войди или Зарегистрируйся.
By default, Android stores this data in an unencrypted XML file within the app's directory on the device's filesystem, with permissions that allow only the app to access this file. This is part of the concept known as "Для просмотра ссылки Войдиили Зарегистрируйся". So the data is private and protected, right? Well, not quite.
If the Android device is rooted, other apps (with root privileges) can read/download/modify this file (as well as the entire filesystem). Worse still, even if the device is unrooted but attackers gain physical access to it, they might be able to download all the data from it, for example with the Для просмотра ссылки Войдиили Зарегистрируйся. See the Для просмотра ссылки Войди или Зарегистрируйся for more information.
So what can you do? Encrypt the data! This way, even if attackers gain access to it, it will remain unreadable and unmodifiable. The class presented below provides an easy and generic solution for this, based on Google's recommendations in the Для просмотра ссылки Войдиили Зарегистрируйся.
Using the code
As you may already know, there are 3 methods to initialize a Для просмотра ссылки Войдиили Зарегистрируйся object:
или Зарегистрируйся object and uses the 3rd approach internally, so instead of the above you should do the following (where this is your app's Для просмотра ссылки Войди или Зарегистрируйся, Для просмотра ссылки Войди или Зарегистрируйся, etc.):
For now, this class does not have a constructor which accepts an existing Для просмотра ссылки Войдиили Зарегистрируйся object for wrapping. The reasons for this safety measure are specified in the "Attention" section below, but future versions of this article may provide additional constructors.
By the way, the constructor also initializes the encryption/decryption key in memory.
That's it! Other than that, you use this class just like a regular Для просмотра ссылки Войдиили Зарегистрируйся object. The only difference is that this class transparently encrypts and decrypts the keys and the values that you provide.
For example, here is how you can get and set a string:
And here is the implementation of these calls:
Lastly, FYI:
The "Background" section above explained the "Для просмотра ссылки Войдиили Зарегистрируйся" concept, which provides some privacy by default. It's important to understand the details of this default behavior, so it won't be changed inadvertently and weaken your app's security:
As written by Michael Burton (a.k.a. emmby) in Для просмотра ссылки Войдиили Зарегистрируйся:
A suggestion from the Для просмотра ссылки Войдиили Зарегистрируйся web page, in case your sensitive data is user credentials:
или Зарегистрируйся, for general sensitive data:
или Зарегистрируйся:
This way, even if the device falls into the wrong hands, the only way to hack the data would be with brute-force attacks.
Points of Interest
This article dealt with Android Для просмотра ссылки Войдиили Зарегистрируйся. If you want to encrypt Для просмотра ссылки Войди или Зарегистрируйся, you can check out Для просмотра ссылки Войди или Зарегистрируйся.
History
License
This article, along with any associated source code and files, is licensed under Для просмотра ссылки Войдиили Зарегистрируйся
[/SHOWTOGROUPS]
This article explains why and how you should protect your app's settings from prying eyes
- Для просмотра ссылки Войди
или Зарегистрируйся - Для просмотра ссылки Войди
или Зарегистрируйся
This article presents a wrapper class for Android's Для просмотра ссылки Войди
Why should you care about this as an Android developer? Read on...
Background
Android's Для просмотра ссылки Войди
By default, Android stores this data in an unencrypted XML file within the app's directory on the device's filesystem, with permissions that allow only the app to access this file. This is part of the concept known as "Для просмотра ссылки Войди
If the Android device is rooted, other apps (with root privileges) can read/download/modify this file (as well as the entire filesystem). Worse still, even if the device is unrooted but attackers gain physical access to it, they might be able to download all the data from it, for example with the Для просмотра ссылки Войди
So what can you do? Encrypt the data! This way, even if attackers gain access to it, it will remain unreadable and unmodifiable. The class presented below provides an easy and generic solution for this, based on Google's recommendations in the Для просмотра ссылки Войди
Using the code
As you may already know, there are 3 methods to initialize a Для просмотра ссылки Войди
- Для просмотра ссылки Войди
или Зарегистрируйся - Для просмотра ссылки Войди
или Зарегистрируйся - Для просмотра ссылки Войди
или Зарегистрируйся
Код:
SharedPreferences prefs = SecurePreferences(this);
For now, this class does not have a constructor which accepts an existing Для просмотра ссылки Войди
By the way, the constructor also initializes the encryption/decryption key in memory.
Код:
public class SecurePreferences implements SharedPreferences {
private static SharedPreferences sFile;
private static byte[] sKey;
/**
* Constructor.
*
* @param context the caller's context
*/
public SecurePreferences(Context context) {
// Proxy design pattern
if (SecurePreferences.sFile == null) {
SecurePreferences.sFile = PreferenceManager.getDefaultSharedPreferences(context);
}
// Initialize encryption/decryption key
try {
final String key = SecurePreferences.generateAesKeyName(context);
String value = SecurePreferences.sFile.getString(key, null);
if (value == null) {
value = SecurePreferences.generateAesKeyValue();
SecurePreferences.sFile.edit().putString(key, value).commit();
}
SecurePreferences.sKey = SecurePreferences.decode(value);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
...
}
That's it! Other than that, you use this class just like a regular Для просмотра ссылки Войди
For example, here is how you can get and set a string:
Код:
String value = prefs.getString("myKey", "defaultValue");
prefs.edit().putString("myKey", "myValue").commit();
And here is the implementation of these calls:
Код:
@Override
public String getString(String key, String defaultValue) {
final String encryptedValue =
SecurePreferences.sFile.getString(SecurePreferences.encrypt(key), null);
return (encryptedValue != null) ? SecurePreferences.decrypt(encryptedValue) : defaultValue;
}
@Override
public SharedPreferences.Editor putString(String key, String value) {
mEditor.putString(SecurePreferences.encrypt(key), SecurePreferences.encrypt(value));
return this;
}
Lastly, FYI:
- This class requires API level 8 (Android 2.2, a.k.a. "Froyo") or greater
- The example above shows strings, but all the other data types of the Для просмотра ссылки Войди
или Зарегистрируйся interface are supported as well: boolean, float, int, long, and Set<String> - null and empty string values are not encrypted
The "Background" section above explained the "Для просмотра ссылки Войди
- The Для просмотра ссылки Войди
или Зарегистрируйся object instance should be initialized with the Для просмотра ссылки Войдиили Зарегистрируйся flag - The location of the Для просмотра ссылки Войди
или Зарегистрируйся object's persistent XML file should be in the device's internal storage, rather than on an SD card, since permissions aren't enforced on external storage
As written by Michael Burton (a.k.a. emmby) in Для просмотра ссылки Войди
Further ImprovementsAny attacker that has access to your preferences file is fairly likely to also have access to your application's binary, and therefore the keys to unencrypt the password.
A suggestion from the Для просмотра ссылки Войди
And another suggestion from the Для просмотра ссылки ВойдиWhere possible, username and password should not be stored on the device. Instead, perform initial authentication using the username and password supplied by the user, and then use a short-lived, service-specific authorization token.
And yet another suggestion from the Для просмотра ссылки ВойдиTo provide additional protection for sensitive data, you might choose to encrypt local files using a key that is not directly accessible to the application. For example, a key can be placed in a Для просмотра ссылки Войдиили Зарегистрируйся and protected with a user password that is not stored on the device.
In other words, an even safer approach would be to have a secret PIN/passphrase/password which is not stored on the device at all. Either the user provides it, or a remote and secure server (which would require internet connectivity and deeper security evaluation). This secret would be converted by the app to the encryption/decryption key.If your app needs additional encryption, a recommended approach is to require a passphase or PIN to access your application. This passphrase could be fed into PBKDF2 to generate the encryption key.
This way, even if the device falls into the wrong hands, the only way to hack the data would be with brute-force attacks.
Points of Interest
This article dealt with Android Для просмотра ссылки Войди
History
- 27 Mar 2013 - Added 2 new samples (integration with Android's PreferenceActivity and PreferenceFragment), added a few @TargetApi annotations in SecurePreferences.java, and fixed the getAll() method to ignore decryption failures in unencrypted key/value pairs
- 25 Feb 2013 - Initial revision
License
This article, along with any associated source code and files, is licensed under Для просмотра ссылки Войди
[/SHOWTOGROUPS]