Browse Source

Merge branch 'issue-17' of isundil/pass into master

isundil 7 years ago
parent
commit
d97f69aa92

+ 0 - 2
app/CMakeLists.txt

@@ -27,7 +27,6 @@ add_library( # Sets the name of the library.
 
 find_library( # Sets the name of the path variable.
               log-lib
-              Z
               # Specifies the name of the NDK library that
               # you want CMake to locate.
               log )
@@ -38,7 +37,6 @@ find_library( # Sets the name of the path variable.
 
 target_link_libraries( # Specifies the target library.
                        native-lib
-                       z
                        # Links the target library to the log library
                        # included in the NDK.
                        ${log-lib} )

+ 44 - 2
app/src/main/java/info/knacki/pass/io/GPGUtil.java

@@ -5,26 +5,37 @@ import android.support.annotation.NonNull;
 
 import org.bouncycastle.bcpg.ArmoredOutputStream;
 import org.bouncycastle.bcpg.CompressionAlgorithmTags;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.sig.KeyFlags;
+import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
 import org.bouncycastle.openpgp.PGPCompressedData;
 import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
 import org.bouncycastle.openpgp.PGPEncryptedData;
 import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
 import org.bouncycastle.openpgp.PGPEncryptedDataList;
 import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPKeyPair;
+import org.bouncycastle.openpgp.PGPKeyRingGenerator;
 import org.bouncycastle.openpgp.PGPLiteralData;
 import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
 import org.bouncycastle.openpgp.PGPObjectFactory;
 import org.bouncycastle.openpgp.PGPPBEEncryptedData;
 import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPPublicKey;
 import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
 import org.bouncycastle.openpgp.PGPSecretKey;
 import org.bouncycastle.openpgp.PGPSecretKeyRing;
 import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
 import org.bouncycastle.openpgp.PGPUtil;
 import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
 import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
 import org.bouncycastle.openpgp.operator.bc.BcPBEDataDecryptorFactory;
+import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
 import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
 import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
 import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
 import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
@@ -42,6 +53,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.math.BigInteger;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Date;
@@ -349,8 +361,38 @@ public class GPGUtil {
         return "";
     }
 
-    public static void Generate(final OutputStream out) {
-        // FIXME
+    public static byte[] Generate(String user) {
+        try {
+            final Date now = new Date();
+            RSAKeyPairGenerator rsakeygen = new RSAKeyPairGenerator();
+            rsakeygen.init(new RSAKeyGenerationParameters(BigInteger.valueOf(257), new SecureRandom(), 2048, 12));
+            PGPKeyPair rsaEncr = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsakeygen.generateKeyPair(), now);
+
+            PGPSignatureSubpacketGenerator encHashGen = new PGPSignatureSubpacketGenerator();
+            encHashGen.setKeyFlags(false, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
+
+            final PBESecretKeyEncryptor newEncryptor = new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("BC").build("".toCharArray());
+            PGPKeyRingGenerator keygen = new PGPKeyRingGenerator(
+                    PGPSignature.POSITIVE_CERTIFICATION,
+                    rsaEncr,
+                    user,
+                    new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1),
+                    encHashGen.generate(),
+                    null,
+                    new BcPGPContentSignerBuilder(
+                            rsaEncr.getPublicKey().getAlgorithm(),
+                            HashAlgorithmTags.SHA1),
+                    newEncryptor);
+            ArrayList<PGPSecretKeyRing> keyringCollection = new ArrayList<>();
+            keyringCollection.add(keygen.generateSecretKeyRing());
+            ByteArrayOutputStream stream = new ByteArrayOutputStream();
+            new PGPSecretKeyRingCollection(keyringCollection).encode(stream);
+            return stream.toByteArray();
+        }
+        catch (IOException | PGPException e) {
+            log.log(Level.SEVERE, "Cannot generate new key", e);
+            return null;
+        }
     }
 
     public static boolean CheckIsPasswordProtected(Context ctx) throws IOException {

+ 36 - 15
app/src/main/java/info/knacki/pass/settings/ui/SettingsActivity.java

@@ -27,6 +27,7 @@ import android.view.MenuItem;
 import android.view.View;
 import android.widget.Toast;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -51,6 +52,7 @@ import info.knacki.pass.settings.SettingsManager;
 import info.knacki.pass.ui.GitPullActivity;
 import info.knacki.pass.ui.alertPrompt.AlertPromptGenerator;
 import info.knacki.pass.ui.alertPrompt.views.TextView;
+import info.knacki.pass.ui.alertPrompt.views.UsernameAndEmail;
 import info.knacki.pass.ui.passwordPicker.PasswordPickerFactory;
 
 /**
@@ -477,22 +479,22 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
                 GPGPreferenceFragment.this.startActivityForResult(i, ACTIVITY_REQUEST_CODE_BROWSEGPG);
                 return true;
             });
-            findPreference(getResources().getString(R.string.id_gpg_password)).setOnPreferenceClickListener(preference -> {
-                try {
-                    GPGUtil.ChangePassword(getActivity(), PasswordPickerFactory.GetPasswordEditor(getActivity()), new OnResponseListener<Void>() {
-                        @Override
-                        public void OnResponse(Void result) {
+            findPreference(getResources().getString(R.string.id_gpg_generate)).setOnPreferenceClickListener(preference -> {
+                AlertPromptGenerator.StaticMake(getActivity())
+                        .setView(new UsernameAndEmail(getActivity()))
+                        .setTitle(R.string.pref_gpg_title_username_mail)
+                        .setPositiveButton(R.string.ok, (dialogInterface, v) -> {
+                            byte[] keyData = GPGUtil.Generate(((UsernameAndEmail) v).GetUserAndEmail());
+                            SettingsManager.SetGPGKeyContent(getActivity(), new ByteArrayInputStream(keyData));
                             updateGpgFileLabel();
-                        }
-
-                        @Override
-                        public void OnError(String msg, Throwable e) {
-                            Toast.makeText(getActivity(), "Error: " + msg, Toast.LENGTH_LONG).show();
-                        }
-                    });
-                } catch (IOException e) {
-                    Toast.makeText(getActivity(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
-                }
+                            GPGSetPassword();
+                        })
+                        .setNegativeButton(R.string.cancel, null)
+                        .show();
+                return true;
+            });
+            findPreference(getResources().getString(R.string.id_gpg_password)).setOnPreferenceClickListener(preference -> {
+                GPGSetPassword();
                 return true;
             });
             findPreference(getResources().getString(R.string.id_gpg_export)).setOnPreferenceClickListener(preference -> {
@@ -516,6 +518,25 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
             updateGpgFileLabel();
         }
 
+        private void GPGSetPassword() {
+            try {
+                GPGUtil.ChangePassword(getActivity(), PasswordPickerFactory.GetPasswordEditor(getActivity()), new OnResponseListener<Void>() {
+                    @Override
+                    public void OnResponse(Void result) {
+                        updateGpgFileLabel();
+                    }
+
+                    @Override
+                    public void OnError(String msg, Throwable e) {
+                        Toast.makeText(getActivity(), "Error: " + msg, Toast.LENGTH_LONG).show();
+                    }
+                });
+            } catch (IOException e) {
+                Toast.makeText(getActivity(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
+            }
+            updateGpgFileLabel();
+        }
+
         private void DoExportKey() {
             final File outFile = new File(getActivity().getCacheDir().getAbsolutePath() + "/secretkey.gpg");
             try {

+ 25 - 0
app/src/main/java/info/knacki/pass/ui/alertPrompt/views/UsernameAndEmail.java

@@ -0,0 +1,25 @@
+package info.knacki.pass.ui.alertPrompt.views;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatEditText;
+import android.view.LayoutInflater;
+import android.widget.ScrollView;
+
+import info.knacki.pass.R;
+
+public class UsernameAndEmail extends ScrollView {
+    private final AppCompatEditText usernameEdit;
+    private final AppCompatEditText emailEdit;
+
+    public UsernameAndEmail(Context context) {
+        super(context);
+        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        addView(inflater.inflate(R.layout.username_and_email, null));
+        usernameEdit = findViewById(R.id.username);
+        emailEdit = findViewById(R.id.email);
+    }
+
+    public String GetUserAndEmail() {
+        return usernameEdit.getText().toString() +" <" +emailEdit.getText().toString() +">";
+    }
+}

+ 22 - 0
app/src/main/res/layout/username_and_email.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v7.widget.LinearLayoutCompat
+    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
+    android:layout_height="match_parent" android:orientation="vertical">
+    <android.support.v7.widget.AppCompatTextView
+        android:text="@string/pref_gpg_username"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+    <android.support.v7.widget.AppCompatEditText
+        android:id="@+id/username"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+    <android.support.v7.widget.AppCompatTextView
+        android:text="@string/pref_gpg_usermail"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+    <android.support.v7.widget.AppCompatEditText
+        android:id="@+id/email"
+        android:inputType="textEmailAddress"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+</android.support.v7.widget.LinearLayoutCompat>

+ 5 - 0
app/src/main/res/values-fr/lang.xml

@@ -52,6 +52,11 @@
         <item>Fort</item>
         <item>Personalisé</item>
     </array>
+    <string name="pref_gpg_title_username_mail">Username</string>
+    <string name="pref_gpg_username">Username</string>
+    <string name="pref_gpg_usermail">Mail Address</string>
+    <string name="pref_header_gpg_generate">Générer une clé GPG</string>
+    <string name="pref_summary_gpg_generate">Générer une nouvelle paire de clé GPG</string>
     <string name="pref_header_gpg_keyfile">Clé GPG</string>
     <string name="pref_summary_gpg_keyfile">Rechercher une clé GPG</string>
     <string name="pref_header_gpg_password">Mot de passe de la clef GPG</string>

+ 5 - 0
app/src/main/res/values/lang.xml

@@ -52,6 +52,11 @@
         <item>Strong</item>
         <item>Custom</item>
     </array>
+    <string name="pref_gpg_title_username_mail">Username</string>
+    <string name="pref_gpg_username">Username</string>
+    <string name="pref_gpg_usermail">Addresse Mail</string>
+    <string name="pref_header_gpg_generate">Generate GPG Key</string>
+    <string name="pref_summary_gpg_generate">Generate a new GPG key pair</string>
     <string name="pref_header_gpg_keyfile">GPG key</string>
     <string name="pref_summary_gpg_keyfile">Browse to find GPG exported key</string>
     <string name="pref_header_gpg_password">GPG key password</string>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -25,6 +25,7 @@
     <string name="id_vcs_git_ci_useremail">id_vcs_git_ci_useremail</string>
     <string name="id_vcs_git_commitinfocategory">id_vcs_git_commitinfocategory</string>
     <string name="id_vcs_git_authcategory">id_vcs_git_authcategory</string>
+    <string name="id_gpg_generate">id_gpg_generate</string>
     <string name="id_gpg_keyfile">id_gpg_keyfile</string>
     <string name="id_gpg_password">id_gpg_password</string>
     <string name="id_gpg_export">id_gpg_export</string>

+ 5 - 0
app/src/main/res/xml/pref_gpg.xml

@@ -1,4 +1,9 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <Preference
+        android:key="@string/id_gpg_generate"
+        android:title="@string/pref_header_gpg_generate"
+        android:summary="@string/pref_summary_gpg_generate"
+        />
     <Preference
         android:key="@string/id_gpg_keyfile"
         android:title="@string/pref_header_gpg_keyfile"