আমি রেটো এবং ফিক্সএডডিতে সম্মত। উদ্দেশ্যমূলকভাবে বলতে গেলে এটি আপনার পছন্দসই ফাইলটিতে অ্যাক্সেস রয়েছে এমন যে কোনও আক্রমণকারী আপনার অ্যাপ্লিকেশনটির বাইনারি অ্যাক্সেস করার সম্ভাবনা বেশি তাই SharedPreferences মধ্যে পাসওয়ার্ড এনক্রিপ্ট করার জন্য উল্লেখযোগ্য সময় এবং প্রচেষ্টা ব্যয় করা প্রচুর অর্থবোধ করে না, এবং সেইজন্য এনক্রিপ্ট করার কীগুলি পাসওয়ার্ড।
যাইহোক, এটি বলা হচ্ছে, এমন একটি প্রচারমূলক উদ্যোগ এমন মোবাইল অ্যাপ্লিকেশনগুলি সনাক্ত করতে চলছে যা তাদের পাসওয়ার্ডগুলি শেরেডপ্রেরিফারেন্সে স্বচ্ছ টেক্সটে সংরক্ষণ করে এবং সেই অ্যাপ্লিকেশনগুলিতে প্রতিকূল আলোকিত করে তোলে। কিছু উদাহরণের জন্য http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ এবং http://viaforensics.com/appwatchdog দেখুন ।
যদিও সাধারণভাবে সুরক্ষায় আমাদের আরও মনোযোগ দেওয়া দরকার, তবুও আমি যুক্তি দিয়ে বলতে পারি যে এই একটি বিশেষ বিষয়ে এই ধরণের মনোযোগ আসলে আমাদের সামগ্রিক সুরক্ষা উল্লেখযোগ্যভাবে বাড়ায় না। যাইহোক, উপলব্ধিগুলি যেমন রয়েছে তেমনি, আপনি SharedPreferences এ থাকা ডেটা এনক্রিপ্ট করার একটি সমাধান এখানে here
কেবল এটির মধ্যে আপনার নিজের ভাগ করা পছন্দসই বিষয়টিকে আবদ্ধ করুন এবং আপনার পড়া / লেখার যে কোনও ডেটা স্বয়ংক্রিয়ভাবে এনক্রিপ্ট হবে এবং ডিক্রিপ্ট হবে। যেমন।
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);
ক্লাসের কোড এখানে:
/**
* 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);
}
}
}