MobileHub where to store API keys - android

I am building an app based on the mobile hub sample app. The sample-app has the API keys stored in a class file AWSconfiguration:
public class AWSConfiguration {
// AWS MobileHub user agent string
public static final String AWS_MOBILEHUB_USER_AGENT =
"MobileHub ********* aws-my-sample-app-android-v0.16";
// AMAZON COGNITO
public static final Regions AMAZON_COGNITO_REGION =
Regions.fromName("us-east-1");
public static String AMAZON_COGNITO_IDENTITY_POOL_ID = "us-east-************6";
// Google Client ID for Web application
public static String GOOGLE_CLIENT_ID ="";//"*********************.apps.googleusercontent.com";
public static final Regions AMAZON_DYNAMODB_REGION =
Regions.fromName("us-east-1");
public static String AMAZON_COGNITO_USER_POOL_ID = "************";
public static String AMAZON_COGNITO_USER_POOL_CLIENT_ID = "*************";
public static String AMAZON_COGNITO_USER_POOL_CLIENT_SECRET = "*************";
private static final AWSMobileHelperConfiguration helperConfiguration = new AWSMobileHelperConfiguration.Builder()
.withCognitoRegion(AMAZON_COGNITO_REGION)
.withCognitoIdentityPoolId(AMAZON_COGNITO_IDENTITY_POOL_ID)
.withCognitoUserPool(AMAZON_COGNITO_USER_POOL_ID,
AMAZON_COGNITO_USER_POOL_CLIENT_ID, AMAZON_COGNITO_USER_POOL_CLIENT_SECRET)
.build();
/**
* #return the configuration for AWSKit.
*/
public static AWSMobileHelperConfiguration getAWSMobileHelperConfiguration() {
return helperConfiguration;
}
}
It seems unsafe to store the client secret key this way. What are the risks?
I experiemnted with hiding the keys in JNI files but could not find the proper entry point in the activity to set the keys before they are called from the mobile helper.

Storing in clear text is generally a bad idea, as you guessed. You could use the android keystore, store it encrypted (the stronger the key, the better), obfuscate it with some unique identifier of your device, or access it via some API you control and secure. It's possible to use some other solution, or a combination of the above possibilities. The final decision comes down to you and what your app needs/abilities are, but there's a few ways to hide it.

SharedPreferences.Editor can be a solution.
Password or something like this are stored in SharedPreferences.

Related

unable to send a notification to myself

After I followed all the steps for the push notification sample app. I wasn't able to send a notifaction to myself. I could send a pushmessage from my PC to my phone, but when I use the button Send myself a Notification nothing happens.
I am using Android sdk
After starting the app I do see that my Device is Registerd
Here is my settings.java
package com.ganyo.pushtest;
/** Change these values to match your setup! */
public class Settings {
static final String UNASSIGNED_ORG_VALUE = "";
// Google Client Id from Google API Console
static final String GCM_SENDER_ID = "xxxxxxxxxxxxx";
// Notifier Name in App Services
static final String NOTIFIER = "androidDev";
static final String API_URL = "https://api.usergrid.com";
static final String ORG = "xxxxxxx";
static final String APP = "sandbox";
// set these if you want to use a user login
static final String USER = null;
static final String PASSWORD = null;
}
I'm not sure what the UNASSIGNED_ORG_VALUE should be.
Thx in advance.
No need to assign any value to UNASSIGNED_ORG_VALUE. It's only used to check that you've entered the other values.
Please check your Android logs as well as the Apigee Console to see what error messages might have been generated during your push attempt. This will help you debug the issue.
Finally, you could try providing your notifier name here in all lowercase. (Note: This shouldn't generally be necessary, but I've heard there may be a issue that affects notifier name resolution.)

Change eBay search from US to UK

