diff --git a/lib/lib.iml b/lib/lib.iml index 20366dc..9f1fe54 100755 --- a/lib/lib.iml +++ b/lib/lib.iml @@ -23,7 +23,7 @@ - + @@ -50,13 +50,6 @@ - - - - - - - @@ -64,6 +57,13 @@ + + + + + + + @@ -71,13 +71,6 @@ - - - - - - - @@ -85,38 +78,28 @@ - + + + + + + + - - - - - - - - - - - - - - - - - + @@ -132,5 +115,6 @@ + \ No newline at end of file diff --git a/lib/src/main/java/com/github/hussainderry/securepreferences/SecurePreferences.java b/lib/src/main/java/com/github/hussainderry/securepreferences/SecurePreferences.java index 0fa49b5..d209d06 100755 --- a/lib/src/main/java/com/github/hussainderry/securepreferences/SecurePreferences.java +++ b/lib/src/main/java/com/github/hussainderry/securepreferences/SecurePreferences.java @@ -15,16 +15,17 @@ */ package com.github.hussainderry.securepreferences; +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Base64; + import com.github.hussainderry.securepreferences.crypto.Cryptor; import com.github.hussainderry.securepreferences.crypto.HashSHA; import com.github.hussainderry.securepreferences.model.SecurityConfig; import com.github.hussainderry.securepreferences.util.AsyncDataLoader; -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Base64; - import java.io.UnsupportedEncodingException; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -32,54 +33,55 @@ /** * @author Hussain Al-Derry * @version 1.0 - * */ -public final class SecurePreferences implements SharedPreferences{ + */ +public final class SecurePreferences implements SharedPreferences { private static final String CHARSET = "UTF-8"; - private final Cryptor mCryptor; + private Cryptor mCryptor; private SharedPreferences mProxyPreferences; + private SecurePreferences(Context context, String fileName, SecurityConfig securityConfig) { + this.mCryptor = Cryptor.initWithSecurityConfig(securityConfig); + this.mProxyPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); + } + /** * Creates an instance of the preferences using the provided security configurations. - * @param context The context to be used to create the instance - * @param filename The preferences filename + * + * @param context The context to be used to create the instance + * @param filename The preferences filename * @param securityConfig The security configurations to use * @return The SecurePreferences instance - * */ - public static SecurePreferences getInstance(Context context, String filename, SecurityConfig securityConfig){ - if(context == null || filename == null || securityConfig == null){ + */ + public static SecurePreferences getInstance(Context context, String filename, SecurityConfig securityConfig) { + if (context == null || filename == null || securityConfig == null) { throw new IllegalArgumentException("Params cannot be null!"); } return new SecurePreferences(context.getApplicationContext(), filename, securityConfig); } - private SecurePreferences(Context context, String fileName, SecurityConfig securityConfig) { - this.mCryptor = Cryptor.initWithSecurityConfig(securityConfig); - this.mProxyPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - } - - private String generateKeyHash(String key){ - try{ + private String generateKeyHash(String key) { + try { byte[] mBytes = HashSHA.hashUsingSHA256(key.getBytes(CHARSET)); return Base64.encodeToString(mBytes, Base64.NO_WRAP); - }catch(UnsupportedEncodingException e){ + } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e.getMessage()); } } - private String encryptToBase64(String data){ - try{ + private String encryptToBase64(String data) { + try { return mCryptor.encryptToBase64(data.getBytes(CHARSET)); - }catch(UnsupportedEncodingException e){ + } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e.getMessage()); } } - private String decryptFromBase64(String base64Data){ - try{ + private String decryptFromBase64(String base64Data) { + try { byte[] decrypted = mCryptor.decryptFromBase64(base64Data); return new String(decrypted, CHARSET); - }catch(UnsupportedEncodingException e){ + } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e.getMessage()); } } @@ -89,8 +91,27 @@ private String decryptFromBase64(String base64Data){ throw new UnsupportedOperationException("Operation Not Supported!"); } + public void changePassword(SecurityConfig securityConfig) { + final Map encryptedData = mProxyPreferences.getAll(); + + Map decryptedData = new HashMap<>(); + for (String key : encryptedData.keySet()) + decryptedData.put(key, decryptFromBase64(mProxyPreferences.getString(key, null))); + + this.mCryptor = Cryptor.initWithSecurityConfig(securityConfig); + SharedPreferences.Editor mProxyEditor = SecurePreferences.this.mProxyPreferences.edit(); + + for (String key : decryptedData.keySet()) { + String data = encryptToBase64(decryptedData.get(key)); + mProxyEditor.putString(key, data); + } + + mProxyEditor.apply(); + } + + @Override - public String getString(String key, String defValue){ + public String getString(String key, String defValue) { final String encryptedData = mProxyPreferences.getString(generateKeyHash(key), null); return encryptedData != null ? decryptFromBase64(encryptedData) : defValue; } @@ -99,13 +120,13 @@ public String getString(String key, String defValue){ public Set getStringSet(String key, Set defSet) { Set encryptedSet = mProxyPreferences.getStringSet(generateKeyHash(key), null); - if(encryptedSet != null){ + if (encryptedSet != null) { Set plainSet = new HashSet<>(); - for(String temp : encryptedSet) { + for (String temp : encryptedSet) { plainSet.add(decryptFromBase64(temp)); } return plainSet; - }else{ + } else { return defSet; } } @@ -154,20 +175,20 @@ public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeL mProxyPreferences.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener); } - public AsyncDataLoader getAsyncDataLoader(){ + public AsyncDataLoader getAsyncDataLoader() { return new AsyncDataLoader(this); } - public final class Editor implements SharedPreferences.Editor{ + public final class Editor implements SharedPreferences.Editor { protected SharedPreferences.Editor mProxyEditor; - public Editor(){ + public Editor() { this.mProxyEditor = SecurePreferences.this.mProxyPreferences.edit(); } @Override - public SecurePreferences.Editor putString(String key, String data){ + public SecurePreferences.Editor putString(String key, String data) { String hashedKey = generateKeyHash(key); String encryptedData = encryptToBase64(data); mProxyEditor.putString(hashedKey, encryptedData); @@ -179,7 +200,7 @@ public SecurePreferences.Editor putStringSet(String key, Set set) { String hashedKey = generateKeyHash(key); Set encryptedSet = new HashSet<>(); - for(String temp : set) { + for (String temp : set) { encryptedSet.add(encryptToBase64(temp)); } @@ -196,7 +217,7 @@ public SecurePreferences.Editor putInt(String key, int data) { } @Override - public SecurePreferences.Editor putLong(String key, long data){ + public SecurePreferences.Editor putLong(String key, long data) { String hashedKey = generateKeyHash(key); String encryptedData = encryptToBase64(Long.toString(data)); mProxyEditor.putString(hashedKey, encryptedData); diff --git a/sample/src/main/java/com/github/hussainderry/sample/MainActivity.java b/sample/src/main/java/com/github/hussainderry/sample/MainActivity.java index 7921971..6a6d3e7 100755 --- a/sample/src/main/java/com/github/hussainderry/sample/MainActivity.java +++ b/sample/src/main/java/com/github/hussainderry/sample/MainActivity.java @@ -1,10 +1,5 @@ package com.github.hussainderry.sample; -import com.github.hussainderry.securepreferences.SecurePreferences; -import com.github.hussainderry.securepreferences.model.DigestType; -import com.github.hussainderry.securepreferences.model.SecurityConfig; -import com.github.hussainderry.securepreferences.util.AsyncDataLoader; - import android.os.Bundle; import android.os.SystemClock; import android.support.design.widget.FloatingActionButton; @@ -13,6 +8,11 @@ import android.view.View; import android.widget.Toast; +import com.github.hussainderry.securepreferences.SecurePreferences; +import com.github.hussainderry.securepreferences.model.DigestType; +import com.github.hussainderry.securepreferences.model.SecurityConfig; +import com.github.hussainderry.securepreferences.util.AsyncDataLoader; + import java.util.concurrent.Future; public class MainActivity extends AppCompatActivity { @@ -23,6 +23,8 @@ public class MainActivity extends AppCompatActivity { private SecurePreferences.Editor mEditor; private AsyncDataLoader mAsyncLoader; + int count = 1; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -34,6 +36,7 @@ protected void onCreate(Bundle savedInstanceState) { SecurityConfig minimumConfig = new SecurityConfig.Builder(PASSWORD) .build(); + // Full Configurations SecurityConfig fullConfig = new SecurityConfig.Builder(PASSWORD) .setKeySize(256) @@ -42,7 +45,7 @@ protected void onCreate(Bundle savedInstanceState) { .setDigestType(DigestType.SHA256) .build(); - mPreferences = SecurePreferences.getInstance(MainActivity.this, FILENAME, minimumConfig); + mPreferences = SecurePreferences.getInstance(MainActivity.this, FILENAME, fullConfig); mEditor = mPreferences.edit(); mAsyncLoader = mPreferences.getAsyncDataLoader(); @@ -50,17 +53,37 @@ protected void onCreate(Bundle savedInstanceState) { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - Toast.makeText(MainActivity.this, "Saving to Secure Prefs", Toast.LENGTH_SHORT).show(); - saveToSecurePref("msg", "Hello World!"); - try { - Toast.makeText(MainActivity.this, "From Secure Prefs: " + getFromSecurePref("msg"), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - e.printStackTrace(); + if(count == 1) { + Toast.makeText(MainActivity.this, "Saving to Secure Prefs", Toast.LENGTH_SHORT).show(); + saveToSecurePref("msg", "Hello World!"); + try { + Toast.makeText(MainActivity.this, "From Secure Prefs: " + getFromSecurePref("msg"), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + e.printStackTrace(); + } + count++; + }else{ + changePassword(); + try { + Toast.makeText(MainActivity.this, "From Secure Prefs: " + getFromSecurePref("msg"), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + e.printStackTrace(); + } } } }); } + private void changePassword(){ + SecurityConfig fullConfig = new SecurityConfig.Builder("thisisthenewpassword") + .setKeySize(256) + .setPbkdf2SaltSize(16) + .setPbkdf2Iterations(12000) + .setDigestType(DigestType.SHA256) + .build(); + mPreferences.changePassword(fullConfig); + } + private void saveToSecurePref(String key, String data){ mEditor.putString(key, data); mEditor.apply();