Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 17 additions & 33 deletions lib/lib.iml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
Expand All @@ -50,73 +50,56 @@
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/attr" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/extractedTypedefs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/intermediate-jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/library_and_local_jars_jni" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged-aidl" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packagedAssets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/public_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/ivy.xml" />
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/poms" />
<excludeFolder url="file://$MODULE_DIR$/build/reports" />
<excludeFolder url="file://$MODULE_DIR$/build/test-results" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
Expand All @@ -132,5 +115,6 @@
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.madgag.spongycastle:core:1.58.0.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:rules-0.5" level="project" />
<orderEntry type="library" name="Gradle: android-android-27" level="project" />
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -15,71 +15,73 @@
*/
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;

/**
* @author Hussain Al-Derry <hussain.derry@gmail.com>
* @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());
}
}
Expand All @@ -89,8 +91,27 @@ private String decryptFromBase64(String base64Data){
throw new UnsupportedOperationException("Operation Not Supported!");
}

public void changePassword(SecurityConfig securityConfig) {
final Map<String, ?> encryptedData = mProxyPreferences.getAll();

Map<String, String> 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;
}
Expand All @@ -99,13 +120,13 @@ public String getString(String key, String defValue){
public Set<String> getStringSet(String key, Set<String> defSet) {
Set<String> encryptedSet = mProxyPreferences.getStringSet(generateKeyHash(key), null);

if(encryptedSet != null){
if (encryptedSet != null) {
Set<String> plainSet = new HashSet<>();
for(String temp : encryptedSet) {
for (String temp : encryptedSet) {
plainSet.add(decryptFromBase64(temp));
}
return plainSet;
}else{
} else {
return defSet;
}
}
Expand Down Expand Up @@ -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);
Expand All @@ -179,7 +200,7 @@ public SecurePreferences.Editor putStringSet(String key, Set<String> set) {
String hashedKey = generateKeyHash(key);
Set<String> encryptedSet = new HashSet<>();

for(String temp : set) {
for (String temp : set) {
encryptedSet.add(encryptToBase64(temp));
}

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand All @@ -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);
Expand All @@ -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)
Expand All @@ -42,25 +45,45 @@ 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();

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
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();
Expand Down