mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-23 17:22:16 -05:00
layout adjustments, force portrait layout for EncryptFileActivity for now, (En|De)cryptFileActivity can now handle symmetric algorithms
This commit is contained in:
parent
ab6c884bdf
commit
0e14dcb290
@ -74,6 +74,7 @@
|
||||
<activity
|
||||
android:name=".EncryptFileActivity"
|
||||
android:label="@string/title_encryptFile"
|
||||
android:screenOrientation="portrait"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard">
|
||||
|
||||
<intent-filter>
|
||||
|
@ -25,8 +25,7 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="5dip"
|
||||
android:paddingRight="5dip">
|
||||
android:paddingLeft="5dip">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_filename"
|
||||
@ -49,12 +48,48 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/ascii_armour"
|
||||
<TableLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:stretchColumns="1"
|
||||
android:paddingLeft="6dip">
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView android:id="@+id/label_algorithm"
|
||||
android:text="Algorithm:"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingRight="10dip"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/algorithm"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_ascii_armour"
|
||||
android:text="@string/ascii_armour"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingRight="10dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/ascii_armour"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="right|center_vertical"/>
|
||||
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<TabHost
|
||||
android:id="@+id/tab_host"
|
||||
android:layout_weight="1"
|
||||
@ -76,7 +111,7 @@
|
||||
<LinearLayout
|
||||
android:id="@+id/tab_asymmetric"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
@ -136,18 +171,12 @@
|
||||
android:id="@+id/public_key_list"
|
||||
android:choiceMode="multipleChoice"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
<!-- -->
|
||||
<ScrollView
|
||||
android:id="@+id/tab_symmetric"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/tab_symmetric"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
@ -157,26 +186,8 @@
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
android:stretchColumns="1"
|
||||
android:layout_marginRight="?android:attr/scrollbarSize"
|
||||
android:paddingLeft="6dip">
|
||||
|
||||
<TableRow
|
||||
android:layout_marginBottom="5dip">
|
||||
|
||||
<TextView android:id="@+id/label_algorithm"
|
||||
android:text="Algorithm:"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingRight="10dip"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/algorithm"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView android:id="@+id/label_pass_phrase"
|
||||
@ -214,8 +225,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</TabHost>
|
||||
|
@ -45,8 +45,8 @@
|
||||
<string name="btn_save">Save</string>
|
||||
<string name="btn_doNotSave">Cancel</string>
|
||||
|
||||
<string name="tab_symmetric">Symmetric</string>
|
||||
<string name="tab_asymmetric">Asymmetric</string>
|
||||
<string name="tab_symmetric">Use Pass Phrase</string>
|
||||
<string name="tab_asymmetric">Use Public Key</string>
|
||||
|
||||
<string name="menu_about">About</string>
|
||||
<string name="menu_addAccount">Add GMail Account</string>
|
||||
|
@ -41,6 +41,7 @@ import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -66,6 +67,7 @@ import org.bouncycastle2.openpgp.PGPLiteralDataGenerator;
|
||||
import org.bouncycastle2.openpgp.PGPObjectFactory;
|
||||
import org.bouncycastle2.openpgp.PGPOnePassSignature;
|
||||
import org.bouncycastle2.openpgp.PGPOnePassSignatureList;
|
||||
import org.bouncycastle2.openpgp.PGPPBEEncryptedData;
|
||||
import org.bouncycastle2.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle2.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle2.openpgp.PGPPublicKeyEncryptedData;
|
||||
@ -1361,24 +1363,60 @@ public class Apg {
|
||||
throw new GeneralException("data not valid encryption data");
|
||||
}
|
||||
|
||||
// TODO: currently we always only look at the first known key
|
||||
// find the secret key
|
||||
PGPSecretKey secretKey = null;
|
||||
for (PGPPublicKeyEncryptedData pbe :
|
||||
new IterableIterator<PGPPublicKeyEncryptedData>(enc.getEncryptedDataObjects())) {
|
||||
Iterator it = enc.getEncryptedDataObjects();
|
||||
while (it.hasNext()) {
|
||||
Object obj = it.next();
|
||||
if (obj instanceof PGPPublicKeyEncryptedData) {
|
||||
PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
|
||||
secretKey = findSecretKey(pbe.getKeyID());
|
||||
if (secretKey != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (secretKey == null) {
|
||||
throw new GeneralException("couldn't find a secret key to decrypt");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return secretKey.getKeyID();
|
||||
}
|
||||
|
||||
public static boolean hasSymmetricEncryption(InputStream inStream)
|
||||
throws GeneralException, IOException {
|
||||
InputStream in = PGPUtil.getDecoderStream(inStream);
|
||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||
PGPEncryptedDataList enc;
|
||||
Object o = pgpF.nextObject();
|
||||
|
||||
// the first object might be a PGP marker packet.
|
||||
if (o instanceof PGPEncryptedDataList) {
|
||||
enc = (PGPEncryptedDataList) o;
|
||||
} else {
|
||||
enc = (PGPEncryptedDataList) pgpF.nextObject();
|
||||
}
|
||||
|
||||
if (enc == null) {
|
||||
throw new GeneralException("data not valid encryption data");
|
||||
}
|
||||
|
||||
Iterator it = enc.getEncryptedDataObjects();
|
||||
while (it.hasNext()) {
|
||||
Object obj = it.next();
|
||||
if (obj instanceof PGPPBEEncryptedData) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Bundle decrypt(InputStream inStream, OutputStream outStream,
|
||||
String passPhrase, ProgressDialogUpdater progress)
|
||||
String passPhrase, ProgressDialogUpdater progress,
|
||||
boolean assumeSymmetric)
|
||||
throws IOException, GeneralException, PGPException, SignatureException {
|
||||
Bundle returnData = new Bundle();
|
||||
InputStream in = PGPUtil.getDecoderStream(inStream);
|
||||
@ -1399,18 +1437,48 @@ public class Apg {
|
||||
throw new GeneralException("data not valid encryption data");
|
||||
}
|
||||
|
||||
InputStream clear = null;
|
||||
PGPEncryptedData encryptedData = null;
|
||||
|
||||
// TODO: currently we always only look at the first known key or symmetric encryption,
|
||||
// there might be more...
|
||||
if (assumeSymmetric) {
|
||||
PGPPBEEncryptedData pbe = null;
|
||||
Iterator it = enc.getEncryptedDataObjects();
|
||||
// find secret key
|
||||
while (it.hasNext()) {
|
||||
Object obj = it.next();
|
||||
if (obj instanceof PGPPBEEncryptedData) {
|
||||
pbe = (PGPPBEEncryptedData) obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbe == null) {
|
||||
throw new GeneralException("couldn't find a packet with symmetric encryption");
|
||||
}
|
||||
|
||||
progress.setProgress("decrypting data...", 20, 100);
|
||||
clear = pbe.getDataStream(passPhrase.toCharArray(), new BouncyCastleProvider());
|
||||
encryptedData = pbe;
|
||||
} else {
|
||||
progress.setProgress("finding key...", 10, 100);
|
||||
// find the secret key
|
||||
PGPPublicKeyEncryptedData pbe = null;
|
||||
PGPSecretKey secretKey = null;
|
||||
for (PGPPublicKeyEncryptedData encData :
|
||||
new IterableIterator<PGPPublicKeyEncryptedData>(enc.getEncryptedDataObjects())) {
|
||||
Iterator it = enc.getEncryptedDataObjects();
|
||||
// find secret key
|
||||
while (it.hasNext()) {
|
||||
Object obj = it.next();
|
||||
if (obj instanceof PGPPublicKeyEncryptedData) {
|
||||
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
||||
secretKey = findSecretKey(encData.getKeyID());
|
||||
if (secretKey != null) {
|
||||
pbe = encData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (secretKey == null) {
|
||||
throw new GeneralException("couldn't find a secret key to decrypt");
|
||||
}
|
||||
@ -1423,8 +1491,12 @@ public class Apg {
|
||||
} catch (PGPException e) {
|
||||
throw new PGPException("wrong pass phrase");
|
||||
}
|
||||
|
||||
progress.setProgress("decrypting data...", 30, 100);
|
||||
InputStream clear = pbe.getDataStream(privateKey, new BouncyCastleProvider());
|
||||
clear = pbe.getDataStream(privateKey, new BouncyCastleProvider());
|
||||
encryptedData = pbe;
|
||||
}
|
||||
|
||||
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
|
||||
Object dataChunk = plainFact.nextObject();
|
||||
PGPOnePassSignature signature = null;
|
||||
@ -1511,15 +1583,15 @@ public class Apg {
|
||||
}
|
||||
|
||||
// TODO: add integrity somewhere
|
||||
if (pbe.isIntegrityProtected()) {
|
||||
if (encryptedData.isIntegrityProtected()) {
|
||||
progress.setProgress("verifying integrity...", 90, 100);
|
||||
if (!pbe.verify()) {
|
||||
System.err.println("message failed integrity check");
|
||||
if (encryptedData.verify()) {
|
||||
// passed
|
||||
} else {
|
||||
System.err.println("message integrity check passed");
|
||||
// failed
|
||||
}
|
||||
} else {
|
||||
System.err.println("no message integrity check");
|
||||
// no integrity check
|
||||
}
|
||||
|
||||
progress.setProgress("done.", 100, 100);
|
||||
|
@ -26,9 +26,6 @@ import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.text.InputType;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnKeyListener;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
@ -43,36 +40,25 @@ public class AskForSecretKeyPassPhrase {
|
||||
PassPhraseCallbackInterface callback) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
|
||||
final PGPSecretKey secretKey =
|
||||
Apg.getMasterKey(Apg.findSecretKeyRing(secretKeyId));
|
||||
alert.setTitle(R.string.title_authentification);
|
||||
|
||||
final PGPSecretKey secretKey;
|
||||
|
||||
if (secretKeyId == 0) {
|
||||
secretKey = null;
|
||||
alert.setMessage("Pass phrase");
|
||||
} else {
|
||||
secretKey = Apg.getMasterKey(Apg.findSecretKeyRing(secretKeyId));
|
||||
if (secretKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String userId = Apg.getMainUserIdSafe(context, secretKey);
|
||||
|
||||
alert.setTitle(R.string.title_authentification);
|
||||
alert.setMessage("Pass phrase for " + userId);
|
||||
}
|
||||
|
||||
final EditText input = new EditText(context);
|
||||
input.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
input.setTransformationMethod(new PasswordTransformationMethod());
|
||||
input.setOnKeyListener(new OnKeyListener() {
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
// If the event is a key-down event on the "enter" button
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN &&
|
||||
keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
try {
|
||||
((AlertDialog) v.getParent()).getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
.performClick();
|
||||
} catch (ClassCastException e) {
|
||||
// don't do anything if we're not in that dialog
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// 5dip padding
|
||||
int padding = (int) (10 * context.getResources().getDisplayMetrics().densityDpi / 160);
|
||||
LinearLayout layout = new LinearLayout(context);
|
||||
@ -91,6 +77,7 @@ public class AskForSecretKeyPassPhrase {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
String passPhrase = "" + input.getText();
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
secretKey.extractPrivateKey(passPhrase.toCharArray(),
|
||||
new BouncyCastleProvider());
|
||||
@ -100,6 +87,7 @@ public class AskForSecretKeyPassPhrase {
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
cb.passPhraseCallback(passPhrase);
|
||||
}
|
||||
});
|
||||
|
@ -59,6 +59,8 @@ public class DecryptFileActivity extends BaseActivity {
|
||||
private String mInputFilename = null;
|
||||
private String mOutputFilename = null;
|
||||
|
||||
private boolean mAssumeSymmetricEncryption = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -128,6 +130,16 @@ public class DecryptFileActivity extends BaseActivity {
|
||||
try {
|
||||
InputStream in = new FileInputStream(mInputFilename);
|
||||
setSecretKeyId(Apg.getDecryptionKeyId(in));
|
||||
if (getSecretKeyId() == 0) {
|
||||
// reopen the file to check whether there's symmetric encryption data in there
|
||||
in = new FileInputStream(mInputFilename);
|
||||
if (!Apg.hasSymmetricEncryption(in)) {
|
||||
throw new Apg.GeneralException("no suitable keys found");
|
||||
}
|
||||
mAssumeSymmetricEncryption = true;
|
||||
} else {
|
||||
mAssumeSymmetricEncryption = false;
|
||||
}
|
||||
showDialog(Id.dialog.pass_phrase);
|
||||
} catch (FileNotFoundException e) {
|
||||
error = "file not found: " + e.getLocalizedMessage();
|
||||
@ -168,7 +180,7 @@ public class DecryptFileActivity extends BaseActivity {
|
||||
InputStream in = new FileInputStream(mInputFilename);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
data = Apg.decrypt(in, out, Apg.getPassPhrase(), this);
|
||||
data = Apg.decrypt(in, out, Apg.getPassPhrase(), this, mAssumeSymmetricEncryption);
|
||||
|
||||
out.close();
|
||||
OutputStream fileOut = new FileOutputStream(mOutputFilename);
|
||||
|
@ -204,7 +204,7 @@ public class DecryptMessageActivity extends BaseActivity {
|
||||
if (mSignedOnly) {
|
||||
data = Apg.verifyText(in, out, this);
|
||||
} else {
|
||||
data = Apg.decrypt(in, out, Apg.getPassPhrase(), this);
|
||||
data = Apg.decrypt(in, out, Apg.getPassPhrase(), this, false);
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
@ -101,7 +101,7 @@ public class EncryptFileActivity extends BaseActivity {
|
||||
|
||||
TabSpec ts2 = mTabHost.newTabSpec(TAB_SYMMETRIC);
|
||||
ts2.setIndicator(getString(R.string.tab_symmetric),
|
||||
getResources().getDrawable(R.drawable.encrypted));
|
||||
getResources().getDrawable(R.drawable.key));
|
||||
ts2.setContent(R.id.tab_symmetric);
|
||||
mTabHost.addTab(ts2);
|
||||
|
||||
|
@ -224,7 +224,7 @@ public class MainActivity extends BaseActivity {
|
||||
new SpannableString("Read the warnings!\n\n" +
|
||||
"Changes:\n" +
|
||||
" * OI File Manager support\n" +
|
||||
" * file encryption\n" +
|
||||
" * file encryption/decryption\n" +
|
||||
"\n" +
|
||||
"WARNING: be careful editing your existing keys, as they " +
|
||||
"WILL be stripped of certificates right now.\n" +
|
||||
|
Loading…
Reference in New Issue
Block a user