I am trying to change the search site that my eBay Android app searches in. At the moment, it searches the US site, but I would like it to search the UK site.
Here's my findingServiceClient class that I'm trying to make search the UK site, with the country code 3(UK, source).
As far as I can see I have set my code up to search the UK site, but it still seems to search the US.
any help would be appreciated, thanks.
public class FindingServiceClient {
// production
public static String eBayFindingServiceURLString = "http://svcs.ebay.com/services/search/FindingService/v1";
// sandbox
//public static String eBayFindingServiceURLString = "https://svcs.sandbox.ebay.com/services/search/FindingService/v1";
public static String eBayAppId = "ebay_app_id";
private static volatile FindingServicePortType_SOAPClient client = null;
public static String targetSiteid = "3";
public static FindingServicePortType_SOAPClient getSharedClient() {
if (client == null) {
synchronized(FindingServiceClient.class) {
if (client == null) {
client = new FindingServicePortType_SOAPClient();
client.setEndpointUrl(eBayFindingServiceURLString);
client.setSoapVersion(SOAPVersion.SOAP12); // ebay finding service supports SOAP 1.2
client.setContentType("application/soap+xml");
client.getAsyncHttpClient().addHeader("X-EBAY-API-SITE-ID", targetSiteid);
client.getAsyncHttpClient().addHeader("Accept", "application/soap+xml");
client.getAsyncHttpClient().addHeader("X-EBAY-SOA-SECURITY-APPNAME", eBayAppId);
client.getAsyncHttpClient().addHeader("X-EBAY-SOA-MESSAGE-PROTOCOL", "SOAP12");
client.getAsyncHttpClient().addHeader("X-EBAY-SOA-REQUEST-DATA-FORMAT", "SOAP");
}
}
}
return client;
}
}
The site that is searched is specified in the HTTP header X-EBAY-SOA-GLOBAL-ID. The value of this header is not a unique integer, such as 3, but a unique string, such as EBAY-US. To search the UK site you need to make the two below changes to your code and remove any reference to X-EBAY-API-SITE-ID.
public static String targetSiteid = "EBAY-GB";
client.getAsyncHttpClient().addHeader("X-EBAY-SOA-GLOBAL-ID", targetSiteid);
The eBay docs provide a complete list of HTTP headers and a table of site IDs mapped to global IDs.

How to connect an Android Chat Application to Openfire server

