global: Automatic code formatting
Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
parent
e2636320b7
commit
7eedf08d4b
@ -35,8 +35,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".activity.SettingsActivity"
|
android:name=".activity.SettingsActivity"
|
||||||
android:label="@string/settings"
|
android:label="@string/settings"
|
||||||
android:theme="@style/SettingsTheme"
|
android:parentActivityName=".activity.MainActivity"
|
||||||
android:parentActivityName=".activity.MainActivity" />
|
android:theme="@style/SettingsTheme" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.TunnelCreatorActivity"
|
android:name=".activity.TunnelCreatorActivity"
|
||||||
@ -58,11 +58,12 @@
|
|||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".backend.GoBackend$VpnService"
|
android:name=".backend.GoBackend$VpnService"
|
||||||
android:permission="android.permission.BIND_VPN_SERVICE" >
|
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.net.VpnService" />
|
<action android:name="android.net.VpnService" />
|
||||||
</intent-filter>
|
</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" />
|
android:value="false" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ public class Application extends android.app.Application {
|
|||||||
public interface ApplicationComponent {
|
public interface ApplicationComponent {
|
||||||
AsyncWorker getAsyncWorker();
|
AsyncWorker getAsyncWorker();
|
||||||
|
|
||||||
|
Class getBackendType();
|
||||||
|
|
||||||
ToolsInstaller getToolsInstaller();
|
ToolsInstaller getToolsInstaller();
|
||||||
|
|
||||||
TunnelManager getTunnelManager();
|
TunnelManager getTunnelManager();
|
||||||
|
|
||||||
Class getBackendType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
|
@ -23,11 +23,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class SettingsActivity extends AppCompatActivity {
|
public class SettingsActivity extends AppCompatActivity {
|
||||||
@FunctionalInterface
|
|
||||||
public interface PermissionRequestCallback {
|
|
||||||
void done(String[] permissions, int[] grantResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashMap<Integer, PermissionRequestCallback> permissionRequestCallbacks = new HashMap<>();
|
private HashMap<Integer, PermissionRequestCallback> permissionRequestCallbacks = new HashMap<>();
|
||||||
private int permissionRequestCounter = 0;
|
private int permissionRequestCounter = 0;
|
||||||
|
|
||||||
@ -48,15 +43,6 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), idx);
|
ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -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 {
|
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String key) {
|
public void onCreatePreferences(final Bundle savedInstanceState, final String key) {
|
||||||
|
@ -27,48 +27,20 @@ import java9.util.concurrent.CompletableFuture;
|
|||||||
|
|
||||||
public final class GoBackend implements Backend {
|
public final class GoBackend implements Backend {
|
||||||
private static final String TAG = "WireGuard/" + GoBackend.class.getSimpleName();
|
private static final String TAG = "WireGuard/" + GoBackend.class.getSimpleName();
|
||||||
|
private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("wg-go");
|
System.loadLibrary("wg-go");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Context context;
|
||||||
private Tunnel currentTunnel;
|
private Tunnel currentTunnel;
|
||||||
private int currentTunnelHandle = -1;
|
private int currentTunnelHandle = -1;
|
||||||
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
public GoBackend(Context context) {
|
public GoBackend(Context context) {
|
||||||
this.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 wgGetSocketV4(int handle);
|
||||||
|
|
||||||
private static native int wgGetSocketV6(int handle);
|
private static native int wgGetSocketV6(int handle);
|
||||||
@ -219,4 +191,30 @@ public final class GoBackend implements Backend {
|
|||||||
currentTunnelHandle = -1;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ import com.wireguard.config.Config;
|
|||||||
public class TunnelDetailFragment extends BaseFragment {
|
public class TunnelDetailFragment extends BaseFragment {
|
||||||
private TunnelDetailFragmentBinding binding;
|
private TunnelDetailFragmentBinding binding;
|
||||||
|
|
||||||
|
private void onConfigLoaded(final String name, final Config config) {
|
||||||
|
binding.setConfig(new Config.Observable(config, name));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -46,10 +50,6 @@ public class TunnelDetailFragment extends BaseFragment {
|
|||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onConfigLoaded(final String name, final Config config) {
|
|
||||||
binding.setConfig(new Config.Observable(config, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
|
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
|
||||||
if (binding == null)
|
if (binding == null)
|
||||||
|
@ -3,8 +3,6 @@ package com.wireguard.android.fragment;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
@ -41,46 +39,30 @@ public class TunnelEditorFragment extends BaseFragment {
|
|||||||
binding.setConfig(new Config.Observable(config, name));
|
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
|
@Override
|
||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.config_editor, menu);
|
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,
|
@Override
|
||||||
final Throwable throwable) {
|
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
final String message;
|
outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig());
|
||||||
if (throwable == null) {
|
outState.putString(KEY_ORIGINAL_NAME, tunnel == null ? null : tunnel.getName());
|
||||||
message = getString(R.string.config_save_success, savedTunnel.getName());
|
super.onSaveInstanceState(outState);
|
||||||
Log.d(TAG, message);
|
}
|
||||||
onFinished();
|
|
||||||
} else {
|
@Override
|
||||||
final String error = ExceptionLoggers.unwrap(throwable).getMessage();
|
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
|
||||||
message = getString(R.string.config_save_error, savedTunnel.getName(), error);
|
tunnel = newTunnel;
|
||||||
Log.e(TAG, message, throwable);
|
if (binding == null)
|
||||||
if (binding != null) {
|
return;
|
||||||
final CoordinatorLayout container = binding.mainContainer;
|
binding.setConfig(new Config.Observable(null, null));
|
||||||
Snackbar.make(container, message, Snackbar.LENGTH_LONG).show();
|
if (tunnel != null)
|
||||||
}
|
tunnel.getConfigAsync().thenAccept(a -> onConfigLoaded(tunnel.getName(), a));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTunnelCreated(final Tunnel newTunnel, final Throwable throwable) {
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import android.widget.AbsListView.MultiChoiceModeListener;
|
|||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.AdapterView.OnItemLongClickListener;
|
import android.widget.AdapterView.OnItemLongClickListener;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.Application;
|
||||||
import com.wireguard.android.Application.ApplicationComponent;
|
import com.wireguard.android.Application.ApplicationComponent;
|
||||||
@ -44,7 +43,6 @@ import java.io.BufferedReader;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
@ -70,6 +68,14 @@ public class TunnelListFragment extends BaseFragment {
|
|||||||
private TunnelListFragmentBinding binding;
|
private TunnelListFragmentBinding binding;
|
||||||
private TunnelManager tunnelManager;
|
private TunnelManager tunnelManager;
|
||||||
|
|
||||||
|
public boolean collapseActionMenu() {
|
||||||
|
if (binding.createMenu.isExpanded()) {
|
||||||
|
binding.createMenu.collapse();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void importTunnel(final Uri uri) {
|
private void importTunnel(final Uri uri) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
if (activity == null)
|
if (activity == null)
|
||||||
@ -199,14 +205,6 @@ public class TunnelListFragment extends BaseFragment {
|
|||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean collapseActionMenu() {
|
|
||||||
if (binding.createMenu.isExpanded()) {
|
|
||||||
binding.createMenu.collapse();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onRequestCreateConfig(@SuppressWarnings("unused") final View view) {
|
public void onRequestCreateConfig(@SuppressWarnings("unused") final View view) {
|
||||||
startActivity(new Intent(getActivity(), TunnelCreatorActivity.class));
|
startActivity(new Intent(getActivity(), TunnelCreatorActivity.class));
|
||||||
if (binding != null)
|
if (binding != null)
|
||||||
@ -254,7 +252,7 @@ public class TunnelListFragment extends BaseFragment {
|
|||||||
if (tunnels.size() == 1 && throwables.isEmpty())
|
if (tunnels.size() == 1 && throwables.isEmpty())
|
||||||
message = getString(R.string.import_success, tunnels.get(0).getName());
|
message = getString(R.string.import_success, tunnels.get(0).getName());
|
||||||
else if (tunnels.isEmpty() && throwables.size() == 1)
|
else if (tunnels.isEmpty() && throwables.size() == 1)
|
||||||
/* Use the exception message from above. */;
|
/* Use the exception message from above. */ ;
|
||||||
else if (throwables.isEmpty())
|
else if (throwables.isEmpty())
|
||||||
message = getString(R.string.import_total_success, tunnels.size());
|
message = getString(R.string.import_total_success, tunnels.size());
|
||||||
else if (!throwables.isEmpty())
|
else if (!throwables.isEmpty())
|
||||||
|
@ -128,15 +128,6 @@ public final class TunnelManager extends BaseObservable {
|
|||||||
return tunnels;
|
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() {
|
public void onCreate() {
|
||||||
asyncWorker.supplyAsync(configStore::enumerate)
|
asyncWorker.supplyAsync(configStore::enumerate)
|
||||||
.thenAcceptBoth(asyncWorker.supplyAsync(backend::enumerate), this::onTunnelsLoaded)
|
.thenAcceptBoth(asyncWorker.supplyAsync(backend::enumerate), this::onTunnelsLoaded)
|
||||||
@ -151,6 +142,15 @@ public final class TunnelManager extends BaseObservable {
|
|||||||
setLastUsedTunnel(tunnels.get(lastUsedName));
|
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() {
|
public CompletionStage<Void> restoreState() {
|
||||||
if (!preferences.getBoolean(KEY_RESTORE_ON_BOOT, false))
|
if (!preferences.getBoolean(KEY_RESTORE_ON_BOOT, false))
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
|
@ -6,9 +6,9 @@ import android.content.pm.PackageManager;
|
|||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.view.ContextThemeWrapper;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.ContextThemeWrapper;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.Application;
|
||||||
import com.wireguard.android.Application.ApplicationComponent;
|
import com.wireguard.android.Application.ApplicationComponent;
|
||||||
@ -25,7 +25,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
@ -50,19 +49,6 @@ public class ZipExporterPreference extends Preference {
|
|||||||
tunnelManager = applicationComponent.getTunnelManager();
|
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() {
|
private void exportZip() {
|
||||||
List<Tunnel> tunnels = new ArrayList<>(tunnelManager.getTunnels());
|
List<Tunnel> tunnels = new ArrayList<>(tunnelManager.getTunnels());
|
||||||
List<CompletableFuture<Config>> futureConfigs = new ArrayList<>(tunnels.size());
|
List<CompletableFuture<Config>> futureConfigs = new ArrayList<>(tunnels.size());
|
||||||
@ -123,10 +109,23 @@ public class ZipExporterPreference extends Preference {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
protected void onClick() {
|
protected void onClick() {
|
||||||
getPrefActivity(this).ensurePermissions(
|
getPrefActivity(this).ensurePermissions(
|
||||||
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||||
(permissions, granted) -> {
|
(permissions, granted) -> {
|
||||||
if (granted.length > 0 && granted[0] == PackageManager.PERMISSION_GRANTED)
|
if (granted.length > 0 && granted[0] == PackageManager.PERMISSION_GRANTED)
|
||||||
exportZip();
|
exportZip();
|
||||||
|
@ -30,6 +30,7 @@ enum Attribute {
|
|||||||
|
|
||||||
private static final Map<String, Attribute> KEY_MAP;
|
private static final Map<String, Attribute> KEY_MAP;
|
||||||
private static final Pattern SEPARATOR_PATTERN = Pattern.compile("\\s|=");
|
private static final Pattern SEPARATOR_PATTERN = Pattern.compile("\\s|=");
|
||||||
|
private static Method parseNumericAddressMethod;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
KEY_MAP = new HashMap<>(Attribute.values().length);
|
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 Pattern pattern;
|
||||||
private final String token;
|
private final String token;
|
||||||
|
|
||||||
@ -46,44 +55,35 @@ enum Attribute {
|
|||||||
this.token = token;
|
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) {
|
public static <T> String listToString(final List<T> list) {
|
||||||
return TextUtils.join(", ", list);
|
return TextUtils.join(", ", list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] stringToList(final String string) {
|
public static Attribute match(final CharSequence line) {
|
||||||
if (string == null)
|
return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0]);
|
||||||
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 InetAddress parseIPString(final String address) {
|
public static InetAddress parseIPString(final String address) {
|
||||||
if (address == null || address.isEmpty())
|
if (address == null || address.isEmpty())
|
||||||
throw new IllegalArgumentException("Empty address");
|
throw new IllegalArgumentException("Empty address");
|
||||||
try {
|
try {
|
||||||
return (InetAddress)parseNumericAddressMethod.invoke(null, new Object[]{address});
|
return (InetAddress) parseNumericAddressMethod.invoke(null, new Object[]{address});
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof IllegalArgumentException)
|
if (e.getCause() instanceof IllegalArgumentException)
|
||||||
throw (IllegalArgumentException)e.getCause();
|
throw (IllegalArgumentException) e.getCause();
|
||||||
else
|
else
|
||||||
throw new IllegalArgumentException(e.getCause());
|
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) {
|
public String composeWith(final Object value) {
|
||||||
return String.format("%s = %s%n", token, value);
|
return String.format("%s = %s%n", token, value);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package com.wireguard.config;
|
package com.wireguard.config;
|
||||||
|
|
||||||
import com.android.databinding.library.baseAdapters.BR;
|
|
||||||
|
|
||||||
import android.databinding.BaseObservable;
|
import android.databinding.BaseObservable;
|
||||||
import android.databinding.Bindable;
|
import android.databinding.Bindable;
|
||||||
import android.databinding.ObservableArrayList;
|
import android.databinding.ObservableArrayList;
|
||||||
@ -9,6 +7,8 @@ import android.databinding.ObservableList;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.android.databinding.library.baseAdapters.BR;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -22,90 +22,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class Config {
|
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 final Interface interfaceSection = new Interface();
|
||||||
private List<Peer> peers = new ArrayList<>();
|
private List<Peer> peers = new ArrayList<>();
|
||||||
|
|
||||||
@ -157,4 +73,86 @@ public class Config {
|
|||||||
sb.append('\n').append(peer);
|
sb.append('\n').append(peer);
|
||||||
return sb.toString();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,158 +17,34 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class Interface {
|
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<IPCidr> addressList;
|
||||||
private List<InetAddress> dnsList;
|
private List<InetAddress> dnsList;
|
||||||
private Keypair keypair;
|
private Keypair keypair;
|
||||||
private int listenPort;
|
private int listenPort;
|
||||||
private int mtu;
|
private int mtu;
|
||||||
|
|
||||||
public Interface() {
|
public Interface() {
|
||||||
addressList = new LinkedList<>();
|
addressList = new LinkedList<>();
|
||||||
dnsList = 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() {
|
private String getAddressString() {
|
||||||
if (addressList.isEmpty())
|
if (addressList.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
@ -179,6 +55,12 @@ public class Interface {
|
|||||||
return addressList.toArray(new IPCidr[addressList.size()]);
|
return addressList.toArray(new IPCidr[addressList.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getDnsString() {
|
||||||
|
if (dnsList.isEmpty())
|
||||||
|
return null;
|
||||||
|
return Attribute.listToString(getDnsStrings());
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> getDnsStrings() {
|
private List<String> getDnsStrings() {
|
||||||
List<String> strings = new LinkedList<>();
|
List<String> strings = new LinkedList<>();
|
||||||
for (final InetAddress addr : dnsList)
|
for (final InetAddress addr : dnsList)
|
||||||
@ -186,12 +68,6 @@ public class Interface {
|
|||||||
return strings;
|
return strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDnsString() {
|
|
||||||
if (dnsList.isEmpty())
|
|
||||||
return null;
|
|
||||||
return Attribute.listToString(getDnsStrings());
|
|
||||||
}
|
|
||||||
|
|
||||||
public InetAddress[] getDnses() {
|
public InetAddress[] getDnses() {
|
||||||
return dnsList.toArray(new InetAddress[dnsList.size()]);
|
return dnsList.toArray(new InetAddress[dnsList.size()]);
|
||||||
}
|
}
|
||||||
@ -244,29 +120,11 @@ public class Interface {
|
|||||||
throw new IllegalArgumentException(line);
|
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) {
|
private void setAddressString(final String addressString) {
|
||||||
this.addressList.clear();
|
this.addressList.clear();
|
||||||
addAddresses(Attribute.stringToList(addressString));
|
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) {
|
private void setDnsString(final String dnsString) {
|
||||||
this.dnsList.clear();
|
this.dnsList.clear();
|
||||||
addDnses(Attribute.stringToList(dnsString));
|
addDnses(Attribute.stringToList(dnsString));
|
||||||
@ -318,4 +176,143 @@ public class Interface {
|
|||||||
sb.append(Attribute.PRIVATE_KEY.composeWith(keypair.getPrivateKey()));
|
sb.append(Attribute.PRIVATE_KEY.composeWith(keypair.getPrivateKey()));
|
||||||
return sb.toString();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,136 +22,26 @@ import java.util.Locale;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class Peer {
|
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 List<IPCidr> allowedIPsList;
|
||||||
private InetSocketAddress endpoint;
|
private InetSocketAddress endpoint;
|
||||||
private int persistentKeepalive;
|
private int persistentKeepalive;
|
||||||
private String preSharedKey;
|
private String preSharedKey;
|
||||||
private String publicKey;
|
private String publicKey;
|
||||||
|
|
||||||
public Peer() {
|
public Peer() {
|
||||||
allowedIPsList = new LinkedList<>();
|
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() {
|
private String getAllowedIPsString() {
|
||||||
if (allowedIPsList.isEmpty())
|
if (allowedIPsList.isEmpty())
|
||||||
@ -159,10 +49,6 @@ public class Peer {
|
|||||||
return Attribute.listToString(allowedIPsList);
|
return Attribute.listToString(allowedIPsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPCidr[] getAllowedIPs() {
|
|
||||||
return allowedIPsList.toArray(new IPCidr[allowedIPsList.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InetSocketAddress getEndpoint() {
|
public InetSocketAddress getEndpoint() {
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
@ -173,24 +59,6 @@ public class Peer {
|
|||||||
return String.format(Locale.getDefault(), "%s:%d", endpoint.getHostString(), endpoint.getPort());
|
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() {
|
public int getPersistentKeepalive() {
|
||||||
return persistentKeepalive;
|
return persistentKeepalive;
|
||||||
}
|
}
|
||||||
@ -209,6 +77,24 @@ public class Peer {
|
|||||||
return publicKey;
|
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) {
|
public void parse(final String line) {
|
||||||
final Attribute key = Attribute.match(line);
|
final Attribute key = Attribute.match(line);
|
||||||
if (key == Attribute.ALLOWED_IPS)
|
if (key == Attribute.ALLOWED_IPS)
|
||||||
@ -225,14 +111,6 @@ public class Peer {
|
|||||||
throw new IllegalArgumentException(line);
|
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) {
|
private void setAllowedIPsString(final String allowedIPsString) {
|
||||||
this.allowedIPsList.clear();
|
this.allowedIPsList.clear();
|
||||||
addAllowedIPs(Attribute.stringToList(allowedIPsString));
|
addAllowedIPs(Attribute.stringToList(allowedIPsString));
|
||||||
@ -246,7 +124,7 @@ public class Peer {
|
|||||||
if (endpoint != null && !endpoint.isEmpty()) {
|
if (endpoint != null && !endpoint.isEmpty()) {
|
||||||
InetSocketAddress constructedEndpoint;
|
InetSocketAddress constructedEndpoint;
|
||||||
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
|
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;
|
URI uri;
|
||||||
try {
|
try {
|
||||||
uri = new URI("wg://" + endpoint);
|
uri = new URI("wg://" + endpoint);
|
||||||
@ -301,4 +179,123 @@ public class Peer {
|
|||||||
sb.append(Attribute.PUBLIC_KEY.composeWith(publicKey));
|
sb.append(Attribute.PUBLIC_KEY.composeWith(publicKey));
|
||||||
return sb.toString();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,16 +26,16 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the Curve25519 elliptic curve algorithm.
|
* Implementation of the Curve25519 elliptic curve algorithm.
|
||||||
*
|
* <p>
|
||||||
* This implementation is based on that from arduinolibs:
|
* This implementation is based on that from arduinolibs:
|
||||||
* https://github.com/rweather/arduinolibs
|
* https://github.com/rweather/arduinolibs
|
||||||
*
|
* <p>
|
||||||
* This implementation is copied verbatim from noise-java:
|
* This implementation is copied verbatim from noise-java:
|
||||||
* https://github.com/rweather/noise-java
|
* https://github.com/rweather/noise-java
|
||||||
*
|
* <p>
|
||||||
* Differences in this version are due to using 26-bit limbs for the
|
* 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.
|
* representation instead of the 8/16/32-bit limbs in the original.
|
||||||
*
|
* <p>
|
||||||
* References: http://cr.yp.to/ecdh.html, RFC 7748
|
* References: http://cr.yp.to/ecdh.html, RFC 7748
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ALL")
|
@SuppressWarnings("ALL")
|
||||||
@ -44,47 +44,148 @@ public final class Curve25519 {
|
|||||||
// Numbers modulo 2^255 - 19 are broken up into ten 26-bit words.
|
// 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_255BIT = 10;
|
||||||
private static final int NUM_LIMBS_510BIT = 20;
|
private static final int NUM_LIMBS_510BIT = 20;
|
||||||
|
private int[] A;
|
||||||
|
private int[] AA;
|
||||||
|
private int[] B;
|
||||||
|
private int[] BB;
|
||||||
|
private int[] C;
|
||||||
|
private int[] CB;
|
||||||
|
private int[] D;
|
||||||
|
private int[] DA;
|
||||||
|
private int[] E;
|
||||||
|
private long[] t1;
|
||||||
|
private int[] t2;
|
||||||
private int[] x_1;
|
private int[] x_1;
|
||||||
private int[] x_2;
|
private int[] x_2;
|
||||||
private int[] x_3;
|
private int[] x_3;
|
||||||
private int[] z_2;
|
private int[] z_2;
|
||||||
private int[] z_3;
|
private int[] z_3;
|
||||||
private int[] A;
|
|
||||||
private int[] B;
|
|
||||||
private int[] C;
|
|
||||||
private int[] D;
|
|
||||||
private int[] E;
|
|
||||||
private int[] AA;
|
|
||||||
private int[] BB;
|
|
||||||
private int[] DA;
|
|
||||||
private int[] CB;
|
|
||||||
private long[] t1;
|
|
||||||
private int[] t2;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the temporary state holder for Curve25519 evaluation.
|
* Constructs the temporary state holder for Curve25519 evaluation.
|
||||||
*/
|
*/
|
||||||
private Curve25519()
|
private Curve25519() {
|
||||||
{
|
|
||||||
// Allocate memory for all of the temporary variables we will need.
|
// Allocate memory for all of the temporary variables we will need.
|
||||||
x_1 = new int [NUM_LIMBS_255BIT];
|
x_1 = new int[NUM_LIMBS_255BIT];
|
||||||
x_2 = new int [NUM_LIMBS_255BIT];
|
x_2 = new int[NUM_LIMBS_255BIT];
|
||||||
x_3 = new int [NUM_LIMBS_255BIT];
|
x_3 = new int[NUM_LIMBS_255BIT];
|
||||||
z_2 = new int [NUM_LIMBS_255BIT];
|
z_2 = new int[NUM_LIMBS_255BIT];
|
||||||
z_3 = new int [NUM_LIMBS_255BIT];
|
z_3 = new int[NUM_LIMBS_255BIT];
|
||||||
A = new int [NUM_LIMBS_255BIT];
|
A = new int[NUM_LIMBS_255BIT];
|
||||||
B = new int [NUM_LIMBS_255BIT];
|
B = new int[NUM_LIMBS_255BIT];
|
||||||
C = new int [NUM_LIMBS_255BIT];
|
C = new int[NUM_LIMBS_255BIT];
|
||||||
D = new int [NUM_LIMBS_255BIT];
|
D = new int[NUM_LIMBS_255BIT];
|
||||||
E = new int [NUM_LIMBS_255BIT];
|
E = new int[NUM_LIMBS_255BIT];
|
||||||
AA = new int [NUM_LIMBS_255BIT];
|
AA = new int[NUM_LIMBS_255BIT];
|
||||||
BB = new int [NUM_LIMBS_255BIT];
|
BB = new int[NUM_LIMBS_255BIT];
|
||||||
DA = new int [NUM_LIMBS_255BIT];
|
DA = new int[NUM_LIMBS_255BIT];
|
||||||
CB = new int [NUM_LIMBS_255BIT];
|
CB = new int[NUM_LIMBS_255BIT];
|
||||||
t1 = new long [NUM_LIMBS_510BIT];
|
t1 = new long[NUM_LIMBS_510BIT];
|
||||||
t2 = new int [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.
|
* Destroy all sensitive data in this object.
|
||||||
@ -105,298 +206,8 @@ public final class Curve25519 {
|
|||||||
Arrays.fill(BB, 0);
|
Arrays.fill(BB, 0);
|
||||||
Arrays.fill(DA, 0);
|
Arrays.fill(DA, 0);
|
||||||
Arrays.fill(CB, 0);
|
Arrays.fill(CB, 0);
|
||||||
Arrays.fill(t1, 0L);
|
Arrays.fill(t1, 0L);
|
||||||
Arrays.fill(t2, 0);
|
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.
|
|
||||||
*
|
|
||||||
* @param x The number to reduce, and the result.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
private void mul(int[] result, int[] x, int[] y)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
// Multiply the two numbers to create the intermediate result.
|
|
||||||
long v = x[0];
|
|
||||||
for (i = 0; i < NUM_LIMBS_255BIT; ++i) {
|
|
||||||
t1[i] = v * y[i];
|
|
||||||
}
|
|
||||||
for (i = 1; i < NUM_LIMBS_255BIT; ++i) {
|
|
||||||
v = x[i];
|
|
||||||
for (j = 0; j < (NUM_LIMBS_255BIT - 1); ++j) {
|
|
||||||
t1[i + j] += v * y[j];
|
|
||||||
}
|
|
||||||
t1[i + NUM_LIMBS_255BIT - 1] = v * y[NUM_LIMBS_255BIT - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Propagate carries and convert back into 26-bit words.
|
|
||||||
v = t1[0];
|
|
||||||
t2[0] = ((int)v) & 0x03FFFFFF;
|
|
||||||
for (i = 1; i < NUM_LIMBS_510BIT; ++i) {
|
|
||||||
v = (v >> 26) + t1[i];
|
|
||||||
t2[i] = ((int)v) & 0x03FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce the result modulo 2^255 - 19.
|
|
||||||
reduce(result, t2, NUM_LIMBS_255BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
carry >>= 26;
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
private void pow250(int[] result, int[] x)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
// The big-endian hexadecimal expansion of (2^250 - 1) is:
|
|
||||||
// 03FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
|
|
||||||
//
|
|
||||||
// The naive implementation needs to do 2 multiplications per 1 bit and
|
|
||||||
// 1 multiplication per 0 bit. We can improve upon this by creating a
|
|
||||||
// pattern 0000000001 ... 0000000001. If we square and multiply the
|
|
||||||
// pattern by itself we can turn the pattern into the partial results
|
|
||||||
// 0000000011 ... 0000000011, 0000000111 ... 0000000111, etc.
|
|
||||||
// This averages out to about 1.1 multiplications per 1 bit instead of 2.
|
|
||||||
|
|
||||||
// Build a pattern of 250 bits in length of repeated copies of 0000000001.
|
|
||||||
square(A, x);
|
|
||||||
for (j = 0; j < 9; ++j)
|
|
||||||
square(A, A);
|
|
||||||
mul(result, A, x);
|
|
||||||
for (i = 0; i < 23; ++i) {
|
|
||||||
for (j = 0; j < 10; ++j)
|
|
||||||
square(A, A);
|
|
||||||
mul(result, result, A);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiply bit-shifted versions of the 0000000001 pattern into
|
|
||||||
// the result to "fill in" the gaps in the pattern.
|
|
||||||
square(A, result);
|
|
||||||
mul(result, result, A);
|
|
||||||
for (j = 0; j < 8; ++j) {
|
|
||||||
square(A, A);
|
|
||||||
mul(result, result, A);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the reciprocal of a number modulo 2^255 - 19.
|
|
||||||
*
|
|
||||||
* @param result The result. Must not overlap with x.
|
|
||||||
* @param x The argument.
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
// Start with the 250 upper bits of the expansion of (p - 2).
|
|
||||||
pow250(result, x);
|
|
||||||
|
|
||||||
// Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
|
|
||||||
square(result, result);
|
|
||||||
square(result, result);
|
|
||||||
mul(result, result, x);
|
|
||||||
square(result, result);
|
|
||||||
square(result, result);
|
|
||||||
mul(result, result, x);
|
|
||||||
square(result, result);
|
|
||||||
mul(result, result, x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -404,8 +215,7 @@ public final class Curve25519 {
|
|||||||
*
|
*
|
||||||
* @param s The 32-byte secret key.
|
* @param s The 32-byte secret key.
|
||||||
*/
|
*/
|
||||||
private void evalCurve(byte[] s)
|
private void evalCurve(byte[] s) {
|
||||||
{
|
|
||||||
int sposn = 31;
|
int sposn = 31;
|
||||||
int sbit = 6;
|
int sbit = 6;
|
||||||
int svalue = s[sposn] | 0x40;
|
int svalue = s[sposn] | 0x40;
|
||||||
@ -414,7 +224,7 @@ public final class Curve25519 {
|
|||||||
|
|
||||||
// Iterate over all 255 bits of "s" from the highest to the lowest.
|
// 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".
|
// We ignore the high bit of the 256-bit representation of "s".
|
||||||
for (;;) {
|
for (; ; ) {
|
||||||
// Conditional swaps on entry to this bit but only if we
|
// Conditional swaps on entry to this bit but only if we
|
||||||
// didn't swap on the previous bit.
|
// didn't swap on the previous bit.
|
||||||
select = (svalue >> sbit) & 0x01;
|
select = (svalue >> sbit) & 0x01;
|
||||||
@ -465,71 +275,247 @@ public final class Curve25519 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the Curve25519 curve.
|
* Multiplies two numbers modulo 2^255 - 19.
|
||||||
*
|
*
|
||||||
* @param result Buffer to place the result of the evaluation into.
|
* @param result The result.
|
||||||
* @param offset Offset into the result buffer.
|
* @param x The first number to multiply.
|
||||||
* @param privateKey The private key to use in the evaluation.
|
* @param y The second number to multiply.
|
||||||
* @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)
|
private void mul(int[] result, int[] x, int[] y) {
|
||||||
{
|
int i, j;
|
||||||
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
|
// Multiply the two numbers to create the intermediate result.
|
||||||
// make sure that it is in range of the field before we start.
|
long v = x[0];
|
||||||
// This eliminates values between 2^255 - 19 and 2^256 - 1.
|
for (i = 0; i < NUM_LIMBS_255BIT; ++i) {
|
||||||
state.reduceQuick(state.x_1);
|
t1[i] = v * y[i];
|
||||||
state.reduceQuick(state.x_1);
|
}
|
||||||
} else {
|
for (i = 1; i < NUM_LIMBS_255BIT; ++i) {
|
||||||
state.x_1[0] = 9;
|
v = x[i];
|
||||||
|
for (j = 0; j < (NUM_LIMBS_255BIT - 1); ++j) {
|
||||||
|
t1[i + j] += v * y[j];
|
||||||
}
|
}
|
||||||
|
t1[i + NUM_LIMBS_255BIT - 1] = v * y[NUM_LIMBS_255BIT - 1];
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the other temporary variables.
|
// Propagate carries and convert back into 26-bit words.
|
||||||
Arrays.fill(state.x_2, 0); // x_2 = 1
|
v = t1[0];
|
||||||
state.x_2[0] = 1;
|
t2[0] = ((int) v) & 0x03FFFFFF;
|
||||||
Arrays.fill(state.z_2, 0); // z_2 = 0
|
for (i = 1; i < NUM_LIMBS_510BIT; ++i) {
|
||||||
System.arraycopy(state.x_1, 0, state.x_3, 0, state.x_1.length); // x_3 = x_1
|
v = (v >> 26) + t1[i];
|
||||||
Arrays.fill(state.z_3, 0); // z_3 = 1
|
t2[i] = ((int) v) & 0x03FFFFFF;
|
||||||
state.z_3[0] = 1;
|
}
|
||||||
|
|
||||||
// Evaluate the curve for every bit of the private key.
|
// Reduce the result modulo 2^255 - 19.
|
||||||
state.evalCurve(privateKey);
|
reduce(result, t2, NUM_LIMBS_255BIT);
|
||||||
|
}
|
||||||
|
|
||||||
// Compute x_2 * (z_2 ^ (p - 2)) where p = 2^255 - 19.
|
/**
|
||||||
state.recip(state.z_3, state.z_2);
|
* Multiplies a number by the a24 constant, modulo 2^255 - 19.
|
||||||
state.mul(state.x_2, state.x_2, state.z_3);
|
*
|
||||||
|
* @param result The result.
|
||||||
|
* @param x The number to multiply by a24.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
carry >>= 26;
|
||||||
|
}
|
||||||
|
t2[NUM_LIMBS_255BIT] = ((int) carry) & 0x03FFFFFF;
|
||||||
|
reduce(result, t2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert x_2 into little-endian in the result buffer.
|
/**
|
||||||
for (int index = 0; index < 32; ++index) {
|
* Raise x to the power of (2^250 - 1).
|
||||||
int bit = (index * 8) % 26;
|
*
|
||||||
int word = (index * 8) / 26;
|
* @param result The result. Must not overlap with x.
|
||||||
if (bit <= (26 - 8))
|
* @param x The argument.
|
||||||
result[offset + index] = (byte)(state.x_2[word] >> bit);
|
*/
|
||||||
else
|
private void pow250(int[] result, int[] x) {
|
||||||
result[offset + index] = (byte)((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
|
int i, j;
|
||||||
}
|
|
||||||
} finally {
|
// The big-endian hexadecimal expansion of (2^250 - 1) is:
|
||||||
// Clean up all temporary state before we exit.
|
// 03FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
|
||||||
state.destroy();
|
//
|
||||||
|
// The naive implementation needs to do 2 multiplications per 1 bit and
|
||||||
|
// 1 multiplication per 0 bit. We can improve upon this by creating a
|
||||||
|
// pattern 0000000001 ... 0000000001. If we square and multiply the
|
||||||
|
// pattern by itself we can turn the pattern into the partial results
|
||||||
|
// 0000000011 ... 0000000011, 0000000111 ... 0000000111, etc.
|
||||||
|
// This averages out to about 1.1 multiplications per 1 bit instead of 2.
|
||||||
|
|
||||||
|
// Build a pattern of 250 bits in length of repeated copies of 0000000001.
|
||||||
|
square(A, x);
|
||||||
|
for (j = 0; j < 9; ++j)
|
||||||
|
square(A, A);
|
||||||
|
mul(result, A, x);
|
||||||
|
for (i = 0; i < 23; ++i) {
|
||||||
|
for (j = 0; j < 10; ++j)
|
||||||
|
square(A, A);
|
||||||
|
mul(result, result, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply bit-shifted versions of the 0000000001 pattern into
|
||||||
|
// the result to "fill in" the gaps in the pattern.
|
||||||
|
square(A, result);
|
||||||
|
mul(result, result, A);
|
||||||
|
for (j = 0; j < 8; ++j) {
|
||||||
|
square(A, A);
|
||||||
|
mul(result, result, A);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the reciprocal of a number modulo 2^255 - 19.
|
||||||
|
*
|
||||||
|
* @param result The result. Must not overlap with x.
|
||||||
|
* @param x The argument.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
// Start with the 250 upper bits of the expansion of (p - 2).
|
||||||
|
pow250(result, x);
|
||||||
|
|
||||||
|
// Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
|
||||||
|
square(result, result);
|
||||||
|
square(result, result);
|
||||||
|
mul(result, result, x);
|
||||||
|
square(result, result);
|
||||||
|
square(result, result);
|
||||||
|
mul(result, result, x);
|
||||||
|
square(result, result);
|
||||||
|
mul(result, result, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces a number modulo 2^255 - 19 where it is known that the
|
||||||
|
* number can be reduced with only 1 trial subtraction.
|
||||||
|
*
|
||||||
|
* @param x The number to reduce, and the result.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ public final class KeyEncoding {
|
|||||||
public static final int KEY_LENGTH_HEX = 64;
|
public static final int KEY_LENGTH_HEX = 64;
|
||||||
private static final String KEY_LENGTH_BASE64_EXCEPTION_MESSAGE =
|
private static final String KEY_LENGTH_BASE64_EXCEPTION_MESSAGE =
|
||||||
"WireGuard base64 keys must be 44 characters encoding 32 bytes";
|
"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 =
|
private static final String KEY_LENGTH_EXCEPTION_MESSAGE =
|
||||||
"WireGuard keys must be 32 bytes";
|
"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() {
|
private KeyEncoding() {
|
||||||
// Prevent instantiation.
|
// Prevent instantiation.
|
||||||
@ -82,6 +82,32 @@ public final class KeyEncoding {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] keyFromHex(final String str) {
|
||||||
|
final char[] input = str.toCharArray();
|
||||||
|
final byte[] key = new byte[KEY_LENGTH];
|
||||||
|
if (input.length != KEY_LENGTH_HEX)
|
||||||
|
throw new IllegalArgumentException(KEY_LENGTH_HEX_EXCEPTION_MESSAGE);
|
||||||
|
|
||||||
|
int c, c_acc = 0, c_alpha0, c_alpha, c_num0, c_num, c_val, state = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < KEY_LENGTH_HEX; ++i) {
|
||||||
|
c = input[i];
|
||||||
|
c_num = c ^ 48;
|
||||||
|
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)
|
||||||
|
throw new IllegalArgumentException(KEY_LENGTH_HEX_EXCEPTION_MESSAGE);
|
||||||
|
c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
|
||||||
|
if (state == 0)
|
||||||
|
c_acc = c_val * 16;
|
||||||
|
else
|
||||||
|
key[i / 2] = (byte) (c_acc | c_val);
|
||||||
|
state = ~state;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
public static String keyToBase64(final byte[] key) {
|
public static String keyToBase64(final byte[] key) {
|
||||||
final char[] output = new char[KEY_LENGTH_BASE64];
|
final char[] output = new char[KEY_LENGTH_BASE64];
|
||||||
if (key.length != KEY_LENGTH)
|
if (key.length != KEY_LENGTH)
|
||||||
@ -99,39 +125,13 @@ public final class KeyEncoding {
|
|||||||
return new String(output);
|
return new String(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] keyFromHex(final String str) {
|
|
||||||
final char[] input = str.toCharArray();
|
|
||||||
final byte[] key = new byte[KEY_LENGTH];
|
|
||||||
if (input.length != KEY_LENGTH_HEX)
|
|
||||||
throw new IllegalArgumentException(KEY_LENGTH_HEX_EXCEPTION_MESSAGE);
|
|
||||||
|
|
||||||
int c, c_acc = 0, c_alpha0, c_alpha, c_num0, c_num, c_val, state = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < KEY_LENGTH_HEX; ++i) {
|
|
||||||
c = input[i];
|
|
||||||
c_num = c ^ 48;
|
|
||||||
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)
|
|
||||||
throw new IllegalArgumentException(KEY_LENGTH_HEX_EXCEPTION_MESSAGE);
|
|
||||||
c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
|
|
||||||
if (state == 0)
|
|
||||||
c_acc = c_val * 16;
|
|
||||||
else
|
|
||||||
key[i / 2] = (byte)(c_acc | c_val);
|
|
||||||
state = ~state;
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String keyToHex(final byte[] key) {
|
public static String keyToHex(final byte[] key) {
|
||||||
final char[] output = new char[KEY_LENGTH_HEX];
|
final char[] output = new char[KEY_LENGTH_HEX];
|
||||||
if (key.length != KEY_LENGTH)
|
if (key.length != KEY_LENGTH)
|
||||||
throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
|
throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
|
||||||
for (int i = 0; i < KEY_LENGTH; ++i) {
|
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] = (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 + 1] = (char) (87 + (key[i] & 0xf) + ((((key[i] & 0xf) - 10) >> 8) & ~38));
|
||||||
}
|
}
|
||||||
return new String(output);
|
return new String(output);
|
||||||
}
|
}
|
||||||
|
@ -114,11 +114,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/public_key_label"
|
android:layout_below="@+id/public_key_label"
|
||||||
|
android:contentDescription="@string/public_key_description"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:hint="@string/hint_generated"
|
android:hint="@string/hint_generated"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:contentDescription="@string/public_key_description"
|
|
||||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||||
android:text="@{config.interfaceSection.publicKey}" />
|
android:text="@{config.interfaceSection.publicKey}" />
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_action_save"
|
android:id="@+id/menu_action_save"
|
||||||
android:alphabeticShortcut="s"
|
android:alphabeticShortcut="s"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_settings"
|
android:id="@+id/menu_settings"
|
||||||
android:alphabeticShortcut="s"
|
android:alphabeticShortcut="s"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_action_edit"
|
android:id="@+id/menu_action_edit"
|
||||||
android:alphabeticShortcut="e"
|
android:alphabeticShortcut="e"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_action_delete"
|
android:id="@+id/menu_action_delete"
|
||||||
android:alphabeticShortcut="d"
|
android:alphabeticShortcut="d"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources>
|
||||||
<plurals name="delete_error">
|
<plurals name="delete_error">
|
||||||
<item quantity="one">Unable to delete %d tunnel: %s</item>
|
<item quantity="one">Unable to delete %d tunnel: %s</item>
|
||||||
<item quantity="other">Unable to delete %d tunnels: %s</item>
|
<item quantity="other">Unable to delete %d tunnels: %s</item>
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" />
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" />
|
||||||
|
|
||||||
<style name="SettingsTheme" parent="AppTheme">
|
<style name="SettingsTheme" parent="AppTheme">
|
||||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="fab_label" parent="android:TextAppearance.DeviceDefault.Inverse">
|
<style name="fab_label" parent="android:TextAppearance.DeviceDefault.Inverse">
|
||||||
<item name="android:background">@drawable/fab_label_background</item>
|
<item name="android:background">@drawable/fab_label_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user