Generate cloud key pair

This commit is contained in:
M66B 2023-01-12 09:20:16 +01:00
parent a96d001b3c
commit 47d0d7c6ad
5 changed files with 159 additions and 1 deletions

View File

@ -53,6 +53,7 @@ import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
@ -81,10 +82,14 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@ -108,6 +113,9 @@ public class FragmentOptionsBackup extends FragmentBase {
private Button btnExport;
private Button btnImport;
private CardView cardCloud;
private EditText etUser;
private TextInputLayout tilPassword;
private Button btnLogin;
private static final int REQUEST_EXPORT_SELECT = 1;
private static final int REQUEST_IMPORT_SELECT = 2;
@ -127,6 +135,9 @@ public class FragmentOptionsBackup extends FragmentBase {
btnExport = view.findViewById(R.id.btnExport);
btnImport = view.findViewById(R.id.btnImport);
cardCloud = view.findViewById(R.id.cardCloud);
etUser = view.findViewById(R.id.etUser);
tilPassword = view.findViewById(R.id.tilPassword);
btnLogin = view.findViewById(R.id.btnLogin);
// Wire controls
@ -153,9 +164,17 @@ public class FragmentOptionsBackup extends FragmentBase {
}
});
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onLogin();
}
});
// Initialize
FragmentDialogTheme.setBackground(getContext(), view, false);
cardCloud.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
cardCloud.setVisibility(BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? View.VISIBLE : View.GONE);
return view;
}
@ -1342,6 +1361,59 @@ public class FragmentOptionsBackup extends FragmentBase {
return intent;
}
private void onLogin() {
Bundle args = new Bundle();
args.putString("user", etUser.getText().toString());
args.putString("password", tilPassword.getEditText().getText().toString());
new SimpleTask<Void>() {
@Override
protected void onPreExecute(Bundle args) {
btnLogin.setEnabled(false);
}
@Override
protected void onPostExecute(Bundle args) {
btnLogin.setEnabled(true);
}
@Override
protected Void onExecute(Context context, Bundle args) throws Throwable {
String user = args.getString("user");
String password = args.getString("password");
Pair<byte[], byte[]> key = getKeyPair(user, password);
return null;
}
@Override
protected void onExecuted(Bundle args, Void data) {
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentOptionsBackup.this, args, "cloud:login");
}
private static Pair<byte[], byte[]> getKeyPair(String user, String password)
throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] salt = MessageDigest.getInstance("SHA256").digest(user.getBytes());
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 310000, 2 * 256);
SecretKey secret = keyFactory.generateSecret(keySpec);
byte[] encoded = secret.getEncoded();
int half = encoded.length / 2;
return new Pair<>(
Arrays.copyOfRange(encoded, 0, half),
Arrays.copyOfRange(encoded, half, half + half));
}
public static class FragmentDialogExport extends FragmentDialogBase {
private TextInputLayout tilPassword1;
private TextInputLayout tilPassword2;

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5,-5L11,7zM20,19h-8v2h8c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-8v2h8V19z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M5,5h7V3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h7v-2H5V5zM21,12l-4,-4v3H9v2h8v3L21,12z"/>
</vector>

View File

@ -167,6 +167,68 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:labelFor="@+id/etUser"
android:text="@string/title_user"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCloud" />
<eu.faircode.email.EditTextPlain
android:id="@+id/etUser"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints="username"
android:inputType="text"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvUser" />
<TextView
android:id="@+id/tvPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_password"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etUser" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:endIconMode="password_toggle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPassword">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="password"
android:inputType="textPassword"
android:maxLength="20000"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnLogin"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:drawableEnd="@drawable/twotone_login_24"
android:drawablePadding="6dp"
android:text="@string/title_advanced_login"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -972,6 +972,8 @@
<string name="title_advanced_cleanup_hint">This will delete all temporary files</string>
<string name="title_advanced_keywords_hint" translatable="false">Space separated</string>
<string name="title_advanced_login" translatable="false">Login</string>
<string name="title_advanced_never_favorite">Never favorite</string>
<string name="title_advanced_edit_name">Edit name</string>