I am trying to connect an Android chat app in Eclipse to my own Openfire server. The code I am using is from the Samsung developers site (http://developer.samsung.com/android/technical-docs/Building-a-Chat-Application) and I am having difficulty in connecting the app to my server.
The problem comes from declaring the connections:
public static final String HOST = "talk.google.com";
public static final int PORT = 5222;
public static final String SERVICE = "gmail.com";
public static final String USERNAME = "userid#gmail.com";
public static final String PASSWORD = "password";
This is the example provided by the site, but I am unsure of what the fields should contain if I am using my own openfire server, as opposed to the example above. If someone could give an example of what I should do to connect to my own server, I would really appreciate it.
Thank you for your time.

What are the response codes (values) returned by the Google Play server in a license response?

I want to cater for LICENSE_OLD_KEY in my android license policy.
I was going to modify the ServerManagedPolicy as it doesn't cater for this, as far as I can tell, it just seems to look for Policy.LICENSED or Policy.NOT_LICENSED in processServerResponse method:
public void processServerResponse(int response, ResponseData rawData) {
// Update retry counter
if (response != Policy.RETRY) {
setRetryCount(0);
} else {
setRetryCount(mRetryCount + 1);
}
if (response == Policy.LICENSED) {
// Update server policy data
Map<String, String> extras = decodeExtras(rawData.extra);
mLastResponse = response;
setValidityTimestamp(extras.get("VT"));
setRetryUntil(extras.get("GT"));
setMaxRetries(extras.get("GR"));
} else if (response == Policy.NOT_LICENSED) {
// Clear out stale policy data
setValidityTimestamp(DEFAULT_VALIDITY_TIMESTAMP);
setRetryUntil(DEFAULT_RETRY_UNTIL);
setMaxRetries(DEFAULT_MAX_RETRIES);
}
setLastResponse(response);
mPreferences.commit();
}
I'd like to know what the response code is for LICENSE_OLD_KEY because that doesn't exist in Policy:
public static final int LICENSED = 0x0100;
public static final int NOT_LICENSED = 0x0231;
public static final int RETRY = 0x0123;
I had a look here, but I can't find anywhere that lists the name and values.
I can see that there are a list of server response codes in LicenseValidator but they don't match up to those in Policy:
// Server response codes.
private static final int LICENSED = 0x0;
private static final int NOT_LICENSED = 0x1;
private static final int LICENSED_OLD_KEY = 0x2;
private static final int ERROR_NOT_MARKET_MANAGED = 0x3;
private static final int ERROR_SERVER_FAILURE = 0x4;
private static final int ERROR_OVER_QUOTA = 0x5;
private static final int ERROR_CONTACTING_SERVER = 0x101;
private static final int ERROR_INVALID_PACKAGE_NAME = 0x102;
private static final int ERROR_NON_MATCHING_UID = 0x103;
Giving it some thought I decided to try displaying the reason codes returned by the Google Play server on my phone, using AlertDialog's. Here is what I found:
Selecting LICENSED, in the Developer console profile, returned the number 256, as per Policy.LICENSED.
Selecting NOT_LICENSED returned the number 561, again as per Policy.NOT_LICENSED.
Finally selecting LICENSED_OLD_KEY returned the number 256, which is the same as Policy.LICENSED.
So it would seem that LICENSED_OLD_KEY is no longer used, or rather there is no distinction between LICENSED and LICENSED_OLD_KEY. Which is a bit confusing given the information that google provide in their documentation here.
Just to note, I did try uninstalling my app and selecting the different options in the developer console a few times, but it always resulted in the same answer!
The code you're looking at is only a reference implementation. It can't know how you would want to deal with a LICENSED_OLD_KEY situation in detail. The documentation suggests you might want to limit access to the current app, or to your server data from the current app, and ask the user to update and use the latest version. There's nothing much a reference implementation can provide to enable you to deal with all these situations. You can and should modify the code to treat LICENSED_OLD_KEY separately.
There's no indication for LICENSED_OLD_KEY "not being used anymore" because it's still handled as a server response in LicenseValidator.java and "OLD_KEY" refers to an older version of your app, not an older version of Google Play server handling.

user credentials on android [duplicate]

I am creating an application which connects to the server using username/password and I would like to enable the option "Save password" so the user wouldn't have to type the password each time the application starts.
I was trying to do it with Shared Preferences but am not sure if this is the best solution.
I would appreciate any suggestion on how to store user values/settings in Android application.
In general SharedPreferences are your best bet for storing preferences, so in general I'd recommend that approach for saving application and user settings.
The only area of concern here is what you're saving. Passwords are always a tricky thing to store, and I'd be particularly wary of storing them as clear text. The Android architecture is such that your application's SharedPreferences are sandboxed to prevent other applications from being able to access the values so there's some security there, but physical access to a phone could potentially allow access to the values.
If possible I'd consider modifying the server to use a negotiated token for providing access, something like OAuth. Alternatively you may need to construct some sort of cryptographic store, though that's non-trivial. At the very least, make sure you're encrypting the password before writing it to disk.
I agree with Reto and fiXedd. Objectively speaking it doesn't make a lot of sense investing significant time and effort into encrypting passwords in SharedPreferences since any 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.
However, that being said, there does seem to be a publicity initiative going on identifying mobile applications that store their passwords in cleartext in SharedPreferences and shining unfavorable light on those applications. See http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ and http://viaforensics.com/appwatchdog for some examples.
While we need more attention paid to security in general, I would argue that this sort of attention on this one particular issue doesn't actually significantly increase our overall security. However, perceptions being as they are, here's a solution to encrypt the data you place in SharedPreferences.
Simply wrap your own SharedPreferences object in this one, and any data you read/write will be automatically encrypted and decrypted. eg.
final SharedPreferences prefs = new ObscuredSharedPreferences(
this, this.getSharedPreferences(MY_PREFS_FILE_NAME, Context.MODE_PRIVATE) );
// eg.
prefs.edit().putString("foo","bar").commit();
prefs.getString("foo", null);
Here's the code for the class:
/**
* Warning, this gives a false sense of security. If an attacker has enough access to
* acquire your password store, then he almost certainly has enough access to acquire your
* source binary and figure out your encryption key. However, it will prevent casual
* investigators from acquiring passwords, and thereby may prevent undesired negative
* publicity.
*/
public class ObscuredSharedPreferences implements SharedPreferences {
protected static final String UTF8 = "utf-8";
private static final char[] SEKRIT = ... ; // INSERT A RANDOM PASSWORD HERE.
// Don't use anything you wouldn't want to
// get out there if someone decompiled
// your app.
protected SharedPreferences delegate;
protected Context context;
public ObscuredSharedPreferences(Context context, SharedPreferences delegate) {
this.delegate = delegate;
this.context = context;
}
public class Editor implements SharedPreferences.Editor {
protected SharedPreferences.Editor delegate;
public Editor() {
this.delegate = ObscuredSharedPreferences.this.delegate.edit();
}
#Override
public Editor putBoolean(String key, boolean value) {
delegate.putString(key, encrypt(Boolean.toString(value)));
return this;
}
#Override
public Editor putFloat(String key, float value) {
delegate.putString(key, encrypt(Float.toString(value)));
return this;
}
#Override
public Editor putInt(String key, int value) {
delegate.putString(key, encrypt(Integer.toString(value)));
return this;
}
#Override
public Editor putLong(String key, long value) {
delegate.putString(key, encrypt(Long.toString(value)));
return this;
}
#Override
public Editor putString(String key, String value) {
delegate.putString(key, encrypt(value));
return this;
}
#Override
public void apply() {
delegate.apply();
}
#Override
public Editor clear() {
delegate.clear();
return this;
}
#Override
public boolean commit() {
return delegate.commit();
}
#Override
public Editor remove(String s) {
delegate.remove(s);
return this;
}
}
public Editor edit() {
return new Editor();
}
#Override
public Map<String, ?> getAll() {
throw new UnsupportedOperationException(); // left as an exercise to the reader
}
#Override
public boolean getBoolean(String key, boolean defValue) {
final String v = delegate.getString(key, null);
return v!=null ? Boolean.parseBoolean(decrypt(v)) : defValue;
}
#Override
public float getFloat(String key, float defValue) {
final String v = delegate.getString(key, null);
return v!=null ? Float.parseFloat(decrypt(v)) : defValue;
}
#Override
public int getInt(String key, int defValue) {
final String v = delegate.getString(key, null);
return v!=null ? Integer.parseInt(decrypt(v)) : defValue;
}
#Override
public long getLong(String key, long defValue) {
final String v = delegate.getString(key, null);
return v!=null ? Long.parseLong(decrypt(v)) : defValue;
}
#Override
public String getString(String key, String defValue) {
final String v = delegate.getString(key, null);
return v != null ? decrypt(v) : defValue;
}
#Override
public boolean contains(String s) {
return delegate.contains(s);
}
#Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
delegate.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
}
#Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
delegate.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
}
protected String encrypt( String value ) {
try {
final byte[] bytes = value!=null ? value.getBytes(UTF8) : new byte[0];
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID).getBytes(UTF8), 20));
return new String(Base64.encode(pbeCipher.doFinal(bytes), Base64.NO_WRAP),UTF8);
} catch( Exception e ) {
throw new RuntimeException(e);
}
}
protected String decrypt(String value){
try {
final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0];
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID).getBytes(UTF8), 20));
return new String(pbeCipher.doFinal(bytes),UTF8);
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
About the simplest way to store a single preference in an Android Activity is to do something like this:
Editor e = this.getPreferences(Context.MODE_PRIVATE).edit();
e.putString("password", mPassword);
e.commit();
If you're worried about the security of these then you could always encrypt the password before storing it.
Using the snippet provided by Richard, you can encrypt the password before saving it. The preferences API however doesn't provide an easy way to intercept the value and encrypt it - you can block it being saved via an OnPreferenceChange listener, and you theoretically could modify it through a preferenceChangeListener, but that results in an endless loop.
I had earlier suggested adding a "hidden" preference in order to accomplish this. It's definitely not the best way. I'm going to present two other options that I consider to be more viable.
First, the simplest, is in a preferenceChangeListener, you can grab the entered value, encrypt it, and then save it to an alternative preferences file:
public boolean onPreferenceChange(Preference preference, Object newValue) {
// get our "secure" shared preferences file.
SharedPreferences secure = context.getSharedPreferences(
"SECURE",
Context.MODE_PRIVATE
);
String encryptedText = null;
// encrypt and set the preference.
try {
encryptedText = SimpleCrypto.encrypt(Preferences.SEED,(String)newValue);
Editor editor = secure.getEditor();
editor.putString("encryptedPassword",encryptedText);
editor.commit();
}
catch (Exception e) {
e.printStackTrace();
}
// always return false.
return false;
}
The second way, and the way I now prefer, is to create your own custom preference, extending EditTextPreference, #Override'ing the setText() and getText() methods, so that setText() encrypts the password, and getText() returns null.
Okay; it's been a while since the answer is kind-of mixed, but here's a few common answers. I researched this like crazy and it was hard to build a good answer
The MODE_PRIVATE method is considered generally safe, if you assume that the user didn't root the device. Your data is stored in plain text in a part of the file system that can only be accessed by the original program. This makings grabbing the password with another app on a rooted device easy. Then again, do you want to support rooted devices?
AES is still the best encryption you can do. Remember to look this up if you are starting a new implementation if it's been a while since I posted this. The largest issue with this is "What to do with the encryption key?"
So, now we are at the "What to do with the key?" portion. This is the hard part. Getting the key turns out to be not that bad. You can use a key derivation function to take some password and make it a pretty secure key. You do get into issues like "how many passes do you do with PKFDF2?", but that's another topic
Ideally, you store the AES key off the device. You have to figure out a good way to retrieve the key from the server safely, reliably, and securely though
You have a login sequence of some sort (even the original login sequence you do for remote access). You can do two runs of your key generator on the same password. How this works is that you derive the key twice with a new salt and a new secure initialization vector. You store one of those generated passwords on the device, and you use the second password as the AES key.
When you log in, you re-derive the key on the local login and compare it to the stored key. Once that is done, you use derive key #2 for AES.
Using the "generally safe" approach, you encrypt the data using AES and store the key in MODE_PRIVATE. This is recommended by a recent-ish Android blog post. Not incredibly secure, but way better for some people over plain text
You can do a lot of variations of these. For example, instead of a full login sequence, you can do a quick PIN (derived). The quick PIN might not be as secure as a full login sequence, but it's many times more secure than plain text
I know this is a little bit of necromancy, but you should use the Android AccountManager. It's purpose-built for this scenario. It's a little bit cumbersome but one of the things it does is invalidate the local credentials if the SIM card changes, so if somebody swipes your phone and throws a new SIM in it, your credentials won't be compromised.
This also gives the user a quick and easy way to access (and potentially delete) the stored credentials for any account they have on the device, all from one place.
SampleSyncAdapter is an example that makes use of stored account credentials.
I'll throw my hat into the ring just to talk about securing passwords in general on Android. On Android, the device binary should be considered compromised - this is the same for any end application which is in direct user control. Conceptually, a hacker could use the necessary access to the binary to decompile it and root out your encrypted passwords and etc.
As such there's two suggestions I'd like to throw out there if security is a major concern for you:
1) Don't store the actual password. Store a granted access token and use the access token and the signature of the phone to authenticate the session server-side. The benefit to this is that you can make the token have a limited duration, you're not compromising the original password and you have a good signature that you can use to correlate to traffic later (to for instance check for intrusion attempts and invalidate the token rendering it useless).
2) Utilize 2 factor authentication. This may be more annoying and intrusive but for some compliance situations unavoidable.
This is a supplemental answer for those arriving here based on the question title (like I did) and don't need to deal with the security issues related to saving passwords.
How to use Shared Preferences
User settings are generally saved locally in Android using SharedPreferences with a key-value pair. You use the String key to save or look up the associated value.
Write to Shared Preferences
String key = "myInt";
int valueToSave = 10;
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(key, valueToSave).commit();
Use apply() instead of commit() to save in the background rather than immediately.
Read from Shared Preferences
String key = "myInt";
int defaultValue = 0;
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
int savedValue = sharedPref.getInt(key, defaultValue);
The default value is used if the key isn't found.
Notes
Rather than using a local key String in multiple places like I did above, it would be better to use a constant in a single location. You could use something like this at the top of your settings activity:
final static String PREF_MY_INT_KEY = "myInt";
I used an int in my example, but you can also use putString(), putBoolean(), getString(), getBoolean(), etc.
See the documentation for more details.
There are multiple ways to get SharedPreferences. See this answer for what to look out for.
You can also check out this little lib, containing the functionality you mention.
https://github.com/kovmarci86/android-secure-preferences
It is similar to some of the other aproaches here. Hope helps :)
This answer is based on a suggested approach by Mark. A custom version of the EditTextPreference class is created which converts back and forth between the plain text seen in the view and an encrypted version of the password stored in the preferences storage.
As has been pointed out by most who have answered on this thread, this is not a very secure technique, although the degree of security depends partly on the encryption/decryption code used. But it's fairly simple and convenient, and will thwart most casual snooping.
Here is the code for the custom EditTextPreference class:
package com.Merlinia.OutBack_Client;
import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.util.Base64;
import com.Merlinia.MEncryption_Main.MEncryptionUserPassword;
/**
* This class extends the EditTextPreference view, providing encryption and decryption services for
* OutBack user passwords. The passwords in the preferences store are first encrypted using the
* MEncryption classes and then converted to string using Base64 since the preferences store can not
* store byte arrays.
*
* This is largely copied from this article, except for the encryption/decryption parts:
* https://groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M
*/
public class EditPasswordPreference extends EditTextPreference {
// Constructor - needed despite what compiler says, otherwise app crashes
public EditPasswordPreference(Context context) {
super(context);
}
// Constructor - needed despite what compiler says, otherwise app crashes
public EditPasswordPreference(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
// Constructor - needed despite what compiler says, otherwise app crashes
public EditPasswordPreference(Context context, AttributeSet attributeSet, int defaultStyle) {
super(context, attributeSet, defaultStyle);
}
/**
* Override the method that gets a preference from the preferences storage, for display by the
* EditText view. This gets the base64 password, converts it to a byte array, and then decrypts
* it so it can be displayed in plain text.
* #return OutBack user password in plain text
*/
#Override
public String getText() {
String decryptedPassword;
try {
decryptedPassword = MEncryptionUserPassword.aesDecrypt(
Base64.decode(getSharedPreferences().getString(getKey(), ""), Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
decryptedPassword = "";
}
return decryptedPassword;
}
/**
* Override the method that gets a text string from the EditText view and stores the value in
* the preferences storage. This encrypts the password into a byte array and then encodes that
* in base64 format.
* #param passwordText OutBack user password in plain text
*/
#Override
public void setText(String passwordText) {
byte[] encryptedPassword;
try {
encryptedPassword = MEncryptionUserPassword.aesEncrypt(passwordText);
} catch (Exception e) {
e.printStackTrace();
encryptedPassword = new byte[0];
}
getSharedPreferences().edit().putString(getKey(),
Base64.encodeToString(encryptedPassword, Base64.DEFAULT))
.commit();
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue)
getEditText().setText(getText());
else
super.onSetInitialValue(restoreValue, defaultValue);
}
}
This shows how it can be used - this is the "items" file that drives the preferences display. Note it contains three ordinary EditTextPreference views and one of the custom EditPasswordPreference views.
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference
android:key="#string/useraccountname_key"
android:title="#string/useraccountname_title"
android:summary="#string/useraccountname_summary"
android:defaultValue="#string/useraccountname_default"
/>
<com.Merlinia.OutBack_Client.EditPasswordPreference
android:key="#string/useraccountpassword_key"
android:title="#string/useraccountpassword_title"
android:summary="#string/useraccountpassword_summary"
android:defaultValue="#string/useraccountpassword_default"
/>
<EditTextPreference
android:key="#string/outbackserverip_key"
android:title="#string/outbackserverip_title"
android:summary="#string/outbackserverip_summary"
android:defaultValue="#string/outbackserverip_default"
/>
<EditTextPreference
android:key="#string/outbackserverport_key"
android:title="#string/outbackserverport_title"
android:summary="#string/outbackserverport_summary"
android:defaultValue="#string/outbackserverport_default"
/>
</PreferenceScreen>
As for the actual encryption/decryption, that is left as an exercise for the reader. I'm currently using some code based on this article http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/, although with different values for the key and the initialization vector.
First of all I think User's data shouldn't be stored on phone, and if it is must to store data somewhere on the phone it should be encrypted with in the apps private data. Security of users credentials should be the priority of the application.
The sensitive data should be stored securely or not at all. In the event of a lost device or malware infection, data stored insecurely can be compromised.
I use the Android KeyStore to encrypt the password using RSA in ECB mode and then save it in the SharedPreferences.
When I want the password back I read the encrypted one from the SharedPreferences and decrypt it using the KeyStore.
With this method you generate a public/private Key-pair where the private one is safely stored and managed by Android.
Here is a link on how to do this: Android KeyStore Tutorial
As others already pointed out you can use SharedPreferences generally but if you would like to store data encrypted it's a bit inconvenient. Fortunately, there is an easier and quicker way to encrypt data now since there is an implementation of SharedPreferences that encrypts keys and values. You can use EncryptedSharedPreferences in Android JetPack Security.
Just add AndroidX Security into your build.gradle:
implementation 'androidx.security:security-crypto:1.0.0-rc01'
And you can use it like this:
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
// use the shared preferences and editor as you normally would
SharedPreferences.Editor editor = sharedPreferences.edit();
See more details: https://android-developers.googleblog.com/2020/02/data-encryption-on-android-with-jetpack.html
Official docs: https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences
This is how I am doing it.
This does not give errors in strict mode.
public class UserPreferenceUtil
{
private static final String THEME = "THEME";
private static final String LANGUAGE = "LANGUAGE";
public static String getLanguagePreference(Context context)
{
String lang = getPreferenceByKey(context,LANGUAGE);
if( lang==null || "System".equalsIgnoreCase(lang))
{
return null;
}
return lang;
}
public static void saveLanguagePreference(Context context,String value)
{
savePreferenceKeyValue(context, LANGUAGE,value);
}
public static String getThemePreference(Context context)
{
return getPreferenceByKey(context,THEME);
}
public static void saveThemePreference(Context context, String value)
{
savePreferenceKeyValue(context,THEME,value);
}
public static String getPreferenceByKey(Context context, String preferenceKey )
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String value = sharedPreferences.getString(preferenceKey, null);
return value;
}
private static void savePreferenceKeyValue(Context context, String preferenceKey, String value)
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(preferenceKey,value);
editor.apply();
}
}
My app does not need a password. However, rather than saving passwords or encrypted passwords, I would save a one-way hash. When the user logs in, I will hash the input the same way and match it with the stored hash.
you need to use the sqlite, security apit to store the passwords.
here is best example, which stores passwords, -- passwordsafe.
here is link for the source and explanation --
http://code.google.com/p/android-passwordsafe/
shared preferences is easiest way to store our application data. but it is possible that anyone can clear our shared preferences data through application manager.so i don't think it is completely safe for our application.

Categories

Resources