Skip to content

Commit 5985a2c

Browse files
author
Jared Tamana
committed
Add encryption for SDK23+ (closes #7)
- delete unneeded drawables.xml - fix custom host functionality
1 parent ffe2901 commit 5985a2c

7 files changed

Lines changed: 94 additions & 24 deletions

File tree

android/ProtogenSSH/.idea/dictionaries/jared.xml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

android/ProtogenSSH/.idea/inspectionProfiles/Project_Default.xml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

android/ProtogenSSH/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ dependencies {
3333
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
3434
implementation 'com.google.android.material:material:1.3.0-alpha01'
3535
implementation 'androidx.preference:preference:1.1.1'
36-
//implementation 'androidx.security:security-crypto:1.0.0-rc02'
36+
implementation 'androidx.security:security-crypto:1.0.0-rc02'
3737
// https://mvnrepository.com/artifact/com.jcraft/jsch
3838
implementation group: 'com.jcraft', name: 'jsch', version: '0.1.55'
3939

android/ProtogenSSH/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
34
package="com.jaredtamana.protogenssh">
45

56
<uses-permission android:name="android.permission.INTERNET" />
67
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
78

9+
<uses-sdk tools:overrideLibrary="androidx.security"/>
10+
811
<application
912
android:allowBackup="true"
1013
android:icon="@mipmap/ic_launcher"

android/ProtogenSSH/app/src/main/java/com/jaredtamana/protogenssh/ui/Functions.java

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.app.Activity;
66
import android.content.Context;
77
import android.content.SharedPreferences;
8+
import android.os.Build;
89
import android.os.StrictMode;
910
import android.view.View;
1011
import android.view.inputmethod.InputMethodManager;
@@ -13,6 +14,9 @@
1314
import android.widget.Toast;
1415

1516
// Material imports
17+
import androidx.security.crypto.EncryptedSharedPreferences;
18+
import androidx.security.crypto.MasterKeys;
19+
1620
import com.google.android.material.snackbar.BaseTransientBottomBar;
1721
import com.google.android.material.snackbar.Snackbar;
1822

@@ -42,17 +46,47 @@ public class Functions {
4246
// (this does mean no responses can be grabbed by this function)
4347
// accepts string of command, context for sharedPrefs, view for snackbar
4448
// returns void
45-
static public int executeSSHcommand(String command, Context context, View baseView) {
46-
SharedPreferences sharedPreferences = context.getSharedPreferences("credentials", Context.MODE_PRIVATE); // open credentials file
47-
String user = sharedPreferences.getString("username", "pi"); // use credentials unless not set, then use username pi
48-
String password = sharedPreferences.getString("password", "raspberry"); // use credentials unless not set, then use password raspberry
49-
String host = "192.168.4.1"; // use IP address, will end up adding a field for this later
50-
int port = sharedPreferences.getInt("port", 22); // use credentials unless not set, then use port 22
49+
static public void executeSSHcommand(String command, Context context, View baseView) {
50+
int sdk = Build.VERSION.SDK_INT;
51+
String user;
52+
String password;
53+
String host;
54+
int port;
55+
SharedPreferences sharedPreferences;
56+
if (sdk >= 23){
57+
String masterKeyAlias;
58+
try {
59+
masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC); // get master key
60+
sharedPreferences = EncryptedSharedPreferences.create(
61+
"secret_shared_prefs",
62+
masterKeyAlias,
63+
context,
64+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
65+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
66+
);
67+
} catch (Exception e) {
68+
e.printStackTrace();
69+
Snackbar.make(baseView, "Failed to create encryption keys (IOException or SecurityException)", BaseTransientBottomBar.LENGTH_LONG)
70+
.show();
71+
return;
72+
}
73+
user = sharedPreferences.getString(context.getString(R.string.username_sharedprop), "pi");
74+
password = sharedPreferences.getString(context.getString(R.string.password_sharedprop), "raspberry");
75+
host = sharedPreferences.getString(context.getString(R.string.host_sharedprop), "192.168.4.1");
76+
port = sharedPreferences.getInt(context.getString(R.string.port_sharedprop), 22);
77+
} else {
78+
sharedPreferences = context.getSharedPreferences("credentials", Context.MODE_PRIVATE); // open credentials file
79+
user = sharedPreferences.getString("username", "pi"); // use credentials unless not set, then use username pi
80+
password = sharedPreferences.getString("password", "raspberry"); // use credentials unless not set, then use password raspberry
81+
host = sharedPreferences.getString("host", "192.168.4.1"); // use IP address, will end up adding a field for this later
82+
port = sharedPreferences.getInt("port", 22); // use credentials unless not set, then use port 22
83+
}
5184
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
5285
.permitAll().build();
5386
StrictMode.setThreadPolicy(policy); // just a workaround
5487
try {
5588
JSch jsch = new JSch(); // instantiate a new JSch call
89+
assert host != null;
5690
Session session = jsch.getSession(user, host, port); // set session credentials
5791
session.setPassword(password); // set password
5892
java.util.Properties config = new java.util.Properties();
@@ -70,15 +104,13 @@ static public int executeSSHcommand(String command, Context context, View baseVi
70104
Snackbar.make(baseView, R.string.connect_failed_snack, BaseTransientBottomBar.LENGTH_LONG)
71105
.show(); // tell the user the command failed
72106
}
73-
return 0;
74107
}
75108

76109
// readFile function
77110
// Reads in button data and places buttons into the designated layout
78111
// accepts LinearLayout to be placed into, context for fileInput, view for snackbar
79112
// returns void
80113
public static void readFile(LinearLayout emoteListLayout, String fileName, final Context context, Activity activity, final View baseView) {
81-
File internalStorageDir = context.getFilesDir();
82114
try {
83115
// instantiate fis
84116
FileInputStream fileInputStream = context.openFileInput(fileName);

android/ProtogenSSH/app/src/main/java/com/jaredtamana/protogenssh/ui/settings/SettingsFragment.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.jaredtamana.protogenssh.ui.settings;
22

3-
// imports for base Android
4-
3+
// base imports
54
import android.app.AlertDialog;
65
import android.content.Context;
76
import android.content.DialogInterface;
87
import android.content.SharedPreferences;
8+
import android.os.Build;
99
import android.os.Bundle;
1010
import android.view.LayoutInflater;
1111
import android.view.View;
@@ -15,8 +15,8 @@
1515
// AndroidX imports
1616
import androidx.annotation.NonNull;
1717
import androidx.fragment.app.Fragment;
18-
//import androidx.security.crypto.EncryptedSharedPreferences;
19-
//import androidx.security.crypto.MasterKeys;
18+
import androidx.security.crypto.EncryptedSharedPreferences;
19+
import androidx.security.crypto.MasterKeys;
2020

2121
// Material imports
2222
import com.google.android.material.snackbar.BaseTransientBottomBar;
@@ -27,6 +27,7 @@
2727
import com.jaredtamana.protogenssh.R;
2828
import com.jaredtamana.protogenssh.ui.Functions;
2929

30+
3031
public class SettingsFragment extends Fragment { // main fragment start
3132

3233

@@ -43,6 +44,7 @@ public View onCreateView(@NonNull LayoutInflater inflater,
4344
final TextInputEditText mInputPort = root.findViewById(R.id.inputPort);
4445
final TextInputEditText mInputUsername = root.findViewById(R.id.inputUsername);
4546
final TextInputEditText mInputPassword = root.findViewById(R.id.inputPassword);
47+
final int sdk = Build.VERSION.SDK_INT;
4648
mFullFaceReset.setOnClickListener(new View.OnClickListener() {
4749
@Override
4850
public void onClick(View view) { // when Reset Full Face Buttons button is clicked
@@ -149,13 +151,34 @@ public void onClick(View v) { // when save button is clicked
149151
mInputHost.setError(getString(R.string.host_empty_error)); // set error flag on field
150152
return; // stop before exception is thrown
151153
}
152-
SharedPreferences credentialPrefs = getActivity().getSharedPreferences("credentials", Context.MODE_PRIVATE); // get credentials file
153-
SharedPreferences.Editor editor = credentialPrefs.edit(); // pull file into editor
154-
editor.putString(getString(R.string.host_sharedprop), mInputHost.getEditableText().toString()); // change host key to input
154+
155+
SharedPreferences sharedPreferences;
156+
157+
if (sdk >= 23) {
158+
String masterKeyAlias;
159+
try {
160+
masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
161+
sharedPreferences = EncryptedSharedPreferences.create(
162+
"secret_shared_prefs",
163+
masterKeyAlias,
164+
getContext(),
165+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
166+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
167+
);
168+
} catch (Exception e) {
169+
e.printStackTrace();
170+
Snackbar.make(getView(), "Failed to create encryption keys (IOException or SecurityException)", BaseTransientBottomBar.LENGTH_LONG)
171+
.show();
172+
return;
173+
}
174+
} else {
175+
sharedPreferences = getActivity().getSharedPreferences("credentials", Context.MODE_PRIVATE); // get credentials file
176+
}
177+
178+
SharedPreferences.Editor editor = sharedPreferences.edit();
179+
editor.putString(getString(R.string.host_sharedprop), mInputHost.getEditableText().toString());
155180
editor.putInt(getString(R.string.port_sharedprop), Integer.parseInt(mInputPort.getEditableText().toString())); // change port key to input
156181
editor.putString(getString(R.string.username_sharedprop), mInputUsername.getEditableText().toString()); // change username key to input
157-
// change password key to input
158-
// I want to implement encryption using androidx.security.crypto.EncryptedSharedPreferences but am having multiple issues, including the fact that sdk21 is needed
159182
editor.putString(getString(R.string.password_sharedprop), mInputPassword.getEditableText().toString());
160183
editor.apply(); // apply changes
161184
Functions.hideKeyboard(getContext(), getView()); // hide the keyboard, it's no longer needed

android/ProtogenSSH/app/src/main/res/values/drawables.xml

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)