summaryrefslogtreecommitdiffhomepage
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml9
-rw-r--r--app/src/main/java/com/wireguard/android/Application.java4
-rw-r--r--app/src/main/java/com/wireguard/android/activity/SettingsActivity.java28
-rw-r--r--app/src/main/java/com/wireguard/android/backend/GoBackend.java58
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java8
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java102
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java20
-rw-r--r--app/src/main/java/com/wireguard/android/model/TunnelManager.java18
-rw-r--r--app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java31
-rw-r--r--app/src/main/java/com/wireguard/config/Attribute.java38
-rw-r--r--app/src/main/java/com/wireguard/config/Config.java170
-rw-r--r--app/src/main/java/com/wireguard/config/Interface.java329
-rw-r--r--app/src/main/java/com/wireguard/config/Peer.java301
-rw-r--r--app/src/main/java/com/wireguard/crypto/Curve25519.java628
-rw-r--r--app/src/main/java/com/wireguard/crypto/KeyEncoding.java46
-rw-r--r--app/src/main/res/layout/tunnel_editor_fragment.xml2
-rw-r--r--app/src/main/res/menu/config_editor.xml4
-rw-r--r--app/src/main/res/menu/main_activity.xml4
-rw-r--r--app/src/main/res/menu/tunnel_detail.xml4
-rw-r--r--app/src/main/res/menu/tunnel_list_action_mode.xml4
-rw-r--r--app/src/main/res/values/strings.xml2
-rw-r--r--app/src/main/res/values/styles.xml2
22 files changed, 893 insertions, 919 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2496e6be..b81b0fcc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -35,8 +35,8 @@
<activity
android:name=".activity.SettingsActivity"
android:label="@string/settings"
- android:theme="@style/SettingsTheme"
- android:parentActivityName=".activity.MainActivity" />
+ android:parentActivityName=".activity.MainActivity"
+ android:theme="@style/SettingsTheme" />
<activity
android:name=".activity.TunnelCreatorActivity"
@@ -58,11 +58,12 @@
<service
android:name=".backend.GoBackend$VpnService"
- android:permission="android.permission.BIND_VPN_SERVICE" >
+ android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
- <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
+ <meta-data
+ android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
android:value="false" />
</service>
diff --git a/app/src/main/java/com/wireguard/android/Application.java b/app/src/main/java/com/wireguard/android/Application.java
index c1b21373..f3cf0887 100644
--- a/app/src/main/java/com/wireguard/android/Application.java
+++ b/app/src/main/java/com/wireguard/android/Application.java
@@ -55,11 +55,11 @@ public class Application extends android.app.Application {
public interface ApplicationComponent {
AsyncWorker getAsyncWorker();
+ Class getBackendType();
+
ToolsInstaller getToolsInstaller();
TunnelManager getTunnelManager();
-
- Class getBackendType();
}
@Qualifier
diff --git a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
index e48b6d88..fb5e7a09 100644
--- a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
@@ -23,11 +23,6 @@ import java.util.List;
*/
public class SettingsActivity extends AppCompatActivity {
- @FunctionalInterface
- public interface PermissionRequestCallback {
- void done(String[] permissions, int[] grantResults);
- }
-
private HashMap<Integer, PermissionRequestCallback> permissionRequestCallbacks = new HashMap<>();
private int permissionRequestCounter = 0;
@@ -49,15 +44,6 @@ public class SettingsActivity extends AppCompatActivity {
}
@Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- final PermissionRequestCallback f = permissionRequestCallbacks.get(requestCode);
- if (f != null) {
- permissionRequestCallbacks.remove(requestCode);
- f.done(permissions, grantResults);
- }
- }
-
- @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
@@ -78,6 +64,20 @@ public class SettingsActivity extends AppCompatActivity {
}
}
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ final PermissionRequestCallback f = permissionRequestCallbacks.get(requestCode);
+ if (f != null) {
+ permissionRequestCallbacks.remove(requestCode);
+ f.done(permissions, grantResults);
+ }
+ }
+
+ @FunctionalInterface
+ public interface PermissionRequestCallback {
+ void done(String[] permissions, int[] grantResults);
+ }
+
public static class SettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String key) {
diff --git a/app/src/main/java/com/wireguard/android/backend/GoBackend.java b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
index 8201b116..519f7427 100644
--- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -27,48 +27,20 @@ import java9.util.concurrent.CompletableFuture;
public final class GoBackend implements Backend {
private static final String TAG = "WireGuard/" + GoBackend.class.getSimpleName();
+ private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
static {
System.loadLibrary("wg-go");
}
+ private Context context;
private Tunnel currentTunnel;
private int currentTunnelHandle = -1;
- private Context context;
-
public GoBackend(Context context) {
this.context = context;
}
- private void startVpnService() {
- context.startService(new Intent(context, VpnService.class));
- }
-
- public static class VpnService extends android.net.VpnService {
- @Override
- public void onCreate() {
- vpnService.complete(this);
- super.onCreate();
- }
-
- @Override
- public void onDestroy() {
- for (final Tunnel tunnel : Application.getComponent().getTunnelManager().getTunnels()) {
- if (tunnel != null && tunnel.getState() != State.DOWN)
- tunnel.setState(State.DOWN);
- }
- vpnService = vpnService.newIncompleteFuture();
- super.onDestroy();
- }
-
- public Builder getBuilder() {
- return new Builder();
- }
- }
-
- private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
-
private static native int wgGetSocketV4(int handle);
private static native int wgGetSocketV6(int handle);
@@ -219,4 +191,30 @@ public final class GoBackend implements Backend {
currentTunnelHandle = -1;
}
}
+
+ private void startVpnService() {
+ context.startService(new Intent(context, VpnService.class));
+ }
+
+ public static class VpnService extends android.net.VpnService {
+ public Builder getBuilder() {
+ return new Builder();
+ }
+
+ @Override
+ public void onCreate() {
+ vpnService.complete(this);
+ super.onCreate();
+ }
+
+ @Override
+ public void onDestroy() {
+ for (final Tunnel tunnel : Application.getComponent().getTunnelManager().getTunnels()) {
+ if (tunnel != null && tunnel.getState() != State.DOWN)
+ tunnel.setState(State.DOWN);
+ }
+ vpnService = vpnService.newIncompleteFuture();
+ super.onDestroy();
+ }
+ }
}
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
index 8d0ae4cf..01fa594b 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
@@ -20,6 +20,10 @@ import com.wireguard.config.Config;
public class TunnelDetailFragment extends BaseFragment {
private TunnelDetailFragmentBinding binding;
+ private void onConfigLoaded(final String name, final Config config) {
+ binding.setConfig(new Config.Observable(config, name));
+ }
+
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -46,10 +50,6 @@ public class TunnelDetailFragment extends BaseFragment {
super.onDestroyView();
}
- private void onConfigLoaded(final String name, final Config config) {
- binding.setConfig(new Config.Observable(config, name));
- }
-
@Override
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
if (binding == null)
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
index b7467b14..a3760ed9 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
@@ -3,8 +3,6 @@ package com.wireguard.android.fragment;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
@@ -41,6 +39,24 @@ public class TunnelEditorFragment extends BaseFragment {
binding.setConfig(new Config.Observable(config, name));
}
+ private void onConfigSaved(final Tunnel savedTunnel, final Config config,
+ final Throwable throwable) {
+ final String message;
+ if (throwable == null) {
+ message = getString(R.string.config_save_success, savedTunnel.getName());
+ Log.d(TAG, message);
+ onFinished();
+ } else {
+ final String error = ExceptionLoggers.unwrap(throwable).getMessage();
+ message = getString(R.string.config_save_error, savedTunnel.getName(), error);
+ Log.e(TAG, message, throwable);
+ if (binding != null) {
+ final CoordinatorLayout container = binding.mainContainer;
+ Snackbar.make(container, message, Snackbar.LENGTH_LONG).show();
+ }
+ }
+ }
+
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -48,40 +64,6 @@ public class TunnelEditorFragment extends BaseFragment {
}
@Override
- public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
- tunnel = newTunnel;
- if (binding == null)
- return;
- binding.setConfig(new Config.Observable(null, null));
- if (tunnel != null)
- tunnel.getConfigAsync().thenAccept(a -> onConfigLoaded(tunnel.getName(), a));
- }
-
- @Override
- public void onSaveInstanceState(@NonNull final Bundle outState) {
- outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig());
- outState.putString(KEY_ORIGINAL_NAME, tunnel == null ? null : tunnel.getName());
- super.onSaveInstanceState(outState);
- }
-
- @Override
- public void onViewStateRestored(final Bundle savedInstanceState) {
- if (savedInstanceState == null) {
- onSelectedTunnelChanged(null, getSelectedTunnel());
- } else {
- tunnel = getSelectedTunnel();
- Config.Observable config = savedInstanceState.getParcelable(KEY_LOCAL_CONFIG);
- String originalName = savedInstanceState.getString(KEY_ORIGINAL_NAME);
- if (tunnel != null && !tunnel.getName().equals(originalName))
- onSelectedTunnelChanged(null, tunnel);
- else
- binding.setConfig(config);
- }
-
- super.onViewStateRestored(savedInstanceState);
- }
-
- @Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.config_editor, menu);
}
@@ -159,22 +141,21 @@ public class TunnelEditorFragment extends BaseFragment {
}
}
- private void onConfigSaved(final Tunnel savedTunnel, final Config config,
- final Throwable throwable) {
- final String message;
- if (throwable == null) {
- message = getString(R.string.config_save_success, savedTunnel.getName());
- Log.d(TAG, message);
- onFinished();
- } else {
- final String error = ExceptionLoggers.unwrap(throwable).getMessage();
- message = getString(R.string.config_save_error, savedTunnel.getName(), error);
- Log.e(TAG, message, throwable);
- if (binding != null) {
- final CoordinatorLayout container = binding.mainContainer;
- Snackbar.make(container, message, Snackbar.LENGTH_LONG).show();
- }
- }
+ @Override
+ public void onSaveInstanceState(@NonNull final Bundle outState) {
+ outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig());
+ outState.putString(KEY_ORIGINAL_NAME, tunnel == null ? null : tunnel.getName());
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
+ tunnel = newTunnel;
+ if (binding == null)
+ return;
+ binding.setConfig(new Config.Observable(null, null));
+ if (tunnel != null)
+ tunnel.getConfigAsync().thenAccept(a -> onConfigLoaded(tunnel.getName(), a));
}
private void onTunnelCreated(final Tunnel newTunnel, final Throwable throwable) {
@@ -214,4 +195,21 @@ public class TunnelEditorFragment extends BaseFragment {
}
}
}
+
+ @Override
+ public void onViewStateRestored(final Bundle savedInstanceState) {
+ if (savedInstanceState == null) {
+ onSelectedTunnelChanged(null, getSelectedTunnel());
+ } else {
+ tunnel = getSelectedTunnel();
+ Config.Observable config = savedInstanceState.getParcelable(KEY_LOCAL_CONFIG);
+ String originalName = savedInstanceState.getString(KEY_ORIGINAL_NAME);
+ if (tunnel != null && !tunnel.getName().equals(originalName))
+ onSelectedTunnelChanged(null, tunnel);
+ else
+ binding.setConfig(config);
+ }
+
+ super.onViewStateRestored(savedInstanceState);
+ }
}
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
index 719960af..5291d8fb 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
@@ -27,7 +27,6 @@ import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
-import android.widget.TextView;
import com.wireguard.android.Application;
import com.wireguard.android.Application.ApplicationComponent;
@@ -44,7 +43,6 @@ import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.zip.ZipEntry;
@@ -70,6 +68,14 @@ public class TunnelListFragment extends BaseFragment {
private TunnelListFragmentBinding binding;
private TunnelManager tunnelManager;
+ public boolean collapseActionMenu() {
+ if (binding.createMenu.isExpanded()) {
+ binding.createMenu.collapse();
+ return true;
+ }
+ return false;
+ }
+
private void importTunnel(final Uri uri) {
final Activity activity = getActivity();
if (activity == null)
@@ -199,14 +205,6 @@ public class TunnelListFragment extends BaseFragment {
super.onDestroyView();
}
- public boolean collapseActionMenu() {
- if (binding.createMenu.isExpanded()) {
- binding.createMenu.collapse();
- return true;
- }
- return false;
- }
-
public void onRequestCreateConfig(@SuppressWarnings("unused") final View view) {
startActivity(new Intent(getActivity(), TunnelCreatorActivity.class));
if (binding != null)
@@ -254,7 +252,7 @@ public class TunnelListFragment extends BaseFragment {
if (tunnels.size() == 1 && throwables.isEmpty())
message = getString(R.string.import_success, tunnels.get(0).getName());
else if (tunnels.isEmpty() && throwables.size() == 1)
- /* Use the exception message from above. */;
+ /* Use the exception message from above. */ ;
else if (throwables.isEmpty())
message = getString(R.string.import_total_success, tunnels.size());
else if (!throwables.isEmpty())
diff --git a/app/src/main/java/com/wireguard/android/model/TunnelManager.java b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
index e4667c82..72980f5e 100644
--- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
@@ -128,15 +128,6 @@ public final class TunnelManager extends BaseObservable {
return tunnels;
}
- public void refreshTunnelStates() {
- asyncWorker.supplyAsync(backend::enumerate)
- .thenAccept(running -> {
- for (final Tunnel tunnel : tunnels)
- tunnel.onStateChanged(running.contains(tunnel.getName()) ? State.UP : State.DOWN);
- })
- .whenComplete(ExceptionLoggers.E);
- }
-
public void onCreate() {
asyncWorker.supplyAsync(configStore::enumerate)
.thenAcceptBoth(asyncWorker.supplyAsync(backend::enumerate), this::onTunnelsLoaded)
@@ -151,6 +142,15 @@ public final class TunnelManager extends BaseObservable {
setLastUsedTunnel(tunnels.get(lastUsedName));
}
+ public void refreshTunnelStates() {
+ asyncWorker.supplyAsync(backend::enumerate)
+ .thenAccept(running -> {
+ for (final Tunnel tunnel : tunnels)
+ tunnel.onStateChanged(running.contains(tunnel.getName()) ? State.UP : State.DOWN);
+ })
+ .whenComplete(ExceptionLoggers.E);
+ }
+
public CompletionStage<Void> restoreState() {
if (!preferences.getBoolean(KEY_RESTORE_ON_BOOT, false))
return CompletableFuture.completedFuture(null);
diff --git a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java
index 421be1df..b10d8388 100644
--- a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java
+++ b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java
@@ -6,9 +6,9 @@ import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.design.widget.Snackbar;
import android.support.v7.preference.Preference;
-import android.view.ContextThemeWrapper;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import com.wireguard.android.Application;
import com.wireguard.android.Application.ApplicationComponent;
@@ -25,7 +25,6 @@ import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@@ -50,19 +49,6 @@ public class ZipExporterPreference extends Preference {
tunnelManager = applicationComponent.getTunnelManager();
}
- @Override
- public CharSequence getSummary() {
- if (exportedFilePath == null)
- return getContext().getString(R.string.export_summary);
- else
- return getContext().getString(R.string.export_success, exportedFilePath);
- }
-
- @Override
- public CharSequence getTitle() {
- return getContext().getString(R.string.zip_exporter_title);
- }
-
private void exportZip() {
List<Tunnel> tunnels = new ArrayList<>(tunnelManager.getTunnels());
List<CompletableFuture<Config>> futureConfigs = new ArrayList<>(tunnels.size());
@@ -124,9 +110,22 @@ public class ZipExporterPreference extends Preference {
}
@Override
+ public CharSequence getSummary() {
+ if (exportedFilePath == null)
+ return getContext().getString(R.string.export_summary);
+ else
+ return getContext().getString(R.string.export_success, exportedFilePath);
+ }
+
+ @Override
+ public CharSequence getTitle() {
+ return getContext().getString(R.string.zip_exporter_title);
+ }
+
+ @Override
protected void onClick() {
getPrefActivity(this).ensurePermissions(
- new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
(permissions, granted) -> {
if (granted.length > 0 && granted[0] == PackageManager.PERMISSION_GRANTED)
exportZip();
diff --git a/app/src/main/java/com/wireguard/config/Attribute.java b/app/src/main/java/com/wireguard/config/Attribute.java
index 5ecd21f4..2d8070ac 100644
--- a/app/src/main/java/com/wireguard/config/Attribute.java
+++ b/app/src/main/java/com/wireguard/config/Attribute.java
@@ -30,6 +30,7 @@ enum Attribute {
private static final Map<String, Attribute> KEY_MAP;
private static final Pattern SEPARATOR_PATTERN = Pattern.compile("\\s|=");
+ private static Method parseNumericAddressMethod;
static {
KEY_MAP = new HashMap<>(Attribute.values().length);
@@ -38,6 +39,14 @@ enum Attribute {
}
}
+ static {
+ try {
+ parseNumericAddressMethod = InetAddress.class.getMethod("parseNumericAddress", new Class[]{String.class});
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private final Pattern pattern;
private final String token;
@@ -46,44 +55,35 @@ enum Attribute {
this.token = token;
}
- public static Attribute match(final CharSequence line) {
- return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0]);
- }
-
public static <T> String listToString(final List<T> list) {
return TextUtils.join(", ", list);
}
- public static String[] stringToList(final String string) {
- if (string == null)
- return new String[0];
- return string.trim().split("\\s*,\\s*");
- }
-
- private static Method parseNumericAddressMethod;
- static {
- try {
- parseNumericAddressMethod = InetAddress.class.getMethod("parseNumericAddress", new Class[]{String.class});
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ public static Attribute match(final CharSequence line) {
+ return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0]);
}
public static InetAddress parseIPString(final String address) {
if (address == null || address.isEmpty())
throw new IllegalArgumentException("Empty address");
try {
- return (InetAddress)parseNumericAddressMethod.invoke(null, new Object[]{address});
+ return (InetAddress) parseNumericAddressMethod.invoke(null, new Object[]{address});
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof IllegalArgumentException)
- throw (IllegalArgumentException)e.getCause();
+ throw (IllegalArgumentException) e.getCause();
else
throw new IllegalArgumentException(e.getCause());
}
}
+ public static String[] stringToList(final String string) {
+ if (string == null)
+ return new String[0];
+ return string.trim().split("\\s*,\\s*");
+ }
+
public String composeWith(final Object value) {
return String.format("%s = %s%n", token, value);
}
diff --git a/app/src/main/java/com/wireguard/config/Config.java b/app/src/main/java/com/wireguard/config/Config.java
index 6330ff5e..7e6ff77c 100644
--- a/app/src/main/java/com/wireguard/config/Config.java
+++ b/app/src/main/java/com/wireguard/config/Config.java
@@ -1,7 +1,5 @@
package com.wireguard.config;
-import com.android.databinding.library.baseAdapters.BR;
-
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.ObservableArrayList;
@@ -9,6 +7,8 @@ import android.databinding.ObservableList;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.databinding.library.baseAdapters.BR;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -22,90 +22,6 @@ import java.util.List;
*/
public class Config {
- public static class Observable extends BaseObservable implements Parcelable {
- private String name;
- private Interface.Observable observableInterface;
- private ObservableList<Peer.Observable> observablePeers;
-
- public Observable(Config parent, String name) {
- this.name = name;
- loadData(parent);
- }
-
- public void loadData(Config parent) {
- this.observableInterface = new Interface.Observable(parent == null ? null : parent.interfaceSection);
- this.observablePeers = new ObservableArrayList<>();
- if (parent != null) {
- for (Peer peer : parent.getPeers())
- this.observablePeers.add(new Peer.Observable(peer));
- }
- }
-
- public void commitData(Config parent) {
- this.observableInterface.commitData(parent.interfaceSection);
- List<Peer> newPeers = new ArrayList<>(this.observablePeers.size());
- for (Peer.Observable observablePeer : this.observablePeers) {
- Peer peer = new Peer();
- observablePeer.commitData(peer);
- newPeers.add(peer);
- }
- parent.peers = newPeers;
- notifyChange();
- }
-
- @Bindable
- public String getName() {
- return name == null ? "" : name;
- }
-
- public void setName(String name) {
- this.name = name;
- notifyPropertyChanged(BR.name);
- }
-
- @Bindable
- public Interface.Observable getInterfaceSection() {
- return observableInterface;
- }
-
- @Bindable
- public ObservableList<Peer.Observable> getPeers() {
- return observablePeers;
- }
-
-
- public static final Creator<Observable> CREATOR = new Creator<Observable>() {
- @Override
- public Observable createFromParcel(final Parcel in) {
- return new Observable(in);
- }
-
- @Override
- public Observable[] newArray(final int size) {
- return new Observable[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags) {
- dest.writeString(name);
- dest.writeParcelable(observableInterface, flags);
- dest.writeTypedList(observablePeers);
- }
-
- private Observable(final Parcel in) {
- name = in.readString();
- observableInterface = in.readParcelable(Interface.Observable.class.getClassLoader());
- observablePeers = new ObservableArrayList<>();
- in.readTypedList(observablePeers, Peer.Observable.CREATOR);
- }
- }
-
private final Interface interfaceSection = new Interface();
private List<Peer> peers = new ArrayList<>();
@@ -157,4 +73,86 @@ public class Config {
sb.append('\n').append(peer);
return sb.toString();
}
+
+ public static class Observable extends BaseObservable implements Parcelable {
+ public static final Creator<Observable> CREATOR = new Creator<Observable>() {
+ @Override
+ public Observable createFromParcel(final Parcel in) {
+ return new Observable(in);
+ }
+
+ @Override
+ public Observable[] newArray(final int size) {
+ return new Observable[size];
+ }
+ };
+ private String name;
+ private Interface.Observable observableInterface;
+ private ObservableList<Peer.Observable> observablePeers;
+
+ public Observable(Config parent, String name) {
+ this.name = name;
+ loadData(parent);
+ }
+
+ private Observable(final Parcel in) {
+ name = in.readString();
+ observableInterface = in.readParcelable(Interface.Observable.class.getClassLoader());
+ observablePeers = new ObservableArrayList<>();
+ in.readTypedList(observablePeers, Peer.Observable.CREATOR);
+ }
+
+ public void commitData(Config parent) {
+ this.observableInterface.commitData(parent.interfaceSection);
+ List<Peer> newPeers = new ArrayList<>(this.observablePeers.size());
+ for (Peer.Observable observablePeer : this.observablePeers) {
+ Peer peer = new Peer();
+ observablePeer.commitData(peer);
+ newPeers.add(peer);
+ }
+ parent.peers = newPeers;
+ notifyChange();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Bindable
+ public Interface.Observable getInterfaceSection() {
+ return observableInterface;
+ }
+
+ @Bindable
+ public String getName() {
+ return name == null ? "" : name;
+ }
+
+ @Bindable
+ public ObservableList<Peer.Observable> getPeers() {
+ return observablePeers;
+ }
+
+ public void loadData(Config parent) {
+ this.observableInterface = new Interface.Observable(parent == null ? null : parent.interfaceSection);
+ this.observablePeers = new ObservableArrayList<>();
+ if (parent != null) {
+ for (Peer peer : parent.getPeers())
+ this.observablePeers.add(new Peer.Observable(peer));
+ }
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ notifyPropertyChanged(BR.name);
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ dest.writeString(name);
+ dest.writeParcelable(observableInterface, flags);
+ dest.writeTypedList(observablePeers);
+ }
+ }
}
diff --git a/app/src/main/java/com/wireguard/config/Interface.java b/app/src/main/java/com/wireguard/config/Interface.java
index 758b528d..ff69ccaf 100644
--- a/app/src/main/java/com/wireguard/config/Interface.java
+++ b/app/src/main/java/com/wireguard/config/Interface.java
@@ -17,158 +17,34 @@ import java.util.List;
*/
public class Interface {
- public static class Observable extends BaseObservable implements Parcelable {
- private String addresses;
- private String dnses;
- private String publicKey;
- private String privateKey;
- private String listenPort;
- private String mtu;
-
- public Observable(Interface parent) {
- if (parent != null)
- loadData(parent);
- }
-
- public void loadData(Interface parent) {
- this.addresses = parent.getAddressString();
- this.dnses = parent.getDnsString();
- this.publicKey = parent.getPublicKey();
- this.privateKey = parent.getPrivateKey();
- this.listenPort = parent.getListenPortString();
- this.mtu = parent.getMtuString();
- }
-
- public void commitData(Interface parent) {
- parent.setAddressString(this.addresses);
- parent.setDnsString(this.dnses);
- parent.setPrivateKey(this.privateKey);
- parent.setListenPortString(this.listenPort);
- parent.setMtuString(this.mtu);
- loadData(parent);
- notifyChange();
- }
-
- @Bindable
- public String getAddresses() {
- return addresses;
- }
-
- public void setAddresses(String addresses) {
- this.addresses = addresses;
- notifyPropertyChanged(BR.addresses);
- }
-
- @Bindable
- public String getDnses() {
- return dnses;
- }
-
- public void setDnses(String dnses) {
- this.dnses = dnses;
- notifyPropertyChanged(BR.dnses);
- }
-
- @Bindable
- public String getPublicKey() {
- return publicKey;
- }
-
- @Bindable
- public String getPrivateKey() {
- return privateKey;
- }
-
- public void setPrivateKey(String privateKey) {
- this.privateKey = privateKey;
-
- try {
- this.publicKey = new Keypair(privateKey).getPublicKey();
- } catch (IllegalArgumentException ignored) {
- this.publicKey = "";
- }
-
- notifyPropertyChanged(BR.privateKey);
- notifyPropertyChanged(BR.publicKey);
- }
-
- public void generateKeypair() {
- Keypair keypair = new Keypair();
- privateKey = keypair.getPrivateKey();
- publicKey = keypair.getPublicKey();
- notifyPropertyChanged(BR.privateKey);
- notifyPropertyChanged(BR.publicKey);
- }
-
- @Bindable
- public String getListenPort() {
- return listenPort;
- }
-
- public void setListenPort(String listenPort) {
- this.listenPort = listenPort;
- notifyPropertyChanged(BR.listenPort);
- }
-
- @Bindable
- public String getMtu() {
- return mtu;
- }
-
- public void setMtu(String mtu) {
- this.mtu = mtu;
- notifyPropertyChanged(BR.mtu);
- }
-
-
- public static final Creator<Observable> CREATOR = new Creator<Observable>() {
- @Override
- public Observable createFromParcel(final Parcel in) {
- return new Observable(in);
- }
-
- @Override
- public Observable[] newArray(final int size) {
- return new Observable[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags) {
- dest.writeString(addresses);
- dest.writeString(dnses);
- dest.writeString(publicKey);
- dest.writeString(privateKey);
- dest.writeString(listenPort);
- dest.writeString(mtu);
- }
-
- private Observable(final Parcel in) {
- addresses = in.readString();
- dnses = in.readString();
- publicKey = in.readString();
- privateKey = in.readString();
- listenPort = in.readString();
- mtu = in.readString();
- }
- }
-
private List<IPCidr> addressList;
private List<InetAddress> dnsList;
private Keypair keypair;
private int listenPort;
private int mtu;
-
public Interface() {
addressList = new LinkedList<>();
dnsList = new LinkedList<>();
}
+ private void addAddresses(String[] addresses) {
+ if (addresses != null && addresses.length > 0) {
+ for (final String addr : addresses) {
+ if (addr.isEmpty())
+ throw new IllegalArgumentException("Address is empty");
+ this.addressList.add(new IPCidr(addr));
+ }
+ }
+ }
+
+ private void addDnses(String[] dnses) {
+ if (dnses != null && dnses.length > 0) {
+ for (final String dns : dnses) {
+ this.dnsList.add(Attribute.parseIPString(dns));
+ }
+ }
+ }
+
private String getAddressString() {
if (addressList.isEmpty())
return null;
@@ -179,6 +55,12 @@ public class Interface {
return addressList.toArray(new IPCidr[addressList.size()]);
}
+ private String getDnsString() {
+ if (dnsList.isEmpty())
+ return null;
+ return Attribute.listToString(getDnsStrings());
+ }
+
private List<String> getDnsStrings() {
List<String> strings = new LinkedList<>();
for (final InetAddress addr : dnsList)
@@ -186,12 +68,6 @@ public class Interface {
return strings;
}
- private String getDnsString() {
- if (dnsList.isEmpty())
- return null;
- return Attribute.listToString(getDnsStrings());
- }
-
public InetAddress[] getDnses() {
return dnsList.toArray(new InetAddress[dnsList.size()]);
}
@@ -244,29 +120,11 @@ public class Interface {
throw new IllegalArgumentException(line);
}
- private void addAddresses(String[] addresses) {
- if (addresses != null && addresses.length > 0) {
- for (final String addr : addresses) {
- if (addr.isEmpty())
- throw new IllegalArgumentException("Address is empty");
- this.addressList.add(new IPCidr(addr));
- }
- }
- }
-
private void setAddressString(final String addressString) {
this.addressList.clear();
addAddresses(Attribute.stringToList(addressString));
}
- private void addDnses(String[] dnses) {
- if (dnses != null && dnses.length > 0) {
- for (final String dns : dnses) {
- this.dnsList.add(Attribute.parseIPString(dns));
- }
- }
- }
-
private void setDnsString(final String dnsString) {
this.dnsList.clear();
addDnses(Attribute.stringToList(dnsString));
@@ -318,4 +176,143 @@ public class Interface {
sb.append(Attribute.PRIVATE_KEY.composeWith(keypair.getPrivateKey()));
return sb.toString();
}
+
+ public static class Observable extends BaseObservable implements Parcelable {
+ public static final Creator<Observable> CREATOR = new Creator<Observable>() {
+ @Override
+ public Observable createFromParcel(final Parcel in) {
+ return new Observable(in);
+ }
+
+ @Override
+ public Observable[] newArray(final int size) {
+ return new Observable[size];
+ }
+ };
+ private String addresses;
+ private String dnses;
+ private String listenPort;
+ private String mtu;
+ private String privateKey;
+ private String publicKey;
+
+ public Observable(Interface parent) {
+ if (parent != null)
+ loadData(parent);
+ }
+
+ private Observable(final Parcel in) {
+ addresses = in.readString();
+ dnses = in.readString();
+ publicKey = in.readString();
+ privateKey = in.readString();
+ listenPort = in.readString();
+ mtu = in.readString();
+ }
+
+ public void commitData(Interface parent) {
+ parent.setAddressString(this.addresses);
+ parent.setDnsString(this.dnses);
+ parent.setPrivateKey(this.privateKey);
+ parent.setListenPortString(this.listenPort);
+ parent.setMtuString(this.mtu);
+ loadData(parent);
+ notifyChange();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public void generateKeypair() {
+ Keypair keypair = new Keypair();
+ privateKey = keypair.getPrivateKey();
+ publicKey = keypair.getPublicKey();
+ notifyPropertyChanged(BR.privateKey);
+ notifyPropertyChanged(BR.publicKey);
+ }
+
+ @Bindable
+ public String getAddresses() {
+ return addresses;
+ }
+
+ @Bindable
+ public String getDnses() {
+ return dnses;
+ }
+
+ @Bindable
+ public String getListenPort() {
+ return listenPort;
+ }
+
+ @Bindable
+ public String getMtu() {
+ return mtu;
+ }
+
+ @Bindable
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ @Bindable
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void loadData(Interface parent) {
+ this.addresses = parent.getAddressString();
+ this.dnses = parent.getDnsString();
+ this.publicKey = parent.getPublicKey();
+ this.privateKey = parent.getPrivateKey();
+ this.listenPort = parent.getListenPortString();
+ this.mtu = parent.getMtuString();
+ }
+
+ public void setAddresses(String addresses) {
+ this.addresses = addresses;
+ notifyPropertyChanged(BR.addresses);
+ }
+
+ public void setDnses(String dnses) {
+ this.dnses = dnses;
+ notifyPropertyChanged(BR.dnses);
+ }
+
+ public void setListenPort(String listenPort) {
+ this.listenPort = listenPort;
+ notifyPropertyChanged(BR.listenPort);
+ }
+
+ public void setMtu(String mtu) {
+ this.mtu = mtu;
+ notifyPropertyChanged(BR.mtu);
+ }
+
+ public void setPrivateKey(String privateKey) {
+ this.privateKey = privateKey;
+
+ try {
+ this.publicKey = new Keypair(privateKey).getPublicKey();
+ } catch (IllegalArgumentException ignored) {
+ this.publicKey = "";
+ }
+
+ notifyPropertyChanged(BR.privateKey);
+ notifyPropertyChanged(BR.publicKey);
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ dest.writeString(addresses);
+ dest.writeString(dnses);
+ dest.writeString(publicKey);
+ dest.writeString(privateKey);
+ dest.writeString(listenPort);
+ dest.writeString(mtu);
+ }
+ }
}
diff --git a/app/src/main/java/com/wireguard/config/Peer.java b/app/src/main/java/com/wireguard/config/Peer.java
index 327365b3..9f71089f 100644
--- a/app/src/main/java/com/wireguard/config/Peer.java
+++ b/app/src/main/java/com/wireguard/config/Peer.java
@@ -22,136 +22,26 @@ import java.util.Locale;
*/
public class Peer {
- public static class Observable extends BaseObservable implements Parcelable {
- private String allowedIPs;
- private String endpoint;
- private String persistentKeepalive;
- private String preSharedKey;
- private String publicKey;
-
- public Observable(Peer parent) {
- loadData(parent);
- }
- public static Observable newInstance() {
- return new Observable(new Peer());
- }
-
- public void loadData(Peer parent) {
- this.allowedIPs = parent.getAllowedIPsString();
- this.endpoint = parent.getEndpointString();
- this.persistentKeepalive = parent.getPersistentKeepaliveString();
- this.preSharedKey = parent.getPreSharedKey();
- this.publicKey = parent.getPublicKey();
- }
-
- public void commitData(Peer parent) {
- parent.setAllowedIPsString(this.allowedIPs);
- parent.setEndpointString(this.endpoint);
- parent.setPersistentKeepaliveString(this.persistentKeepalive);
- parent.setPreSharedKey(this.preSharedKey);
- parent.setPublicKey(this.publicKey);
- if (parent.getPublicKey() == null)
- throw new IllegalArgumentException("Peer public key may not be empty");
- loadData(parent);
- notifyChange();
- }
-
- @Bindable
- public String getAllowedIPs() {
- return allowedIPs;
- }
-
- public void setAllowedIPs(String allowedIPs) {
- this.allowedIPs = allowedIPs;
- notifyPropertyChanged(BR.allowedIPs);
- }
-
- @Bindable
- public String getEndpoint() {
- return endpoint;
- }
-
- public void setEndpoint(String endpoint) {
- this.endpoint = endpoint;
- notifyPropertyChanged(BR.endpoint);
- }
-
- @Bindable
- public String getPersistentKeepalive() {
- return persistentKeepalive;
- }
-
- public void setPersistentKeepalive(String persistentKeepalive) {
- this.persistentKeepalive = persistentKeepalive;
- notifyPropertyChanged(BR.persistentKeepalive);
- }
-
- @Bindable
- public String getPreSharedKey() {
- return preSharedKey;
- }
-
- public void setPreSharedKey(String preSharedKey) {
- this.preSharedKey = preSharedKey;
- notifyPropertyChanged(BR.preSharedKey);
- }
-
- @Bindable
- public String getPublicKey() {
- return publicKey;
- }
-
- public void setPublicKey(String publicKey) {
- this.publicKey = publicKey;
- notifyPropertyChanged(BR.publicKey);
- }
-
-
- public static final Creator<Observable> CREATOR = new Creator<Observable>() {
- @Override
- public Observable createFromParcel(final Parcel in) {
- return new Observable(in);
- }
-
- @Override
- public Observable[] newArray(final int size) {
- return new Observable[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags) {
- dest.writeString(allowedIPs);
- dest.writeString(endpoint);
- dest.writeString(persistentKeepalive);
- dest.writeString(preSharedKey);
- dest.writeString(publicKey);
- }
-
- private Observable(final Parcel in) {
- allowedIPs = in.readString();
- endpoint = in.readString();
- persistentKeepalive = in.readString();
- preSharedKey = in.readString();
- publicKey = in.readString();
- }
- }
-
private List<IPCidr> allowedIPsList;
private InetSocketAddress endpoint;
private int persistentKeepalive;
private String preSharedKey;
private String publicKey;
-
public Peer() {
allowedIPsList = new LinkedList<>();
}
+ private void addAllowedIPs(String[] allowedIPs) {
+ if (allowedIPs != null && allowedIPs.length > 0) {
+ for (final String allowedIP : allowedIPs) {
+ this.allowedIPsList.add(new IPCidr(allowedIP));
+ }
+ }
+ }
+
+ public IPCidr[] getAllowedIPs() {
+ return allowedIPsList.toArray(new IPCidr[allowedIPsList.size()]);
+ }
private String getAllowedIPsString() {
if (allowedIPsList.isEmpty())
@@ -159,10 +49,6 @@ public class Peer {
return Attribute.listToString(allowedIPsList);
}
- public IPCidr[] getAllowedIPs() {
- return allowedIPsList.toArray(new IPCidr[allowedIPsList.size()]);
- }
-
public InetSocketAddress getEndpoint() {
return endpoint;
}
@@ -173,24 +59,6 @@ public class Peer {
return String.format(Locale.getDefault(), "%s:%d", endpoint.getHostString(), endpoint.getPort());
}
- public String getResolvedEndpointString() throws UnknownHostException {
- if (endpoint == null)
- throw new UnknownHostException("{empty}");
- if (endpoint.isUnresolved())
- endpoint = new InetSocketAddress(endpoint.getHostString(), endpoint.getPort());
- if (endpoint.isUnresolved())
- throw new UnknownHostException(endpoint.getHostString());
- if (endpoint.getAddress() instanceof Inet6Address)
- return String.format(Locale.getDefault(),
- "[%s]:%d",
- endpoint.getAddress().getHostAddress(),
- endpoint.getPort());
- return String.format(Locale.getDefault(),
- "%s:%d",
- endpoint.getAddress().getHostAddress(),
- endpoint.getPort());
- }
-
public int getPersistentKeepalive() {
return persistentKeepalive;
}
@@ -209,6 +77,24 @@ public class Peer {
return publicKey;
}
+ public String getResolvedEndpointString() throws UnknownHostException {
+ if (endpoint == null)
+ throw new UnknownHostException("{empty}");
+ if (endpoint.isUnresolved())
+ endpoint = new InetSocketAddress(endpoint.getHostString(), endpoint.getPort());
+ if (endpoint.isUnresolved())
+ throw new UnknownHostException(endpoint.getHostString());
+ if (endpoint.getAddress() instanceof Inet6Address)
+ return String.format(Locale.getDefault(),
+ "[%s]:%d",
+ endpoint.getAddress().getHostAddress(),
+ endpoint.getPort());
+ return String.format(Locale.getDefault(),
+ "%s:%d",
+ endpoint.getAddress().getHostAddress(),
+ endpoint.getPort());
+ }
+
public void parse(final String line) {
final Attribute key = Attribute.match(line);
if (key == Attribute.ALLOWED_IPS)
@@ -225,14 +111,6 @@ public class Peer {
throw new IllegalArgumentException(line);
}
- private void addAllowedIPs(String[] allowedIPs) {
- if (allowedIPs != null && allowedIPs.length > 0) {
- for (final String allowedIP : allowedIPs) {
- this.allowedIPsList.add(new IPCidr(allowedIP));
- }
- }
- }
-
private void setAllowedIPsString(final String allowedIPsString) {
this.allowedIPsList.clear();
addAllowedIPs(Attribute.stringToList(allowedIPsString));
@@ -246,7 +124,7 @@ public class Peer {
if (endpoint != null && !endpoint.isEmpty()) {
InetSocketAddress constructedEndpoint;
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
- throw new IllegalArgumentException("Forbidden characters in endpoint");
+ throw new IllegalArgumentException("Forbidden characters in endpoint");
URI uri;
try {
uri = new URI("wg://" + endpoint);
@@ -301,4 +179,123 @@ public class Peer {
sb.append(Attribute.PUBLIC_KEY.composeWith(publicKey));
return sb.toString();
}
+
+ public static class Observable extends BaseObservable implements Parcelable {
+ public static final Creator<Observable> CREATOR = new Creator<Observable>() {
+ @Override
+ public Observable createFromParcel(final Parcel in) {
+ return new Observable(in);
+ }
+
+ @Override
+ public Observable[] newArray(final int size) {
+ return new Observable[size];
+ }
+ };
+ private String allowedIPs;
+ private String endpoint;
+ private String persistentKeepalive;
+ private String preSharedKey;
+ private String publicKey;
+
+ public Observable(Peer parent) {
+ loadData(parent);
+ }
+
+ private Observable(final Parcel in) {
+ allowedIPs = in.readString();
+ endpoint = in.readString();
+ persistentKeepalive = in.readString();
+ preSharedKey = in.readString();
+ publicKey = in.readString();
+ }
+
+ public static Observable newInstance() {
+ return new Observable(new Peer());
+ }
+
+ public void commitData(Peer parent) {
+ parent.setAllowedIPsString(this.allowedIPs);
+ parent.setEndpointString(this.endpoint);
+ parent.setPersistentKeepaliveString(this.persistentKeepalive);
+ parent.setPreSharedKey(this.preSharedKey);
+ parent.setPublicKey(this.publicKey);
+ if (parent.getPublicKey() == null)
+ throw new IllegalArgumentException("Peer public key may not be empty");
+ loadData(parent);
+ notifyChange();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Bindable
+ public String getAllowedIPs() {
+ return allowedIPs;
+ }
+
+ @Bindable
+ public String getEndpoint() {
+ return endpoint;
+ }
+
+ @Bindable
+ public String getPersistentKeepalive() {
+ return persistentKeepalive;
+ }
+
+ @Bindable
+ public String getPreSharedKey() {
+ return preSharedKey;
+ }
+
+ @Bindable
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void loadData(Peer parent) {
+ this.allowedIPs = parent.getAllowedIPsString();
+ this.endpoint = parent.getEndpointString();
+ this.persistentKeepalive = parent.getPersistentKeepaliveString();
+ this.preSharedKey = parent.getPreSharedKey();
+ this.publicKey = parent.getPublicKey();
+ }
+
+ public void setAllowedIPs(String allowedIPs) {
+ this.allowedIPs = allowedIPs;
+ notifyPropertyChanged(BR.allowedIPs);
+ }
+
+ public void setEndpoint(String endpoint) {
+ this.endpoint = endpoint;
+ notifyPropertyChanged(BR.endpoint);
+ }
+
+ public void setPersistentKeepalive(String persistentKeepalive) {
+ this.persistentKeepalive = persistentKeepalive;
+ notifyPropertyChanged(BR.persistentKeepalive);
+ }
+
+ public void setPreSharedKey(String preSharedKey) {
+ this.preSharedKey = preSharedKey;
+ notifyPropertyChanged(BR.preSharedKey);
+ }
+
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ notifyPropertyChanged(BR.publicKey);
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ dest.writeString(allowedIPs);
+ dest.writeString(endpoint);
+ dest.writeString(persistentKeepalive);
+ dest.writeString(preSharedKey);
+ dest.writeString(publicKey);
+ }
+ }
}
diff --git a/app/src/main/java/com/wireguard/crypto/Curve25519.java b/app/src/main/java/com/wireguard/crypto/Curve25519.java
index 5d27c3e3..0956c4fb 100644
--- a/app/src/main/java/com/wireguard/crypto/Curve25519.java
+++ b/app/src/main/java/com/wireguard/crypto/Curve25519.java
@@ -26,16 +26,16 @@ import java.util.Arrays;
/**
* Implementation of the Curve25519 elliptic curve algorithm.
- *
+ * <p>
* This implementation is based on that from arduinolibs:
* https://github.com/rweather/arduinolibs
- *
+ * <p>
* This implementation is copied verbatim from noise-java:
* https://github.com/rweather/noise-java
- *
+ * <p>
* Differences in this version are due to using 26-bit limbs for the
* representation instead of the 8/16/32-bit limbs in the original.
- *
+ * <p>
* References: http://cr.yp.to/ecdh.html, RFC 7748
*/
@SuppressWarnings("ALL")
@@ -44,47 +44,148 @@ public final class Curve25519 {
// Numbers modulo 2^255 - 19 are broken up into ten 26-bit words.
private static final int NUM_LIMBS_255BIT = 10;
private static final int NUM_LIMBS_510BIT = 20;
- private int[] x_1;
- private int[] x_2;
- private int[] x_3;
- private int[] z_2;
- private int[] z_3;
private int[] A;
+ private int[] AA;
private int[] B;
+ private int[] BB;
private int[] C;
+ private int[] CB;
private int[] D;
- private int[] E;
- private int[] AA;
- private int[] BB;
private int[] DA;
- private int[] CB;
+ private int[] E;
private long[] t1;
private int[] t2;
+ private int[] x_1;
+ private int[] x_2;
+ private int[] x_3;
+ private int[] z_2;
+ private int[] z_3;
/**
* Constructs the temporary state holder for Curve25519 evaluation.
*/
- private Curve25519()
- {
+ private Curve25519() {
// Allocate memory for all of the temporary variables we will need.
- x_1 = new int [NUM_LIMBS_255BIT];
- x_2 = new int [NUM_LIMBS_255BIT];
- x_3 = new int [NUM_LIMBS_255BIT];
- z_2 = new int [NUM_LIMBS_255BIT];
- z_3 = new int [NUM_LIMBS_255BIT];
- A = new int [NUM_LIMBS_255BIT];
- B = new int [NUM_LIMBS_255BIT];
- C = new int [NUM_LIMBS_255BIT];
- D = new int [NUM_LIMBS_255BIT];
- E = new int [NUM_LIMBS_255BIT];
- AA = new int [NUM_LIMBS_255BIT];
- BB = new int [NUM_LIMBS_255BIT];
- DA = new int [NUM_LIMBS_255BIT];
- CB = new int [NUM_LIMBS_255BIT];
- t1 = new long [NUM_LIMBS_510BIT];
- t2 = new int [NUM_LIMBS_510BIT];
+ x_1 = new int[NUM_LIMBS_255BIT];
+ x_2 = new int[NUM_LIMBS_255BIT];
+ x_3 = new int[NUM_LIMBS_255BIT];
+ z_2 = new int[NUM_LIMBS_255BIT];
+ z_3 = new int[NUM_LIMBS_255BIT];
+ A = new int[NUM_LIMBS_255BIT];
+ B = new int[NUM_LIMBS_255BIT];
+ C = new int[NUM_LIMBS_255BIT];
+ D = new int[NUM_LIMBS_255BIT];
+ E = new int[NUM_LIMBS_255BIT];
+ AA = new int[NUM_LIMBS_255BIT];
+ BB = new int[NUM_LIMBS_255BIT];
+ DA = new int[NUM_LIMBS_255BIT];
+ CB = new int[NUM_LIMBS_255BIT];
+ t1 = new long[NUM_LIMBS_510BIT];
+ t2 = new int[NUM_LIMBS_510BIT];
}
+ /**
+ * Conditional swap of two values.
+ *
+ * @param select Set to 1 to swap, 0 to leave as-is.
+ * @param x The first value.
+ * @param y The second value.
+ */
+ private static void cswap(int select, int[] x, int[] y) {
+ int dummy;
+ select = -select;
+ for (int index = 0; index < NUM_LIMBS_255BIT; ++index) {
+ dummy = select & (x[index] ^ y[index]);
+ x[index] ^= dummy;
+ y[index] ^= dummy;
+ }
+ }
+
+ /**
+ * Evaluates the Curve25519 curve.
+ *
+ * @param result Buffer to place the result of the evaluation into.
+ * @param offset Offset into the result buffer.
+ * @param privateKey The private key to use in the evaluation.
+ * @param publicKey The public key to use in the evaluation, or null
+ * if the base point of the curve should be used.
+ */
+ public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey) {
+ Curve25519 state = new Curve25519();
+ try {
+ // Unpack the public key value. If null, use 9 as the base point.
+ Arrays.fill(state.x_1, 0);
+ if (publicKey != null) {
+ // Convert the input value from little-endian into 26-bit limbs.
+ for (int index = 0; index < 32; ++index) {
+ int bit = (index * 8) % 26;
+ int word = (index * 8) / 26;
+ int value = publicKey[index] & 0xFF;
+ if (bit <= (26 - 8)) {
+ state.x_1[word] |= value << bit;
+ } else {
+ state.x_1[word] |= value << bit;
+ state.x_1[word] &= 0x03FFFFFF;
+ state.x_1[word + 1] |= value >> (26 - bit);
+ }
+ }
+
+ // Just in case, we reduce the number modulo 2^255 - 19 to
+ // make sure that it is in range of the field before we start.
+ // This eliminates values between 2^255 - 19 and 2^256 - 1.
+ state.reduceQuick(state.x_1);
+ state.reduceQuick(state.x_1);
+ } else {
+ state.x_1[0] = 9;
+ }
+
+ // Initialize the other temporary variables.
+ Arrays.fill(state.x_2, 0); // x_2 = 1
+ state.x_2[0] = 1;
+ Arrays.fill(state.z_2, 0); // z_2 = 0
+ System.arraycopy(state.x_1, 0, state.x_3, 0, state.x_1.length); // x_3 = x_1
+ Arrays.fill(state.z_3, 0); // z_3 = 1
+ state.z_3[0] = 1;
+
+ // Evaluate the curve for every bit of the private key.
+ state.evalCurve(privateKey);
+
+ // Compute x_2 * (z_2 ^ (p - 2)) where p = 2^255 - 19.
+ state.recip(state.z_3, state.z_2);
+ state.mul(state.x_2, state.x_2, state.z_3);
+
+ // Convert x_2 into little-endian in the result buffer.
+ for (int index = 0; index < 32; ++index) {
+ int bit = (index * 8) % 26;
+ int word = (index * 8) / 26;
+ if (bit <= (26 - 8))
+ result[offset + index] = (byte) (state.x_2[word] >> bit);
+ else
+ result[offset + index] = (byte) ((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
+ }
+ } finally {
+ // Clean up all temporary state before we exit.
+ state.destroy();
+ }
+ }
+
+ /**
+ * Adds two numbers modulo 2^255 - 19.
+ *
+ * @param result The result.
+ * @param x The first number to add.
+ * @param y The second number to add.
+ */
+ private void add(int[] result, int[] x, int[] y) {
+ int index, carry;
+ carry = x[0] + y[0];
+ result[0] = carry & 0x03FFFFFF;
+ for (index = 1; index < NUM_LIMBS_255BIT; ++index) {
+ carry = (carry >> 26) + x[index] + y[index];
+ result[index] = carry & 0x03FFFFFF;
+ }
+ reduceQuick(result);
+ }
/**
* Destroy all sensitive data in this object.
@@ -105,107 +206,82 @@ public final class Curve25519 {
Arrays.fill(BB, 0);
Arrays.fill(DA, 0);
Arrays.fill(CB, 0);
- Arrays.fill(t1, 0L);
- Arrays.fill(t2, 0);
+ Arrays.fill(t1, 0L);
+ Arrays.fill(t2, 0);
}
/**
- * Reduces a number modulo 2^255 - 19 where it is known that the
- * number can be reduced with only 1 trial subtraction.
+ * Evaluates the curve for every bit in a secret key.
*
- * @param x The number to reduce, and the result.
+ * @param s The 32-byte secret key.
*/
- private void reduceQuick(int[] x)
- {
- int index, carry;
-
- // Perform a trial subtraction of (2^255 - 19) from "x" which is
- // equivalent to adding 19 and subtracting 2^255. We add 19 here;
- // the subtraction of 2^255 occurs in the next step.
- carry = 19;
- for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
- carry += x[index];
- t2[index] = carry & 0x03FFFFFF;
- carry >>= 26;
- }
+ private void evalCurve(byte[] s) {
+ int sposn = 31;
+ int sbit = 6;
+ int svalue = s[sposn] | 0x40;
+ int swap = 0;
+ int select;
- // If there was a borrow, then the original "x" is the correct answer.
- // If there was no borrow, then "t2" is the correct answer. Select the
- // correct answer but do it in a way that instruction timing will not
- // reveal which value was selected. Borrow will occur if bit 21 of
- // "t2" is zero. Turn the bit into a selection mask.
- int mask = -((t2[NUM_LIMBS_255BIT - 1] >> 21) & 0x01);
- int nmask = ~mask;
- t2[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
- for (index = 0; index < NUM_LIMBS_255BIT; ++index)
- x[index] = (x[index] & nmask) | (t2[index] & mask);
- }
+ // Iterate over all 255 bits of "s" from the highest to the lowest.
+ // We ignore the high bit of the 256-bit representation of "s".
+ for (; ; ) {
+ // Conditional swaps on entry to this bit but only if we
+ // didn't swap on the previous bit.
+ select = (svalue >> sbit) & 0x01;
+ swap ^= select;
+ cswap(swap, x_2, x_3);
+ cswap(swap, z_2, z_3);
+ swap = select;
- /**
- * Reduce a number modulo 2^255 - 19.
- *
- * @param result The result.
- * @param x The value to be reduced. This array will be
- * modified during the reduction.
- * @param size The number of limbs in the high order half of x.
- */
- private void reduce(int[] result, int[] x, int size)
- {
- int index, limb, carry;
+ // Evaluate the curve.
+ add(A, x_2, z_2); // A = x_2 + z_2
+ square(AA, A); // AA = A^2
+ sub(B, x_2, z_2); // B = x_2 - z_2
+ square(BB, B); // BB = B^2
+ sub(E, AA, BB); // E = AA - BB
+ add(C, x_3, z_3); // C = x_3 + z_3
+ sub(D, x_3, z_3); // D = x_3 - z_3
+ mul(DA, D, A); // DA = D * A
+ mul(CB, C, B); // CB = C * B
+ add(x_3, DA, CB); // x_3 = (DA + CB)^2
+ square(x_3, x_3);
+ sub(z_3, DA, CB); // z_3 = x_1 * (DA - CB)^2
+ square(z_3, z_3);
+ mul(z_3, z_3, x_1);
+ mul(x_2, AA, BB); // x_2 = AA * BB
+ mulA24(z_2, E); // z_2 = E * (AA + a24 * E)
+ add(z_2, z_2, AA);
+ mul(z_2, z_2, E);
- // Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
- // either produce the answer we want or it will produce a
- // value of the form "answer + j * (2^255 - 19)". There are
- // 5 left-over bits in the top-most limb of the bottom half.
- carry = 0;
- limb = x[NUM_LIMBS_255BIT - 1] >> 21;
- x[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
- for (index = 0; index < size; ++index) {
- limb += x[NUM_LIMBS_255BIT + index] << 5;
- carry += (limb & 0x03FFFFFF) * 19 + x[index];
- x[index] = carry & 0x03FFFFFF;
- limb >>= 26;
- carry >>= 26;
- }
- if (size < NUM_LIMBS_255BIT) {
- // The high order half of the number is short; e.g. for mulA24().
- // Propagate the carry through the rest of the low order part.
- for (index = size; index < NUM_LIMBS_255BIT; ++index) {
- carry += x[index];
- x[index] = carry & 0x03FFFFFF;
- carry >>= 26;
+ // Move onto the next lower bit of "s".
+ if (sbit > 0) {
+ --sbit;
+ } else if (sposn == 0) {
+ break;
+ } else if (sposn == 1) {
+ --sposn;
+ svalue = s[sposn] & 0xF8;
+ sbit = 7;
+ } else {
+ --sposn;
+ svalue = s[sposn];
+ sbit = 7;
}
}
- // The "j" value may still be too large due to the final carry-out.
- // We must repeat the reduction. If we already have the answer,
- // then this won't do any harm but we must still do the calculation
- // to preserve the overall timing. The "j" value will be between
- // 0 and 19, which means that the carry we care about is in the
- // top 5 bits of the highest limb of the bottom half.
- carry = (x[NUM_LIMBS_255BIT - 1] >> 21) * 19;
- x[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
- for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
- carry += x[index];
- result[index] = carry & 0x03FFFFFF;
- carry >>= 26;
- }
-
- // At this point "x" will either be the answer or it will be the
- // answer plus (2^255 - 19). Perform a trial subtraction to
- // complete the reduction process.
- reduceQuick(result);
+ // Final conditional swaps.
+ cswap(swap, x_2, x_3);
+ cswap(swap, z_2, z_3);
}
/**
* Multiplies two numbers modulo 2^255 - 19.
*
* @param result The result.
- * @param x The first number to multiply.
- * @param y The second number to multiply.
+ * @param x The first number to multiply.
+ * @param y The second number to multiply.
*/
- private void mul(int[] result, int[] x, int[] y)
- {
+ private void mul(int[] result, int[] x, int[] y) {
int i, j;
// Multiply the two numbers to create the intermediate result.
@@ -223,10 +299,10 @@ public final class Curve25519 {
// Propagate carries and convert back into 26-bit words.
v = t1[0];
- t2[0] = ((int)v) & 0x03FFFFFF;
+ t2[0] = ((int) v) & 0x03FFFFFF;
for (i = 1; i < NUM_LIMBS_510BIT; ++i) {
v = (v >> 26) + t1[i];
- t2[i] = ((int)v) & 0x03FFFFFF;
+ t2[i] = ((int) v) & 0x03FFFFFF;
}
// Reduce the result modulo 2^255 - 19.
@@ -234,113 +310,31 @@ public final class Curve25519 {
}
/**
- * Squares a number modulo 2^255 - 19.
- *
- * @param result The result.
- * @param x The number to square.
- */
- private void square(int[] result, int[] x)
- {
- mul(result, x, x);
- }
-
- /**
* Multiplies a number by the a24 constant, modulo 2^255 - 19.
*
* @param result The result.
- * @param x The number to multiply by a24.
+ * @param x The number to multiply by a24.
*/
- private void mulA24(int[] result, int[] x)
- {
+ private void mulA24(int[] result, int[] x) {
long a24 = 121665;
long carry = 0;
int index;
for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
carry += a24 * x[index];
- t2[index] = ((int)carry) & 0x03FFFFFF;
+ t2[index] = ((int) carry) & 0x03FFFFFF;
carry >>= 26;
}
- t2[NUM_LIMBS_255BIT] = ((int)carry) & 0x03FFFFFF;
+ t2[NUM_LIMBS_255BIT] = ((int) carry) & 0x03FFFFFF;
reduce(result, t2, 1);
}
/**
- * Adds two numbers modulo 2^255 - 19.
- *
- * @param result The result.
- * @param x The first number to add.
- * @param y The second number to add.
- */
- private void add(int[] result, int[] x, int[] y)
- {
- int index, carry;
- carry = x[0] + y[0];
- result[0] = carry & 0x03FFFFFF;
- for (index = 1; index < NUM_LIMBS_255BIT; ++index) {
- carry = (carry >> 26) + x[index] + y[index];
- result[index] = carry & 0x03FFFFFF;
- }
- reduceQuick(result);
- }
-
- /**
- * Subtracts two numbers modulo 2^255 - 19.
- *
- * @param result The result.
- * @param x The first number to subtract.
- * @param y The second number to subtract.
- */
- private void sub(int[] result, int[] x, int[] y)
- {
- int index, borrow;
-
- // Subtract y from x to generate the intermediate result.
- borrow = 0;
- for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
- borrow = x[index] - y[index] - ((borrow >> 26) & 0x01);
- result[index] = borrow & 0x03FFFFFF;
- }
-
- // If we had a borrow, then the result has gone negative and we
- // have to add 2^255 - 19 to the result to make it positive again.
- // The top bits of "borrow" will be all 1's if there is a borrow
- // or it will be all 0's if there was no borrow. Easiest is to
- // conditionally subtract 19 and then mask off the high bits.
- borrow = result[0] - ((-((borrow >> 26) & 0x01)) & 19);
- result[0] = borrow & 0x03FFFFFF;
- for (index = 1; index < NUM_LIMBS_255BIT; ++index) {
- borrow = result[index] - ((borrow >> 26) & 0x01);
- result[index] = borrow & 0x03FFFFFF;
- }
- result[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
- }
-
- /**
- * Conditional swap of two values.
- *
- * @param select Set to 1 to swap, 0 to leave as-is.
- * @param x The first value.
- * @param y The second value.
- */
- private static void cswap(int select, int[] x, int[] y)
- {
- int dummy;
- select = -select;
- for (int index = 0; index < NUM_LIMBS_255BIT; ++index) {
- dummy = select & (x[index] ^ y[index]);
- x[index] ^= dummy;
- y[index] ^= dummy;
- }
- }
-
- /**
* Raise x to the power of (2^250 - 1).
*
* @param result The result. Must not overlap with x.
- * @param x The argument.
+ * @param x The argument.
*/
- private void pow250(int[] result, int[] x)
- {
+ private void pow250(int[] result, int[] x) {
int i, j;
// The big-endian hexadecimal expansion of (2^250 - 1) is:
@@ -378,10 +372,9 @@ public final class Curve25519 {
* Computes the reciprocal of a number modulo 2^255 - 19.
*
* @param result The result. Must not overlap with x.
- * @param x The argument.
+ * @param x The argument.
*/
- private void recip(int[] result, int[] x)
- {
+ private void recip(int[] result, int[] x) {
// The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
// The big-endian hexadecimal expansion of (p - 2) is:
// 7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFEB
@@ -400,136 +393,129 @@ public final class Curve25519 {
}
/**
- * Evaluates the curve for every bit in a secret key.
+ * Reduce a number modulo 2^255 - 19.
*
- * @param s The 32-byte secret key.
+ * @param result The result.
+ * @param x The value to be reduced. This array will be
+ * modified during the reduction.
+ * @param size The number of limbs in the high order half of x.
*/
- private void evalCurve(byte[] s)
- {
- int sposn = 31;
- int sbit = 6;
- int svalue = s[sposn] | 0x40;
- int swap = 0;
- int select;
-
- // Iterate over all 255 bits of "s" from the highest to the lowest.
- // We ignore the high bit of the 256-bit representation of "s".
- for (;;) {
- // Conditional swaps on entry to this bit but only if we
- // didn't swap on the previous bit.
- select = (svalue >> sbit) & 0x01;
- swap ^= select;
- cswap(swap, x_2, x_3);
- cswap(swap, z_2, z_3);
- swap = select;
-
- // Evaluate the curve.
- add(A, x_2, z_2); // A = x_2 + z_2
- square(AA, A); // AA = A^2
- sub(B, x_2, z_2); // B = x_2 - z_2
- square(BB, B); // BB = B^2
- sub(E, AA, BB); // E = AA - BB
- add(C, x_3, z_3); // C = x_3 + z_3
- sub(D, x_3, z_3); // D = x_3 - z_3
- mul(DA, D, A); // DA = D * A
- mul(CB, C, B); // CB = C * B
- add(x_3, DA, CB); // x_3 = (DA + CB)^2
- square(x_3, x_3);
- sub(z_3, DA, CB); // z_3 = x_1 * (DA - CB)^2
- square(z_3, z_3);
- mul(z_3, z_3, x_1);
- mul(x_2, AA, BB); // x_2 = AA * BB
- mulA24(z_2, E); // z_2 = E * (AA + a24 * E)
- add(z_2, z_2, AA);
- mul(z_2, z_2, E);
+ private void reduce(int[] result, int[] x, int size) {
+ int index, limb, carry;
- // Move onto the next lower bit of "s".
- if (sbit > 0) {
- --sbit;
- } else if (sposn == 0) {
- break;
- } else if (sposn == 1) {
- --sposn;
- svalue = s[sposn] & 0xF8;
- sbit = 7;
- } else {
- --sposn;
- svalue = s[sposn];
- sbit = 7;
+ // Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
+ // either produce the answer we want or it will produce a
+ // value of the form "answer + j * (2^255 - 19)". There are
+ // 5 left-over bits in the top-most limb of the bottom half.
+ carry = 0;
+ limb = x[NUM_LIMBS_255BIT - 1] >> 21;
+ x[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
+ for (index = 0; index < size; ++index) {
+ limb += x[NUM_LIMBS_255BIT + index] << 5;
+ carry += (limb & 0x03FFFFFF) * 19 + x[index];
+ x[index] = carry & 0x03FFFFFF;
+ limb >>= 26;
+ carry >>= 26;
+ }
+ if (size < NUM_LIMBS_255BIT) {
+ // The high order half of the number is short; e.g. for mulA24().
+ // Propagate the carry through the rest of the low order part.
+ for (index = size; index < NUM_LIMBS_255BIT; ++index) {
+ carry += x[index];
+ x[index] = carry & 0x03FFFFFF;
+ carry >>= 26;
}
}
- // Final conditional swaps.
- cswap(swap, x_2, x_3);
- cswap(swap, z_2, z_3);
+ // The "j" value may still be too large due to the final carry-out.
+ // We must repeat the reduction. If we already have the answer,
+ // then this won't do any harm but we must still do the calculation
+ // to preserve the overall timing. The "j" value will be between
+ // 0 and 19, which means that the carry we care about is in the
+ // top 5 bits of the highest limb of the bottom half.
+ carry = (x[NUM_LIMBS_255BIT - 1] >> 21) * 19;
+ x[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
+ for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
+ carry += x[index];
+ result[index] = carry & 0x03FFFFFF;
+ carry >>= 26;
+ }
+
+ // At this point "x" will either be the answer or it will be the
+ // answer plus (2^255 - 19). Perform a trial subtraction to
+ // complete the reduction process.
+ reduceQuick(result);
}
/**
- * Evaluates the Curve25519 curve.
+ * Reduces a number modulo 2^255 - 19 where it is known that the
+ * number can be reduced with only 1 trial subtraction.
*
- * @param result Buffer to place the result of the evaluation into.
- * @param offset Offset into the result buffer.
- * @param privateKey The private key to use in the evaluation.
- * @param publicKey The public key to use in the evaluation, or null
- * if the base point of the curve should be used.
+ * @param x The number to reduce, and the result.
*/
- public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey)
- {
- Curve25519 state = new Curve25519();
- try {
- // Unpack the public key value. If null, use 9 as the base point.
- Arrays.fill(state.x_1, 0);
- if (publicKey != null) {
- // Convert the input value from little-endian into 26-bit limbs.
- for (int index = 0; index < 32; ++index) {
- int bit = (index * 8) % 26;
- int word = (index * 8) / 26;
- int value = publicKey[index] & 0xFF;
- if (bit <= (26 - 8)) {
- state.x_1[word] |= value << bit;
- } else {
- state.x_1[word] |= value << bit;
- state.x_1[word] &= 0x03FFFFFF;
- state.x_1[word + 1] |= value >> (26 - bit);
- }
- }
+ private void reduceQuick(int[] x) {
+ int index, carry;
- // Just in case, we reduce the number modulo 2^255 - 19 to
- // make sure that it is in range of the field before we start.
- // This eliminates values between 2^255 - 19 and 2^256 - 1.
- state.reduceQuick(state.x_1);
- state.reduceQuick(state.x_1);
- } else {
- state.x_1[0] = 9;
- }
+ // Perform a trial subtraction of (2^255 - 19) from "x" which is
+ // equivalent to adding 19 and subtracting 2^255. We add 19 here;
+ // the subtraction of 2^255 occurs in the next step.
+ carry = 19;
+ for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
+ carry += x[index];
+ t2[index] = carry & 0x03FFFFFF;
+ carry >>= 26;
+ }
- // Initialize the other temporary variables.
- Arrays.fill(state.x_2, 0); // x_2 = 1
- state.x_2[0] = 1;
- Arrays.fill(state.z_2, 0); // z_2 = 0
- System.arraycopy(state.x_1, 0, state.x_3, 0, state.x_1.length); // x_3 = x_1
- Arrays.fill(state.z_3, 0); // z_3 = 1
- state.z_3[0] = 1;
+ // If there was a borrow, then the original "x" is the correct answer.
+ // If there was no borrow, then "t2" is the correct answer. Select the
+ // correct answer but do it in a way that instruction timing will not
+ // reveal which value was selected. Borrow will occur if bit 21 of
+ // "t2" is zero. Turn the bit into a selection mask.
+ int mask = -((t2[NUM_LIMBS_255BIT - 1] >> 21) & 0x01);
+ int nmask = ~mask;
+ t2[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
+ for (index = 0; index < NUM_LIMBS_255BIT; ++index)
+ x[index] = (x[index] & nmask) | (t2[index] & mask);
+ }
- // Evaluate the curve for every bit of the private key.
- state.evalCurve(privateKey);
+ /**
+ * Squares a number modulo 2^255 - 19.
+ *
+ * @param result The result.
+ * @param x The number to square.
+ */
+ private void square(int[] result, int[] x) {
+ mul(result, x, x);
+ }
- // Compute x_2 * (z_2 ^ (p - 2)) where p = 2^255 - 19.
- state.recip(state.z_3, state.z_2);
- state.mul(state.x_2, state.x_2, state.z_3);
+ /**
+ * Subtracts two numbers modulo 2^255 - 19.
+ *
+ * @param result The result.
+ * @param x The first number to subtract.
+ * @param y The second number to subtract.
+ */
+ private void sub(int[] result, int[] x, int[] y) {
+ int index, borrow;
- // Convert x_2 into little-endian in the result buffer.
- for (int index = 0; index < 32; ++index) {
- int bit = (index * 8) % 26;
- int word = (index * 8) / 26;
- if (bit <= (26 - 8))
- result[offset + index] = (byte)(state.x_2[word] >> bit);
- else
- result[offset + index] = (byte)((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
- }
- } finally {
- // Clean up all temporary state before we exit.
- state.destroy();
+ // Subtract y from x to generate the intermediate result.
+ borrow = 0;
+ for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
+ borrow = x[index] - y[index] - ((borrow >> 26) & 0x01);
+ result[index] = borrow & 0x03FFFFFF;
}
+
+ // If we had a borrow, then the result has gone negative and we
+ // have to add 2^255 - 19 to the result to make it positive again.
+ // The top bits of "borrow" will be all 1's if there is a borrow
+ // or it will be all 0's if there was no borrow. Easiest is to
+ // conditionally subtract 19 and then mask off the high bits.
+ borrow = result[0] - ((-((borrow >> 26) & 0x01)) & 19);
+ result[0] = borrow & 0x03FFFFFF;
+ for (index = 1; index < NUM_LIMBS_255BIT; ++index) {
+ borrow = result[index] - ((borrow >> 26) & 0x01);
+ result[index] = borrow & 0x03FFFFFF;
+ }
+ result[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
}
}
diff --git a/app/src/main/java/com/wireguard/crypto/KeyEncoding.java b/app/src/main/java/com/wireguard/crypto/KeyEncoding.java
index 92e03230..ba867668 100644
--- a/app/src/main/java/com/wireguard/crypto/KeyEncoding.java
+++ b/app/src/main/java/com/wireguard/crypto/KeyEncoding.java
@@ -13,10 +13,10 @@ public final class KeyEncoding {
public static final int KEY_LENGTH_HEX = 64;
private static final String KEY_LENGTH_BASE64_EXCEPTION_MESSAGE =
"WireGuard base64 keys must be 44 characters encoding 32 bytes";
- private static final String KEY_LENGTH_HEX_EXCEPTION_MESSAGE =
- "WireGuard hex keys must be 64 characters encoding 32 bytes";
private static final String KEY_LENGTH_EXCEPTION_MESSAGE =
"WireGuard keys must be 32 bytes";
+ private static final String KEY_LENGTH_HEX_EXCEPTION_MESSAGE =
+ "WireGuard hex keys must be 64 characters encoding 32 bytes";
private KeyEncoding() {
// Prevent instantiation.
@@ -82,23 +82,6 @@ public final class KeyEncoding {
return key;
}
- public static String keyToBase64(final byte[] key) {
- final char[] output = new char[KEY_LENGTH_BASE64];
- if (key.length != KEY_LENGTH)
- throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
- int i;
- for (i = 0; i < KEY_LENGTH / 3; ++i)
- encodeBase64(key, i * 3, output, i * 4);
- final byte[] endSegment = {
- key[i * 3],
- key[i * 3 + 1],
- 0,
- };
- encodeBase64(endSegment, 0, output, i * 4);
- output[KEY_LENGTH_BASE64 - 1] = '=';
- return new String(output);
- }
-
public static byte[] keyFromHex(final String str) {
final char[] input = str.toCharArray();
final byte[] key = new byte[KEY_LENGTH];
@@ -110,7 +93,7 @@ public final class KeyEncoding {
for (int i = 0; i < KEY_LENGTH_HEX; ++i) {
c = input[i];
c_num = c ^ 48;
- c_num0 = (c_num - 10) >>8;
+ c_num0 = (c_num - 10) >> 8;
c_alpha = (c & ~32) - 55;
c_alpha0 = ((c_alpha - 10) ^ (c_alpha - 16)) >> 8;
if ((c_num0 | c_alpha0) == 0)
@@ -119,19 +102,36 @@ public final class KeyEncoding {
if (state == 0)
c_acc = c_val * 16;
else
- key[i / 2] = (byte)(c_acc | c_val);
+ key[i / 2] = (byte) (c_acc | c_val);
state = ~state;
}
return key;
}
+ public static String keyToBase64(final byte[] key) {
+ final char[] output = new char[KEY_LENGTH_BASE64];
+ if (key.length != KEY_LENGTH)
+ throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
+ int i;
+ for (i = 0; i < KEY_LENGTH / 3; ++i)
+ encodeBase64(key, i * 3, output, i * 4);
+ final byte[] endSegment = {
+ key[i * 3],
+ key[i * 3 + 1],
+ 0,
+ };
+ encodeBase64(endSegment, 0, output, i * 4);
+ output[KEY_LENGTH_BASE64 - 1] = '=';
+ return new String(output);
+ }
+
public static String keyToHex(final byte[] key) {
final char[] output = new char[KEY_LENGTH_HEX];
if (key.length != KEY_LENGTH)
throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
for (int i = 0; i < KEY_LENGTH; ++i) {
- output[i * 2] = (char)(87 + (key[i] >> 4 & 0xf) + ((((key[i] >> 4 & 0xf) - 10) >> 8) & ~38));
- output[i * 2 + 1] = (char)(87 + (key[i] & 0xf) + ((((key[i] & 0xf) - 10) >> 8) & ~38));
+ output[i * 2] = (char) (87 + (key[i] >> 4 & 0xf) + ((((key[i] >> 4 & 0xf) - 10) >> 8) & ~38));
+ output[i * 2 + 1] = (char) (87 + (key[i] & 0xf) + ((((key[i] & 0xf) - 10) >> 8) & ~38));
}
return new String(output);
}
diff --git a/app/src/main/res/layout/tunnel_editor_fragment.xml b/app/src/main/res/layout/tunnel_editor_fragment.xml
index 964aff5c..70f376af 100644
--- a/app/src/main/res/layout/tunnel_editor_fragment.xml
+++ b/app/src/main/res/layout/tunnel_editor_fragment.xml
@@ -114,11 +114,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/public_key_label"
+ android:contentDescription="@string/public_key_description"
android:ellipsize="end"
android:focusable="false"
android:hint="@string/hint_generated"
android:maxLines="1"
- android:contentDescription="@string/public_key_description"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interfaceSection.publicKey}" />
diff --git a/app/src/main/res/menu/config_editor.xml b/app/src/main/res/menu/config_editor.xml
index bb58f6c9..dd0137df 100644
--- a/app/src/main/res/menu/config_editor.xml
+++ b/app/src/main/res/menu/config_editor.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_action_save"
android:alphabeticShortcut="s"
diff --git a/app/src/main/res/menu/main_activity.xml b/app/src/main/res/menu/main_activity.xml
index 54211ec4..ce593296 100644
--- a/app/src/main/res/menu/main_activity.xml
+++ b/app/src/main/res/menu/main_activity.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_settings"
android:alphabeticShortcut="s"
diff --git a/app/src/main/res/menu/tunnel_detail.xml b/app/src/main/res/menu/tunnel_detail.xml
index 8e2c2eb9..2834a661 100644
--- a/app/src/main/res/menu/tunnel_detail.xml
+++ b/app/src/main/res/menu/tunnel_detail.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_action_edit"
android:alphabeticShortcut="e"
diff --git a/app/src/main/res/menu/tunnel_list_action_mode.xml b/app/src/main/res/menu/tunnel_list_action_mode.xml
index 6d175573..6b03cd19 100644
--- a/app/src/main/res/menu/tunnel_list_action_mode.xml
+++ b/app/src/main/res/menu/tunnel_list_action_mode.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_action_delete"
android:alphabeticShortcut="d"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a2a79cf9..f028d2b6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:tools="http://schemas.android.com/tools">
+<resources>
<plurals name="delete_error">
<item quantity="one">Unable to delete %d tunnel: %s</item>
<item quantity="other">Unable to delete %d tunnels: %s</item>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 37957a7b..1fda6aa6 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -2,9 +2,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" />
+
<style name="SettingsTheme" parent="AppTheme">
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
</style>
+
<style name="fab_label" parent="android:TextAppearance.DeviceDefault.Inverse">
<item name="android:background">@drawable/fab_label_background</item>
</style>