summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle7
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java8
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java85
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java8
6 files changed, 88 insertions, 23 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 07cf4ca5..367f69c8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,9 +4,9 @@ import java.util.regex.Pattern
apply plugin: 'com.android.application'
android {
- compileSdkVersion 31
+ compileSdkVersion 33
ndkVersion "21.4.7075529"
- buildToolsVersion '31.0.0'
+ buildToolsVersion '33.0.2'
compileOptions {
targetCompatibility 1.8
@@ -25,7 +25,7 @@ android {
versionCode 169000
versionName "1.1.8"
minSdkVersion 21
- targetSdkVersion 31
+ targetSdkVersion 33
vectorDrawables.useSupportLibrary = true
buildConfigField 'boolean', 'openvpn3', 'false'
@@ -429,6 +429,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.10.0'
implementation 'org.conscrypt:conscrypt-android:2.5.2'
+ implementation 'androidx.security:security-crypto:1.1.0-alpha06'
implementation 'androidx.legacy:legacy-support-core-utils:1.0.0'
implementation 'androidx.annotation:annotation:1.4.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java
index 6426c3d6..b622f5ca 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java
@@ -38,6 +38,7 @@ import android.util.Log;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
+import androidx.security.crypto.EncryptedSharedPreferences;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -81,7 +82,7 @@ public class StartActivity extends Activity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ preferences = PreferenceHelper.getSharedPreferences(this);
Log.d(TAG, "Started");
@@ -197,6 +198,11 @@ public class StartActivity extends Activity{
}
}
+ if (hasNewFeature(FeatureVersionCode.ENCRYPTED_SHARED_PREFS)) {
+ PreferenceHelper.migrateToEncryptedPrefs(this);
+ preferences = PreferenceHelper.getSharedPreferences(this);
+ }
+
// always check if manual gateway selection feature switch has been disabled
if (!BuildConfig.allow_manual_gateway_selection && PreferenceHelper.getPreferredCity(this) != null) {
PreferenceHelper.setPreferredCity(this, null);
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
index 57467974..70bf3943 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
@@ -27,6 +27,7 @@ public interface Constants {
/////////////////////////////////////////////
String SHARED_PREFERENCES = "LEAPPreferences";
+ String SHARED_ENCRYPTED_PREFERENCES = "LEAPEncryptedPreferences";
String PREFERENCES_APP_VERSION = "bitmask version";
String ALWAYS_ON_SHOW_DIALOG = "DIALOG.ALWAYS_ON_SHOW_DIALOG";
String CLEARLOG = "clearlogconnect";
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java b/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java
index f7251acb..c2eb9694 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java
@@ -5,4 +5,6 @@ public interface FeatureVersionCode {
int GEOIP_SERVICE = 148;
int CALYX_PROVIDER_LILYPAD_UPDATE = 165000;
int RISEUP_PROVIDER_LILYPAD_UPDATE = 165000;
+
+ int ENCRYPTED_SHARED_PREFS = 170000;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
index 9cba221a..eadd37bc 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
@@ -27,6 +27,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_UPD
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.base.models.Constants.RESTART_ON_UPDATE;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_ENCRYPTED_PREFERENCES;
import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL;
import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES;
@@ -37,16 +38,21 @@ import static se.leap.bitmaskclient.base.models.Constants.USE_SNOWFLAKE;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
+import androidx.security.crypto.EncryptedSharedPreferences;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.GeneralSecurityException;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import de.blinkt.openvpn.VpnProfile;
@@ -60,6 +66,23 @@ import se.leap.bitmaskclient.tor.TorStatusObservable;
public class PreferenceHelper {
+ private static final String TAG = PreferenceHelper.class.getSimpleName();
+
+ public static SharedPreferences getSharedPreferences(Context context) {
+ try {
+ return EncryptedSharedPreferences.create(
+ SHARED_ENCRYPTED_PREFERENCES,
+ "leap_secret_shared_prefs",
+ context,
+ EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
+ EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
+ );
+ } catch (GeneralSecurityException | IOException e) {
+ e.printStackTrace();
+ }
+ return context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ }
+
public static Provider getSavedProviderFromSharedPreferences(@NonNull SharedPreferences preferences) {
Provider provider = new Provider();
try {
@@ -97,7 +120,7 @@ public class PreferenceHelper {
}
public static void persistProviderAsync(Context context, Provider provider) {
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
storeProviderInPreferences(preferences, provider, true);
}
@@ -151,7 +174,7 @@ public class PreferenceHelper {
* Sets the profile that is connected (to connect if the service restarts)
*/
public static void setLastUsedVpnProfile(Context context, VpnProfile connectedProfile) {
- SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences prefs = getSharedPreferences(context);
SharedPreferences.Editor prefsedit = prefs.edit();
prefsedit.putString(LAST_USED_PROFILE, connectedProfile.toJson());
prefsedit.apply();
@@ -161,7 +184,7 @@ public class PreferenceHelper {
* Returns the profile that was last connected (to connect if the service restarts)
*/
public static VpnProfile getLastConnectedVpnProfile(Context context) {
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
String lastConnectedProfileJson = preferences.getString(LAST_USED_PROFILE, null);
return VpnProfile.fromJson(lastConnectedProfileJson);
}
@@ -204,6 +227,8 @@ public class PreferenceHelper {
apply();
}
+ // used in fatweb flavor
+ @SuppressWarnings("unused")
public static void setLastAppUpdateCheck(Context context) {
putLong(context, LAST_UPDATE_CHECK, System.currentTimeMillis());
}
@@ -419,7 +444,7 @@ public class PreferenceHelper {
if (context == null) {
return null;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
return preferences.getStringSet(EXCLUDED_APPS, new HashSet<>());
}
@@ -427,7 +452,7 @@ public class PreferenceHelper {
if (context == null) {
return defValue;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
return preferences.getLong(key, defValue);
}
@@ -435,7 +460,7 @@ public class PreferenceHelper {
if (context == null) {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
preferences.edit().putLong(key, value).apply();
}
@@ -443,7 +468,7 @@ public class PreferenceHelper {
if (context == null) {
return defValue;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
return preferences.getString(key, defValue);
}
@@ -452,7 +477,7 @@ public class PreferenceHelper {
if (context == null) {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
preferences.edit().putString(key, value).commit();
}
@@ -460,7 +485,7 @@ public class PreferenceHelper {
if (context == null) {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
preferences.edit().putString(key, value).apply();
}
@@ -468,7 +493,7 @@ public class PreferenceHelper {
if (context == null) {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
preferences.edit().putStringSet(key, value).apply();
}
@@ -477,7 +502,7 @@ public class PreferenceHelper {
return false;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
return preferences.getBoolean(key, defValue);
}
@@ -486,7 +511,7 @@ public class PreferenceHelper {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
preferences.edit().putBoolean(key, value).apply();
}
@@ -495,7 +520,41 @@ public class PreferenceHelper {
return false;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences preferences = getSharedPreferences(context);
return preferences.contains(key);
}
+
+ public static void migrateToEncryptedPrefs(Context context) {
+ SharedPreferences encryptedPrefs = getSharedPreferences(context);
+ if (!(encryptedPrefs instanceof EncryptedSharedPreferences)) {
+ Log.e(TAG, "Failed to migrate shared preferences");
+ return;
+ }
+ SharedPreferences.Editor encryptedEditor = encryptedPrefs.edit();
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ Map<String,?> keys = preferences.getAll();
+
+ for(Map.Entry<String,?> entry : keys.entrySet()){
+ try {
+ Object value = entry.getValue();
+ if (value instanceof String) {
+ encryptedEditor.putString(entry.getKey(), (String) value);
+ } else if (value instanceof Boolean) {
+ encryptedEditor.putBoolean(entry.getKey(), (Boolean) value);
+ } else if (value instanceof Integer) {
+ encryptedEditor.putInt(entry.getKey(), (Integer) value);
+ } else if (value instanceof Set<?>) {
+ encryptedEditor.putStringSet(entry.getKey(), (Set<String>) value);
+ } else if (value instanceof Long) {
+ encryptedEditor.putLong(entry.getKey(), (Long) value);
+ } else if (value instanceof Float) {
+ encryptedEditor.putFloat(entry.getKey(), (Float) value);
+ }
+ } catch (ClassCastException e) {
+ e.printStackTrace();
+ }
+ }
+ encryptedEditor.commit();
+ preferences.edit().clear().apply();
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java
index 86ce577b..0e7e1f4a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java
@@ -19,7 +19,6 @@ package se.leap.bitmaskclient.providersetup;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
@@ -31,11 +30,9 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.concurrent.TimeoutException;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator;
import se.leap.bitmaskclient.tor.TorServiceCommand;
-import se.leap.bitmaskclient.tor.TorServiceConnection;
-
-import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
/**
* Implements HTTP api methods (encapsulated in {{@link ProviderApiManager}})
@@ -180,9 +177,8 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB
private ProviderApiManager initApiManager() {
- SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
OkHttpClientGenerator clientGenerator = new OkHttpClientGenerator(getResources());
- return new ProviderApiManager(preferences, getResources(), clientGenerator, this);
+ return new ProviderApiManager(PreferenceHelper.getSharedPreferences(this), getResources(), clientGenerator, this);
}
}