├── AndroidManifest.xml
├── LICENSE
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-ldpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── layout
│ ├── advanced.xml
│ ├── main.xml
│ ├── network.xml
│ ├── status.xml
│ └── tunnel.xml
├── menu
│ ├── allitems.xml
│ └── client.xml
└── values
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── frozenriver
└── sigmavpn
├── SigmaVPNClient.java
├── SigmaVPNClientNetworkFragment.java
├── SigmaVPNClientStatusFragment.java
├── SigmaVPNClientTunnelFragment.java
├── SigmaVPNProto.java
├── SigmaVPNProtoTAI64.java
├── SigmaVPNProtoZero.java
├── SigmaVPNService.java
├── SigmaVPNServiceRecv.java
└── SigmaVPNServiceSend.java
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, Neil Alexander T.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with
5 | or without modification, are permitted provided that the following
6 | conditions are met:
7 |
8 | - Redistributions of source code must retain the above copyright notice,
9 | this list of conditions and the following disclaimer.
10 | - Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 | POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-14
12 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neilalexander/sigmavpn-android/4e02508b833850465ca5cbab56fea0f905354556/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neilalexander/sigmavpn-android/4e02508b833850465ca5cbab56fea0f905354556/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neilalexander/sigmavpn-android/4e02508b833850465ca5cbab56fea0f905354556/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neilalexander/sigmavpn-android/4e02508b833850465ca5cbab56fea0f905354556/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/layout/advanced.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
21 |
22 |
27 |
28 |
31 |
32 |
36 |
37 |
42 |
43 |
46 |
47 |
54 |
55 |
56 |
59 |
60 |
63 |
64 |
69 |
70 |
73 |
74 |
80 |
81 |
86 |
87 |
94 |
95 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
112 |
115 |
116 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
23 |
--------------------------------------------------------------------------------
/res/layout/network.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
21 |
22 |
27 |
28 |
34 |
35 |
38 |
39 |
42 |
43 |
47 |
48 |
51 |
52 |
58 |
59 |
64 |
65 |
66 |
67 |
68 |
71 |
72 |
78 |
79 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/res/layout/status.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
21 |
22 |
27 |
28 |
33 |
34 |
37 |
38 |
43 |
44 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/res/layout/tunnel.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
28 |
29 |
33 |
34 |
37 |
38 |
41 |
42 |
47 |
48 |
51 |
52 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
67 |
68 |
71 |
72 |
76 |
77 |
85 |
86 |
93 |
94 |
95 |
98 |
99 |
102 |
103 |
107 |
108 |
116 |
117 |
124 |
125 |
126 |
127 |
132 |
133 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/res/menu/allitems.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/res/menu/client.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | SigmaVPN
20 |
21 | Remote Address:
22 | Remote Port:
23 | Local Private Key:
24 | Connect
25 |
26 | SigmaVPN is connecting...
27 | SigmaVPN is connected!
28 | SigmaVPN has disconnected.
29 | Tunnel Address Prefix:
30 | Remote Public Key:
31 | Enter your SigmaVPN tunnel and network details and then activate the tunnel below.
32 | Generate
33 | Local Public Key:
34 | Send this key to your peer
35 | Port unreachable
36 | Static Routes:
37 | 10.0.0.0/8, fc00::/7, ...
38 | 192.168.0.1/24, fd12:3456:7890::2/64
39 | 1.2.3.4
40 | 5678
41 | DNS Servers:
42 | Attempt to learn network settings from remote endpoint
43 | 10.0.0.1, fd12:3456:7890::1
44 | Use TAI64 nonce (more secure)
45 | 0.21
46 | Maximum Transmission Unit:
47 | 1400
48 | Idle Send Poll Frequency:
49 | Lower frequencies use more battery and CPU, but higher frequencies increase potential send delay. Default: 1000ms.
50 | Set Manually:
51 | Local Port:
52 | 1234
53 | Save
54 |
55 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
25 |
26 |
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNClient.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import com.frozenriver.sigmavpn.R;
31 |
32 | import android.app.ActionBar.Tab;
33 | import android.app.ActivityManager.RunningServiceInfo;
34 | import android.app.ActionBar;
35 | import android.app.Activity;
36 | import android.app.ActivityManager;
37 | import android.app.Dialog;
38 | import android.app.Fragment;
39 | import android.app.FragmentTransaction;
40 | import android.content.Context;
41 | import android.content.Intent;
42 | import android.content.SharedPreferences;
43 | import android.net.VpnService;
44 | import android.os.Bundle;
45 | import android.view.Menu;
46 | import android.view.MenuInflater;
47 | import android.view.MenuItem;
48 | import android.view.View;
49 | import android.widget.TextView;
50 | import android.widget.CheckBox;
51 | import android.widget.SeekBar;
52 |
53 | public class SigmaVPNClient extends Activity
54 | {
55 | SharedPreferences settings;
56 | Dialog dialog;
57 |
58 | @Override
59 | public void onCreate(Bundle savedInstanceState)
60 | {
61 | /*if ((System.currentTimeMillis() / 1000) > 1327060800)
62 | {
63 | this.finish();
64 | return;
65 | }*/
66 |
67 | ActionBar actionBar = getActionBar();
68 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
69 |
70 | Tab statusTab = actionBar.newTab()
71 | .setText("Status")
72 | .setTabListener(new TabListener(new SigmaVPNClientStatusFragment()));
73 | actionBar.addTab(statusTab);
74 |
75 | Tab tunnelTab = actionBar.newTab()
76 | .setText("Tunnel")
77 | .setTabListener(new TabListener(new SigmaVPNClientTunnelFragment()));
78 | actionBar.addTab(tunnelTab);
79 |
80 | Tab networkTab = actionBar.newTab()
81 | .setText("Network")
82 | .setTabListener(new TabListener(new SigmaVPNClientNetworkFragment()));
83 | actionBar.addTab(networkTab);
84 |
85 | settings = this.getPreferences(Context.MODE_PRIVATE);
86 |
87 | super.onCreate(savedInstanceState);
88 | setContentView(R.layout.main);
89 | }
90 |
91 | public boolean onCreateOptionsMenu(Menu menu)
92 | {
93 | MenuInflater inflater = getMenuInflater();
94 | inflater.inflate(R.menu.allitems, menu);
95 | return true;
96 | }
97 |
98 | public boolean onOptionsItemSelected(MenuItem item)
99 | {
100 | if (item.getItemId() == R.id.advanced)
101 | {
102 | showAdvancedOptions();
103 | return true;
104 | }
105 |
106 | return false;
107 | }
108 |
109 | public void showAdvancedOptions()
110 | {
111 | dialog = new Dialog(this);
112 |
113 | dialog.setContentView(R.layout.advanced);
114 | dialog.setTitle("Advanced Settings");
115 | dialog.setOwnerActivity(this);
116 | dialog.setCancelable(true);
117 | dialog.findViewById(R.id.advancedsavebutton).setOnClickListener(new View.OnClickListener()
118 | {
119 | public void onClick(View v)
120 | {
121 | saveAdvancedSettings();
122 | dialog.dismiss();
123 | }
124 | });
125 |
126 | CheckBox defineLocalSocket = (CheckBox) dialog.findViewById(R.id.definelocalsocket);
127 | defineLocalSocket.setChecked(settings.getBoolean("LocalPortSetManually", false));
128 |
129 | TextView localPortNumber = (TextView) dialog.findViewById(R.id.localportnumber);
130 | localPortNumber.setText(Integer.toString(settings.getInt("LocalPort", 1234)));
131 |
132 | TextView mtu = (TextView) dialog.findViewById(R.id.mtu);
133 | mtu.setText(Integer.toString(settings.getInt("MTU", 1400)));
134 |
135 | SeekBar sendPollFreq = (SeekBar) dialog.findViewById(R.id.sendpollfreq);
136 | sendPollFreq.setProgress(settings.getInt("SendPollFreq", 1000));
137 | sendPollFreq.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
138 | {
139 | public void onStopTrackingTouch(SeekBar arg0) {}
140 | public void onStartTrackingTouch(SeekBar arg0) {}
141 | public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2)
142 | {
143 | if (arg0.getProgress() < 100)
144 | arg0.setProgress(100);
145 | else
146 | arg0.setProgress(arg0.getProgress() - (arg0.getProgress() % 100));
147 |
148 | TextView sendPollFreqLabel = (TextView) dialog.findViewById(R.id.sendpollfreqlabel);
149 | sendPollFreqLabel.setText(arg0.getProgress() + "ms");
150 | }
151 | });
152 |
153 | TextView sendPollFreqLabel = (TextView) dialog.findViewById(R.id.sendpollfreqlabel);
154 | sendPollFreqLabel.setText(sendPollFreq.getProgress() + "ms");
155 |
156 | dialog.show();
157 | }
158 |
159 | public void saveAdvancedSettings()
160 | {
161 | if (dialog == null)
162 | return;
163 |
164 | SharedPreferences.Editor edit = settings.edit();
165 | edit.putBoolean("LocalPortSetManually", ((CheckBox) dialog.findViewById(R.id.definelocalsocket)).isChecked());
166 |
167 | int localPortNumber = Integer.parseInt(((TextView) dialog.findViewById(R.id.localportnumber)).getText().toString());
168 | if (localPortNumber > 0 && localPortNumber < 65535)
169 | edit.putInt("LocalPort", localPortNumber);
170 |
171 | int mtu = Integer.parseInt(((TextView) dialog.findViewById(R.id.mtu)).getText().toString());
172 | if (mtu >= 1280 && mtu <= 1500)
173 | edit.putInt("MTU", mtu);
174 |
175 | edit.putInt("SendPollFreq", ((SeekBar) dialog.findViewById(R.id.sendpollfreq)).getProgress());
176 | edit.commit();
177 | }
178 |
179 | @Override
180 | protected void onActivityResult(int request, int result, Intent data)
181 | {
182 | if (result == RESULT_OK)
183 | {
184 | SharedPreferences settings = getPreferences(MODE_PRIVATE);
185 | String prefix = getPackageName();
186 |
187 | Intent intent = new Intent(this, SigmaVPNService.class)
188 | .putExtra(prefix + ".REMOTEADDRESS", settings.getString("RemoteAddress", ""))
189 | .putExtra(prefix + ".REMOTEPORT", settings.getString("RemotePort", ""))
190 | .putExtra(prefix + ".TUNNELADDRESS", settings.getString("TunnelAddress", ""))
191 | .putExtra(prefix + ".TUNNELREALADDRESS", settings.getString("TunnelRealAddress", ""))
192 | .putExtra(prefix + ".TUNNELPREFIXLEN", settings.getString("TunnelPrefixLen", ""))
193 | .putExtra(prefix + ".PRIVATEKEY", settings.getString("PrivateKey", ""))
194 | .putExtra(prefix + ".PUBLICKEY", settings.getString("RemotePublicKey", ""))
195 | .putExtra(prefix + ".LOCALPUBLICKEY", settings.getString("LocalPublicKey", ""))
196 | .putExtra(prefix + ".DNSSERVERS", settings.getString("DNSServers", ""))
197 | .putExtra(prefix + ".STATICROUTES", settings.getString("StaticRoutes", ""))
198 | .putExtra(prefix + ".PROTOCOL", settings.getBoolean("UseTAI64", false) ? "nacltai" : "nacl0")
199 | .putExtra(prefix + ".MTU", settings.getInt("MTU", 1400))
200 | .putExtra(prefix + ".SENDPOLLFREQ", settings.getInt("SendPollFreq", 1000))
201 | .putExtra(prefix + ".DEFINELOCALPORT", settings.getBoolean("LocalPortSetManually", false))
202 | .putExtra(prefix + ".LOCALPORT", settings.getInt("LocalPort", 1234));
203 |
204 | startService(intent);
205 | }
206 | }
207 |
208 | private boolean checkVPNServiceActive()
209 | {
210 | ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
211 |
212 | for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
213 | {
214 | if ("com.frozenriver.sigmavpn.SigmaVPNService".equals(service.service.getClassName()))
215 | return true;
216 | }
217 | return false;
218 | }
219 |
220 | public void startVPNService()
221 | {
222 | if (!checkVPNServiceActive())
223 | {
224 | Intent intent = VpnService.prepare(this);
225 |
226 | if (intent != null)
227 | startActivityForResult(intent, 0);
228 | else
229 | onActivityResult(0, RESULT_OK, null);
230 | }
231 | }
232 |
233 | private class TabListener implements ActionBar.TabListener
234 | {
235 | private Fragment mFragment;
236 |
237 | public TabListener(Fragment fragment)
238 | {
239 | mFragment = fragment;
240 | }
241 |
242 | public void onTabSelected(Tab tab, FragmentTransaction ft)
243 | {
244 | ft.add(R.id.mainscrollview, mFragment);
245 | }
246 |
247 | public void onTabUnselected(Tab tab, FragmentTransaction ft)
248 | {
249 | ft.remove(mFragment);
250 | }
251 |
252 | public void onTabReselected(Tab tab, FragmentTransaction ft)
253 | {
254 |
255 | }
256 | }
257 | }
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNClientNetworkFragment.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import java.net.InetAddress;
31 |
32 | import com.frozenriver.sigmavpn.R;
33 |
34 | import android.app.Fragment;
35 | import android.content.Context;
36 | import android.content.SharedPreferences;
37 | import android.os.Bundle;
38 | import android.view.KeyEvent;
39 | import android.view.LayoutInflater;
40 | import android.view.View;
41 | import android.view.ViewGroup;
42 | import android.widget.TextView;
43 |
44 | public class SigmaVPNClientNetworkFragment extends Fragment implements View.OnFocusChangeListener, TextView.OnEditorActionListener
45 | {
46 | private TextView entryTunnelAddress, entryStaticRoutes, entryDNSServers;
47 | private SharedPreferences settings;
48 |
49 | @Override
50 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
51 | {
52 | setHasOptionsMenu(false);
53 |
54 | settings = this.getActivity().getPreferences(Context.MODE_PRIVATE);
55 | View v = inflater.inflate(R.layout.network, container, false);
56 |
57 | entryTunnelAddress = (TextView) v.findViewById(R.id.tunneladdress);
58 | entryTunnelAddress.setText(settings.getString("TunnelAddress", ""));
59 | entryTunnelAddress.setOnFocusChangeListener(this);
60 | entryTunnelAddress.setOnEditorActionListener(this);
61 |
62 | entryStaticRoutes = (TextView) v.findViewById(R.id.staticroutes);
63 | entryStaticRoutes.setText(settings.getString("StaticRoutes", ""));
64 | entryStaticRoutes.setOnFocusChangeListener(this);
65 | entryStaticRoutes.setOnEditorActionListener(this);
66 |
67 | entryDNSServers = (TextView) v.findViewById(R.id.dnsservers);
68 | entryDNSServers.setText(settings.getString("DNSServers", ""));
69 | entryDNSServers.setOnFocusChangeListener(this);
70 | entryDNSServers.setOnEditorActionListener(this);
71 |
72 | return v;
73 | }
74 |
75 | public boolean validate()
76 | {
77 | boolean error = false;
78 |
79 | try
80 | {
81 | String[] tokens = entryTunnelAddress.getText().toString().split("/");
82 |
83 | if (Integer.parseInt(tokens[1]) <= 0 ||
84 | Integer.parseInt(tokens[1]) > 128)
85 | throw new Exception();
86 |
87 | if (tokens.length != 2)
88 | throw new Exception();
89 |
90 | InetAddress.getByName(tokens[0]);
91 | }
92 | catch (Exception e)
93 | {
94 | entryTunnelAddress.setError("IPv4 or IPv6 address in CIDR notation (i.e. 192.168.0.2/24) is required");
95 | error = true;
96 | }
97 |
98 | return !error;
99 | }
100 |
101 | public void onFocusChange(View v, boolean hasFocus)
102 | {
103 | try
104 | {
105 | if (!validate())
106 | {
107 | }
108 | }
109 | catch (Exception e)
110 | {
111 | }
112 |
113 | SharedPreferences.Editor editor = settings.edit();
114 | editor.putString("TunnelAddress", entryTunnelAddress.getText().toString().trim());
115 |
116 | try
117 | {
118 | String[] tokens = entryTunnelAddress.getText().toString().trim().split("/");
119 | editor.putString("TunnelRealAddress", tokens[0]);
120 | editor.putString("TunnelPrefixLen", tokens[1]);
121 | }
122 | catch (Exception e)
123 | {
124 | entryTunnelAddress.setError("IPv4 or IPv6 address in CIDR notation (i.e. 192.168.0.2/24) is required");
125 | }
126 |
127 | editor.putString("DNSServers", entryDNSServers.getText().toString().trim());
128 | editor.putString("StaticRoutes", entryStaticRoutes.getText().toString().trim());
129 | editor.commit();
130 | }
131 |
132 | public boolean onEditorAction(TextView arg0, int arg1, KeyEvent arg2)
133 | {
134 | onFocusChange((View) arg0, false);
135 | return false;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNClientStatusFragment.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import com.frozenriver.sigmavpn.R;
31 |
32 | import android.app.Fragment;
33 | import android.os.Bundle;
34 | import android.view.LayoutInflater;
35 | import android.view.View;
36 | import android.view.ViewGroup;
37 | import android.widget.Button;
38 |
39 | public class SigmaVPNClientStatusFragment extends Fragment implements View.OnClickListener
40 | {
41 | private Button connectButton;
42 |
43 | @Override
44 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
45 | {
46 | setHasOptionsMenu(false);
47 |
48 | View v = inflater.inflate(R.layout.status, container, false);
49 |
50 | connectButton = (Button) v.findViewById(R.id.connect);
51 | connectButton.setOnClickListener(this);
52 |
53 | return v;
54 | }
55 |
56 | public void onClick(View v)
57 | {
58 | if (v.getId() == R.id.connect)
59 | {
60 | ((SigmaVPNClient) this.getActivity()).startVPNService();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNClientTunnelFragment.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import java.util.Random;
31 |
32 | import com.neilalexander.jnacl.NaCl;
33 | import com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305;
34 | import com.frozenriver.sigmavpn.R;
35 |
36 | import android.app.Fragment;
37 | import android.content.ClipboardManager;
38 | import android.content.Context;
39 | import android.content.SharedPreferences;
40 | import android.os.Bundle;
41 | import android.view.KeyEvent;
42 | import android.view.LayoutInflater;
43 | import android.view.Menu;
44 | import android.view.MenuInflater;
45 | import android.view.MenuItem;
46 | import android.view.View;
47 | import android.view.ViewGroup;
48 | import android.widget.CheckBox;
49 | import android.widget.TextView;
50 | import android.widget.Toast;
51 |
52 | public class SigmaVPNClientTunnelFragment extends Fragment implements View.OnClickListener, View.OnFocusChangeListener, TextView.OnEditorActionListener
53 | {
54 | private TextView entryRemoteAddress, entryRemotePort,
55 | entryPrivateKey, entryPublicKey, entryLocalPublicKey;
56 | private CheckBox entryUseTAI64;
57 | private SharedPreferences settings;
58 |
59 | @Override
60 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
61 | {
62 | Random rand = new Random();
63 | byte[] pk = new byte[32], sk = new byte[32];
64 | rand.nextBytes(sk);
65 | curve25519xsalsa20poly1305.crypto_box_getpublickey(pk, sk);
66 |
67 | setHasOptionsMenu(true);
68 |
69 | settings = this.getActivity().getPreferences(Context.MODE_PRIVATE);
70 | View v = inflater.inflate(R.layout.tunnel, container, false);
71 |
72 | entryRemoteAddress = (TextView) v.findViewById(R.id.remoteaddress);
73 | entryRemoteAddress.setText(settings.getString("RemoteAddress", ""));
74 | entryRemoteAddress.setOnFocusChangeListener(this);
75 | entryRemoteAddress.setOnEditorActionListener(this);
76 |
77 | entryRemotePort = (TextView) v.findViewById(R.id.remoteport);
78 | entryRemotePort.setText(settings.getString("RemotePort", ""));
79 | entryRemotePort.setOnFocusChangeListener(this);
80 | entryRemotePort.setOnEditorActionListener(this);
81 |
82 | entryPrivateKey = (TextView) v.findViewById(R.id.privatekey);
83 | entryPrivateKey.setText(settings.getString("PrivateKey", NaCl.asHex(sk)));
84 | entryPrivateKey.setOnFocusChangeListener(this);
85 | entryPrivateKey.setOnEditorActionListener(this);
86 |
87 | entryLocalPublicKey = (TextView) v.findViewById(R.id.localpublickey);
88 | entryLocalPublicKey.setText(settings.getString("LocalPublicKey", NaCl.asHex(pk)));
89 | entryLocalPublicKey.setOnFocusChangeListener(this);
90 | entryLocalPublicKey.setOnEditorActionListener(this);
91 |
92 | entryPublicKey = (TextView) v.findViewById(R.id.publickey);
93 | entryPublicKey.setText(settings.getString("RemotePublicKey", ""));
94 | entryPublicKey.setOnFocusChangeListener(this);
95 | entryPublicKey.setOnEditorActionListener(this);
96 |
97 | entryUseTAI64 = (CheckBox) v.findViewById(R.id.enablenacltai);
98 | entryUseTAI64.setChecked(settings.getBoolean("UseTAI64", false));
99 | entryUseTAI64.setOnClickListener(this);
100 |
101 | v.findViewById(R.id.copypublickey).setOnClickListener(this);
102 | v.findViewById(R.id.genprivatekey).setOnClickListener(this);
103 |
104 | return v;
105 | }
106 |
107 | @Override
108 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
109 | {
110 | inflater.inflate(R.menu.client, menu);
111 | }
112 |
113 | @Override
114 | public boolean onOptionsItemSelected(MenuItem item)
115 | {
116 | ClipboardManager clipboard = (ClipboardManager) this.getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
117 |
118 | switch (item.getItemId())
119 | {
120 | case R.id.copypublickey:
121 | clipboard.setText(((TextView) this.getActivity().findViewById(R.id.localpublickey)).getText().toString());
122 |
123 | Toast.makeText(this.getActivity(), "Copied public key to clipboard", Toast.LENGTH_SHORT).show();
124 | break;
125 |
126 | case R.id.copyprivatekey:
127 | clipboard.setText(((TextView) this.getActivity().findViewById(R.id.privatekey)).getText().toString());
128 |
129 | Toast.makeText(this.getActivity(), "Copied private key to clipboard", Toast.LENGTH_SHORT).show();
130 | break;
131 |
132 | case R.id.copybothkeys:
133 | clipboard.setText("Private: " + ((TextView) this.getActivity().findViewById(R.id.privatekey)).getText().toString() + "\n" +
134 | "Public: " + ((TextView) this.getActivity().findViewById(R.id.localpublickey)).getText().toString());
135 |
136 | Toast.makeText(this.getActivity(), "Copied both keys to clipboard", Toast.LENGTH_SHORT).show();
137 | break;
138 | }
139 |
140 | return true;
141 | }
142 |
143 | public boolean validate()
144 | {
145 | boolean error = false;
146 |
147 | if (entryRemoteAddress.getText().length() == 0)
148 | {
149 | entryRemoteAddress.setError("Remote address required");
150 | error = true;
151 | }
152 |
153 | try
154 | {
155 | if (Integer.parseInt(entryRemotePort.getText().toString()) < 1||
156 | Integer.parseInt(entryRemotePort.getText().toString()) > 65535)
157 | {
158 | entryRemotePort.setError("Port number between 1 and 65535 is required");
159 | error = true;
160 | }
161 | }
162 | catch (NumberFormatException e)
163 | {
164 | entryRemotePort.setError("Port number is required");
165 | error = true;
166 | }
167 |
168 | if (!entryPublicKey.getText().toString().matches("[0-9A-Fa-f]+"))
169 | {
170 | entryPublicKey.setError("Public key should be provided in hexadecimal format");
171 | error = true;
172 | }
173 |
174 | if (entryPublicKey.getText().length() != 64)
175 | {
176 | entryPublicKey.setError("32-bit key length is required");
177 | error = true;
178 | }
179 |
180 | return !error;
181 | }
182 |
183 | public void onFocusChange(View v, boolean hasFocus)
184 | {
185 | try
186 | {
187 | if (!validate())
188 | {
189 | }
190 | }
191 | catch (Exception e)
192 | {
193 | }
194 |
195 | SharedPreferences.Editor editor = settings.edit();
196 | editor.putString("RemoteAddress", entryRemoteAddress.getText().toString().trim());
197 | editor.putString("RemotePort", entryRemotePort.getText().toString().trim());
198 | editor.putString("PrivateKey", entryPrivateKey.getText().toString().trim());
199 | editor.putString("LocalPublicKey", entryLocalPublicKey.getText().toString().trim());
200 | editor.putString("RemotePublicKey", entryPublicKey.getText().toString().trim());
201 | editor.putBoolean("UseTAI64", entryUseTAI64.isChecked());
202 | editor.commit();
203 | }
204 |
205 | public void onClick(View v)
206 | {
207 | switch (v.getId())
208 | {
209 | case R.id.enablenacltai:
210 | SharedPreferences.Editor editor = settings.edit();
211 | editor.putBoolean("UseTAI64", entryUseTAI64.isChecked());
212 | editor.commit();
213 | break;
214 |
215 | case R.id.copypublickey:
216 | ClipboardManager clipboard = (ClipboardManager) this.getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
217 | clipboard.setText(entryLocalPublicKey.getText().toString());
218 |
219 | Toast.makeText(this.getActivity(), "Copied public key to clipboard", Toast.LENGTH_SHORT).show();
220 | break;
221 |
222 | case R.id.genprivatekey:
223 | Random rand = new Random();
224 | byte[] pk = new byte[32], sk = new byte[32];
225 | rand.nextBytes(sk);
226 | curve25519xsalsa20poly1305.crypto_box_getpublickey(pk, sk);
227 | entryLocalPublicKey.setText(NaCl.asHex(pk));
228 | entryPrivateKey.setText(NaCl.asHex(sk));
229 | break;
230 | }
231 | }
232 |
233 | public boolean onEditorAction(TextView arg0, int arg1, KeyEvent arg2)
234 | {
235 | onFocusChange((View) arg0, false);
236 | return false;
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNProto.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | public class SigmaVPNProto
31 | {
32 | protected com.neilalexander.jnacl.NaCl crypto;
33 |
34 | public SigmaVPNProto(com.neilalexander.jnacl.NaCl crypto)
35 | {
36 | this.crypto = crypto;
37 | }
38 |
39 | public byte[] encode(byte[] packet, int length)
40 | {
41 | return packet;
42 | }
43 |
44 | public byte[] decode(byte[] packet, int length)
45 | {
46 | return packet;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNProtoTAI64.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | public class SigmaVPNProtoTAI64 extends SigmaVPNProto
31 | {
32 | public class TAI
33 | {
34 | public long x;
35 | }
36 |
37 | public class TAIa
38 | {
39 | public TAI sec;
40 | public long nano;
41 | public long atto;
42 | }
43 |
44 | TAIa cdTAIp, cdTAIe;
45 |
46 | public SigmaVPNProtoTAI64(com.neilalexander.jnacl.NaCl crypto)
47 | {
48 | super(crypto);
49 |
50 | cdTAIp = new TAIa();
51 | cdTAIp.sec = new TAI();
52 |
53 | cdTAIe = new TAIa();
54 | cdTAIe.sec = new TAI();
55 |
56 | System.out.println("nacltai initialised");
57 | }
58 |
59 | public byte[] encode(byte[] input, int length)
60 | {
61 | byte[] nonce = new byte[24];
62 | nonce[7] = (byte) (crypto.getRole() ? 1 : 0);
63 |
64 | TAIa_now(cdTAIp);
65 | TAIa_pack(nonce, 8, cdTAIp);
66 |
67 | byte[] enc = crypto.encrypt(input, length, nonce);
68 |
69 | for (int i = 0; i < 16; i ++)
70 | enc[i] = nonce[8 + i];
71 |
72 | return enc;
73 | }
74 |
75 | public byte[] decode(byte[] input, int length)
76 | {
77 | byte[] nonce = new byte[24];
78 | nonce[7] = (byte) (crypto.getRole() ? 0 : 1);
79 |
80 | for (int i = 0; i < 16; i ++)
81 | {
82 | nonce[8 + i] = input[i];
83 | input[i] = 0;
84 | }
85 |
86 | return crypto.decrypt(input, length, nonce);
87 | }
88 |
89 | public void TAIa_now(TAIa t)
90 | {
91 | long millis = System.currentTimeMillis();
92 | t.sec.x = 4611686018427387914L + (long) millis / 1000;
93 | t.nano = (millis % 1000) * 1000 * 1000;
94 | t.atto ++;
95 | }
96 |
97 | public void TAI_pack(byte[] s, int soffset, TAI t)
98 | {
99 | long x = t.x;
100 | s[7 + soffset] = (byte) (x & 255); x >>>= 8;
101 | s[6 + soffset] = (byte) (x & 255); x >>>= 8;
102 | s[5 + soffset] = (byte) (x & 255); x >>>= 8;
103 | s[4 + soffset] = (byte) (x & 255); x >>>= 8;
104 | s[3 + soffset] = (byte) (x & 255); x >>>= 8;
105 | s[2 + soffset] = (byte) (x & 255); x >>>= 8;
106 | s[1 + soffset] = (byte) (x & 255); x >>>= 8;
107 | s[0 + soffset] = (byte) x;
108 | }
109 |
110 | public void TAI_unpack(byte[] s, int soffset, TAI t)
111 | {
112 | long x;
113 |
114 | x = s[0 + soffset];
115 | x <<= 8; x += s[1 + soffset];
116 | x <<= 8; x += s[2 + soffset];
117 | x <<= 8; x += s[3 + soffset];
118 | x <<= 8; x += s[4 + soffset];
119 | x <<= 8; x += s[5 + soffset];
120 | x <<= 8; x += s[6 + soffset];
121 | x <<= 8; x += s[7 + soffset];
122 |
123 | t.x = x;
124 | }
125 |
126 | public void TAIa_pack(byte[] s, int soffset, TAIa t)
127 | {
128 | long x;
129 |
130 | TAI_pack(s, soffset, t.sec);
131 |
132 | soffset += 8;
133 | x = t.atto;
134 |
135 | s[7 + soffset] = (byte)(x & 255); x >>>= 8;
136 | s[6 + soffset] = (byte)(x & 255); x >>>= 8;
137 | s[5 + soffset] = (byte)(x & 255); x >>>= 8;
138 | s[4 + soffset] = (byte) x;
139 |
140 | x = t.nano;
141 |
142 | s[3 + soffset] = (byte)(x & 255); x >>>= 8;
143 | s[2 + soffset] = (byte)(x & 255); x >>>= 8;
144 | s[1 + soffset] = (byte)(x & 255); x >>>= 8;
145 | s[0 + soffset] = (byte) x;
146 | }
147 |
148 | public void TAIa_unpack(byte[] s, int soffset, TAIa t)
149 | {
150 | int x;
151 |
152 | TAI_unpack(s, soffset, t.sec);
153 | soffset += 8;
154 |
155 | x = s[4 + soffset];
156 | x <<= 8; x += s[5 + soffset];
157 | x <<= 8; x += s[6 + soffset];
158 | x <<= 8; x += s[7 + soffset];
159 |
160 | t.atto = x;
161 |
162 | x = s[0 + soffset];
163 | x <<= 8; x += s[1 + soffset];
164 | x <<= 8; x += s[2 + soffset];
165 | x <<= 8; x += s[3 + soffset];
166 |
167 | t.nano = x;
168 | }
169 | }
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNProtoZero.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | public class SigmaVPNProtoZero extends SigmaVPNProto
31 | {
32 | public SigmaVPNProtoZero(com.neilalexander.jnacl.NaCl crypto)
33 | {
34 | super(crypto);
35 |
36 | System.out.println("nacl0 initialised");
37 | }
38 |
39 | public byte[] encode(byte[] input, int length)
40 | {
41 | byte[] enc = crypto.encrypt(input, length, new byte[24]);
42 | byte[] buf = new byte[enc.length - 16];
43 |
44 | for (int i = 0; i < enc.length - 16; i ++)
45 | buf[i] = enc[16 + i];
46 |
47 | return buf;
48 | }
49 |
50 | public byte[] decode(byte[] input, int length)
51 | {
52 | byte[] dec = new byte[length + 16];
53 |
54 | for (int i = 0; i < length; i ++)
55 | dec[16 + i] = input[i];
56 |
57 | return crypto.decrypt(dec, dec.length, new byte[24]);
58 | }
59 | }
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNService.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import android.app.PendingIntent;
31 | import android.content.Intent;
32 | import android.net.VpnService;
33 | import android.os.Handler;
34 | import android.os.Message;
35 | import android.os.ParcelFileDescriptor;
36 | import android.widget.Toast;
37 |
38 | import java.io.FileInputStream;
39 | import java.io.FileOutputStream;
40 | import java.net.DatagramSocket;
41 | import java.net.InetSocketAddress;
42 | import java.nio.channels.DatagramChannel;
43 |
44 | import com.frozenriver.sigmavpn.R;
45 | import com.neilalexander.jnacl.*;
46 |
47 | public class SigmaVPNService extends VpnService implements Handler.Callback, Runnable
48 | {
49 | private String _RemoteAddress, _RemotePort, _TunnelAddress, _PrivateKey, _PublicKey, _Protocol, _DNSServers, _StaticRoutes;
50 | private int _TunnelPrefixLen, _MTU, _LocalPort, _SendPollFreq;
51 | private boolean _DefineLocalPort;
52 | private PendingIntent ConfigureIntent;
53 |
54 | private Handler mHandler;
55 | private Thread mThread;
56 |
57 | private ParcelFileDescriptor mInterface;
58 | private String mParameters;
59 |
60 | private NaCl crypto;
61 |
62 | Thread sendThread, recvThread;
63 |
64 | public int onStartCommand(Intent intent, int flags, int startId)
65 | {
66 | if (mHandler == null)
67 | mHandler = new Handler(this);
68 |
69 | if (mThread != null)
70 | mThread.interrupt();
71 |
72 | String prefix = getPackageName();
73 |
74 | try
75 | {
76 | _RemoteAddress = intent.getStringExtra(prefix + ".REMOTEADDRESS");
77 | _RemotePort = intent.getStringExtra(prefix + ".REMOTEPORT");
78 | _PrivateKey = intent.getStringExtra(prefix + ".PRIVATEKEY");
79 | _PublicKey = intent.getStringExtra(prefix + ".PUBLICKEY");
80 | _TunnelAddress = intent.getStringExtra(prefix + ".TUNNELREALADDRESS");
81 | _TunnelPrefixLen = Integer.parseInt(intent.getStringExtra(prefix + ".TUNNELPREFIXLEN"));
82 | _DNSServers = intent.getStringExtra(prefix + ".DNSSERVERS");
83 | _StaticRoutes = intent.getStringExtra(prefix + ".STATICROUTES");
84 | _Protocol = intent.getStringExtra(prefix + ".PROTOCOL");
85 | _DefineLocalPort = intent.getBooleanExtra(prefix + ".DEFINELOCALPORT", false);
86 | _LocalPort = intent.getIntExtra(prefix + ".LOCALPORT", 1234);
87 | _MTU = intent.getIntExtra(prefix + ".MTU", 1400);
88 | _SendPollFreq = intent.getIntExtra(prefix + ".SENDPOLLFREQ", 1000);
89 | }
90 | catch (Exception e)
91 | {
92 | mHandler.sendEmptyMessage(R.string.disconnected);
93 | this.stopSelf();
94 | }
95 |
96 | mThread = new Thread(this, "SigmaVPNThread");
97 | mThread.start();
98 |
99 | return START_STICKY;
100 | }
101 |
102 | public void onDestroy()
103 | {
104 | if (mThread != null)
105 | mThread.interrupt();
106 | }
107 |
108 | public boolean handleMessage(Message message)
109 | {
110 | if (message != null)
111 | Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
112 |
113 | return true;
114 | }
115 |
116 | public synchronized void run()
117 | {
118 | try
119 | {
120 | crypto = new NaCl(_PrivateKey, _PublicKey);
121 |
122 | InetSocketAddress server = new InetSocketAddress(_RemoteAddress, Integer.parseInt(_RemotePort));
123 |
124 | for (int attempt = 0; attempt < 10; ++attempt)
125 | {
126 | if (run(server))
127 | attempt = 0;
128 |
129 | Thread.sleep(3000);
130 | }
131 | }
132 | catch (Exception e)
133 | {
134 | System.out.println(e.getClass().getName() + " reported error: " + e.getMessage());
135 | }
136 | finally
137 | {
138 | try
139 | {
140 | mInterface.close();
141 | }
142 | catch (Exception e) {};
143 |
144 | mInterface = null;
145 | mParameters = null;
146 |
147 | mHandler.sendEmptyMessage(R.string.disconnected);
148 | this.stopSelf();
149 | }
150 | }
151 |
152 | private boolean run(InetSocketAddress server) throws Exception
153 | {
154 | DatagramChannel tunnel = DatagramChannel.open();
155 |
156 | if (!protect(tunnel.socket()))
157 | {
158 | return false;
159 | }
160 |
161 | try
162 | {
163 | if (_DefineLocalPort)
164 | {
165 | System.out.println("Binding " + _LocalPort + "...");
166 |
167 | DatagramSocket sock = tunnel.socket();
168 | sock.setReuseAddress(true);
169 | sock.bind(new InetSocketAddress(_LocalPort));
170 | }
171 | }
172 | catch (Exception e)
173 | {
174 | System.out.println("Unable to set local socket binding manually");
175 | }
176 |
177 | tunnel.connect(server);
178 | tunnel.configureBlocking(true);
179 |
180 | String config = "m," + _MTU + " a," + _TunnelAddress + "," + _TunnelPrefixLen + " ";
181 |
182 | try
183 | {
184 | if (!_DNSServers.trim().equals(""))
185 | {
186 | String[] dnsservers = _DNSServers.split(",");
187 |
188 | for (String dnsserver: dnsservers)
189 | {
190 | System.out.println("Installing new DNS server: " + dnsserver.trim());
191 | config = config.concat("d," + dnsserver.trim() + " ");
192 | }
193 | }
194 |
195 | if (!_StaticRoutes.trim().equals(""))
196 | {
197 | String[] staticroutes = _StaticRoutes.split(",");
198 |
199 | for (String staticroute: staticroutes)
200 | {
201 | System.out.println("Installing new static route: " + staticroute.trim());
202 | String[] parts = staticroute.trim().split("/");
203 | config = config.concat("r," + parts[0] + "," + parts[1] + " ");
204 | }
205 | }
206 | }
207 | catch (Exception e) { }
208 |
209 | configure(config);
210 |
211 | FileInputStream sendQ = new FileInputStream(mInterface.getFileDescriptor());
212 | FileOutputStream recvQ = new FileOutputStream(mInterface.getFileDescriptor());
213 |
214 | SigmaVPNProto proto;
215 |
216 | if (_Protocol.equals("nacl0"))
217 | proto = new SigmaVPNProtoZero(crypto);
218 | else if (_Protocol.equals("nacltai"))
219 | proto = new SigmaVPNProtoTAI64(crypto);
220 | else
221 | proto = new SigmaVPNProto(crypto);
222 |
223 | SigmaVPNServiceSend sendTask = new SigmaVPNServiceSend(tunnel, sendQ, proto, _SendPollFreq);
224 | SigmaVPNServiceRecv recvTask = new SigmaVPNServiceRecv(tunnel, recvQ, proto);
225 |
226 | sendThread = new Thread(sendTask);
227 | recvThread = new Thread(recvTask);
228 |
229 | sendThread.start();
230 | recvThread.start();
231 |
232 | sendThread.join();
233 | // recvThread.join();
234 |
235 | tunnel.disconnect();
236 | tunnel.close();
237 |
238 | return true;
239 | }
240 |
241 | private void configure(String parameters) throws Exception
242 | {
243 | if (mInterface != null && parameters.equals(mParameters))
244 | return;
245 |
246 | Builder builder = new Builder();
247 |
248 | for (String parameter : parameters.split(" "))
249 | {
250 | String[] fields = parameter.split(",");
251 |
252 | try
253 | {
254 | switch (fields[0].charAt(0))
255 | {
256 | case 'm':
257 | builder.setMtu(Short.parseShort(fields[1]));
258 | break;
259 | case 'a':
260 | builder.addAddress(fields[1], Integer.parseInt(fields[2]));
261 | break;
262 | case 'r':
263 | builder.addRoute(fields[1], Integer.parseInt(fields[2]));
264 | break;
265 | case 'd':
266 | builder.addDnsServer(fields[1]);
267 | break;
268 | case 's':
269 | builder.addSearchDomain(fields[1]);
270 | break;
271 | }
272 | }
273 | catch (Exception e)
274 | {
275 | throw new IllegalArgumentException("Bad parameter: " + parameter);
276 | }
277 | }
278 |
279 | try
280 | {
281 | mInterface.close();
282 | }
283 | catch (Exception e) { };
284 |
285 | mInterface = builder.setSession(_RemoteAddress)
286 | .setConfigureIntent(ConfigureIntent)
287 | .establish();
288 | mParameters = parameters;
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNServiceRecv.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import java.io.FileOutputStream;
31 | import java.io.IOException;
32 | import java.nio.ByteBuffer;
33 | import java.nio.channels.DatagramChannel;
34 |
35 | public class SigmaVPNServiceRecv implements Runnable
36 | {
37 | private DatagramChannel tunnel;
38 | private FileOutputStream fileStream;
39 | private SigmaVPNProto proto;
40 |
41 | public SigmaVPNServiceRecv(DatagramChannel tunnel, FileOutputStream fileStream, SigmaVPNProto proto)
42 | {
43 | this.tunnel = tunnel;
44 | this.fileStream = fileStream;
45 | this.proto = proto;
46 | }
47 |
48 | public void run()
49 | {
50 | int result = 0;
51 |
52 | do
53 | {
54 | try
55 | {
56 | if (result <= 0)
57 | Thread.sleep(1000);
58 |
59 | result = process();
60 | }
61 | catch (IOException e)
62 | {
63 | System.out.println("IOException from recv thread");
64 | e.printStackTrace();
65 | return;
66 | }
67 | catch (Exception e)
68 | {
69 | e.printStackTrace();
70 | };
71 | }
72 | while (result != -1);
73 | }
74 |
75 | public int process() throws Exception
76 | {
77 | ByteBuffer packet = ByteBuffer.allocate(1516);
78 | int length = tunnel.read(packet);
79 |
80 | byte[] dec = proto.decode(packet.array(), length);
81 |
82 | fileStream.write(dec, 0, dec.length);
83 | packet.clear();
84 |
85 | return length;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/com/frozenriver/sigmavpn/SigmaVPNServiceSend.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2014, Neil Alexander T.
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with
6 | // or without modification, are permitted provided that the following
7 | // conditions are met:
8 | //
9 | // - Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // - Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | // POSSIBILITY OF SUCH DAMAGE.
26 | //
27 |
28 | package com.frozenriver.sigmavpn;
29 |
30 | import java.io.FileInputStream;
31 | import java.io.IOException;
32 | import java.nio.ByteBuffer;
33 | import java.nio.channels.DatagramChannel;
34 |
35 | public class SigmaVPNServiceSend implements Runnable
36 | {
37 | private DatagramChannel tunnel;
38 | private FileInputStream fileStream;
39 | private SigmaVPNProto proto;
40 | private int pollfreq;
41 |
42 | public SigmaVPNServiceSend(DatagramChannel tunnel, FileInputStream fileStream, SigmaVPNProto proto, int pollfreq)
43 | {
44 | this.tunnel = tunnel;
45 | this.fileStream = fileStream;
46 | this.proto = proto;
47 | this.pollfreq = pollfreq;
48 | }
49 |
50 | public void run()
51 | {
52 | int result = 0;
53 | int packetcount = 1;
54 |
55 | do
56 | {
57 | try
58 | {
59 | if (result <= 0)
60 | {
61 | if (packetcount > 1)
62 | packetcount --;
63 |
64 | Thread.sleep(pollfreq / packetcount);
65 | }
66 | else
67 | packetcount ++;
68 |
69 | result = process();
70 | }
71 | catch (IOException e)
72 | {
73 | System.out.println("IOException from send thread");
74 | return;
75 | }
76 | catch (Exception e)
77 | {
78 | e.printStackTrace();
79 | };
80 | }
81 | while (result != -1);
82 | }
83 |
84 | public int process() throws Exception
85 | {
86 | byte[] packet = new byte[1516];
87 | int length = fileStream.read(packet);
88 |
89 | if (length <= 0)
90 | return length;
91 |
92 | byte[] enc = proto.encode(packet, length);
93 |
94 | ByteBuffer buf = ByteBuffer.wrap(enc, 0, enc.length);
95 | tunnel.write(buf);
96 |
97 | return length;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------