mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Merge remote-tracking branch 'origin/development' into development
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
This commit is contained in:
commit
abce05d529
@ -47,6 +47,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
import org.sufficientlysecure.keychain.util.TestingUtils;
|
import org.sufficientlysecure.keychain.util.TestingUtils;
|
||||||
|
|
||||||
@ -65,8 +66,8 @@ import java.util.Random;
|
|||||||
public class CertifyOperationTest {
|
public class CertifyOperationTest {
|
||||||
|
|
||||||
static UncachedKeyRing mStaticRing1, mStaticRing2;
|
static UncachedKeyRing mStaticRing1, mStaticRing2;
|
||||||
static String mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
||||||
static String mKeyPhrase2 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase2 = TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
static PrintStream oldShadowStream;
|
static PrintStream oldShadowStream;
|
||||||
|
|
||||||
@ -255,13 +256,13 @@ public class CertifyOperationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CertifyOperation operationWithFakePassphraseCache(
|
private CertifyOperation operationWithFakePassphraseCache(
|
||||||
final Long checkMasterKeyId, final Long checkSubKeyId, final String passphrase) {
|
final Long checkMasterKeyId, final Long checkSubKeyId, final Passphrase passphrase) {
|
||||||
|
|
||||||
return new CertifyOperation(Robolectric.application,
|
return new CertifyOperation(Robolectric.application,
|
||||||
new ProviderHelper(Robolectric.application),
|
new ProviderHelper(Robolectric.application),
|
||||||
null, null) {
|
null, null) {
|
||||||
@Override
|
@Override
|
||||||
public String getCachedPassphrase(long masterKeyId, long subKeyId)
|
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId)
|
||||||
throws NoSecretKeyException {
|
throws NoSecretKeyException {
|
||||||
if (checkMasterKeyId != null) {
|
if (checkMasterKeyId != null) {
|
||||||
Assert.assertEquals("requested passphrase should be for expected master key id",
|
Assert.assertEquals("requested passphrase should be for expected master key id",
|
||||||
|
@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
import org.sufficientlysecure.keychain.util.TestingUtils;
|
import org.sufficientlysecure.keychain.util.TestingUtils;
|
||||||
|
|
||||||
@ -51,11 +52,11 @@ import java.util.Iterator;
|
|||||||
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
||||||
public class ExportTest {
|
public class ExportTest {
|
||||||
|
|
||||||
static String mPassphrase = TestingUtils.genPassphrase(true);
|
static Passphrase mPassphrase = TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
static UncachedKeyRing mStaticRing1, mStaticRing2;
|
static UncachedKeyRing mStaticRing1, mStaticRing2;
|
||||||
static String mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
||||||
static String mKeyPhrase2 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase2 = TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
static PrintStream oldShadowStream;
|
static PrintStream oldShadowStream;
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ public class ExportTest {
|
|||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
||||||
parcel.mAddUserIds.add("snails");
|
parcel.mAddUserIds.add("snails");
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel(null, "1234");
|
parcel.mNewUnlock = new ChangeUnlockParcel(null, new Passphrase("1234"));
|
||||||
|
|
||||||
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
||||||
Assert.assertTrue("initial test key creation must succeed", result.success());
|
Assert.assertTrue("initial test key creation must succeed", result.success());
|
||||||
|
@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
import org.sufficientlysecure.keychain.util.TestingUtils;
|
import org.sufficientlysecure.keychain.util.TestingUtils;
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ import java.util.Iterator;
|
|||||||
public class PromoteKeyOperationTest {
|
public class PromoteKeyOperationTest {
|
||||||
|
|
||||||
static UncachedKeyRing mStaticRing;
|
static UncachedKeyRing mStaticRing;
|
||||||
static String mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
static PrintStream oldShadowStream;
|
static PrintStream oldShadowStream;
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
import org.sufficientlysecure.keychain.util.TestingUtils;
|
import org.sufficientlysecure.keychain.util.TestingUtils;
|
||||||
|
|
||||||
@ -47,17 +48,18 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
||||||
public class PgpEncryptDecryptTest {
|
public class PgpEncryptDecryptTest {
|
||||||
|
|
||||||
static String mPassphrase = TestingUtils.genPassphrase(true);
|
static Passphrase mPassphrase = TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
static UncachedKeyRing mStaticRing1, mStaticRing2;
|
static UncachedKeyRing mStaticRing1, mStaticRing2;
|
||||||
static String mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase1 = TestingUtils.genPassphrase(true);
|
||||||
static String mKeyPhrase2 = TestingUtils.genPassphrase(true);
|
static Passphrase mKeyPhrase2 = TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
static PrintStream oldShadowStream;
|
static PrintStream oldShadowStream;
|
||||||
|
|
||||||
@ -180,7 +182,7 @@ public class PgpEncryptDecryptTest {
|
|||||||
new ProviderHelper(Robolectric.application),
|
new ProviderHelper(Robolectric.application),
|
||||||
null, // new DummyPassphraseCache(mPassphrase, 0L),
|
null, // new DummyPassphraseCache(mPassphrase, 0L),
|
||||||
data, out);
|
data, out);
|
||||||
b.setPassphrase(mPassphrase + "x");
|
b.setPassphrase(new Passphrase(Arrays.toString(mPassphrase.getCharArray()) + "x"));
|
||||||
DecryptVerifyResult result = b.build().execute();
|
DecryptVerifyResult result = b.build().execute();
|
||||||
Assert.assertFalse("decryption must succeed", result.success());
|
Assert.assertFalse("decryption must succeed", result.success());
|
||||||
Assert.assertEquals("decrypted plaintext should be empty", 0, out.size());
|
Assert.assertEquals("decrypted plaintext should be empty", 0, out.size());
|
||||||
@ -511,7 +513,7 @@ public class PgpEncryptDecryptTest {
|
|||||||
|
|
||||||
private PgpDecryptVerify.Builder builderWithFakePassphraseCache (
|
private PgpDecryptVerify.Builder builderWithFakePassphraseCache (
|
||||||
InputData data, OutputStream out,
|
InputData data, OutputStream out,
|
||||||
final String passphrase, final Long checkMasterKeyId, final Long checkSubKeyId) {
|
final Passphrase passphrase, final Long checkMasterKeyId, final Long checkSubKeyId) {
|
||||||
|
|
||||||
return new PgpDecryptVerify.Builder(Robolectric.application,
|
return new PgpDecryptVerify.Builder(Robolectric.application,
|
||||||
new ProviderHelper(Robolectric.application),
|
new ProviderHelper(Robolectric.application),
|
||||||
@ -520,7 +522,7 @@ public class PgpEncryptDecryptTest {
|
|||||||
public PgpDecryptVerify build() {
|
public PgpDecryptVerify build() {
|
||||||
return new PgpDecryptVerify(this) {
|
return new PgpDecryptVerify(this) {
|
||||||
@Override
|
@Override
|
||||||
public String getCachedPassphrase(long masterKeyId, long subKeyId)
|
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId)
|
||||||
throws NoSecretKeyException {
|
throws NoSecretKeyException {
|
||||||
if (checkMasterKeyId != null) {
|
if (checkMasterKeyId != null) {
|
||||||
Assert.assertEquals("requested passphrase should be for expected master key id",
|
Assert.assertEquals("requested passphrase should be for expected master key id",
|
||||||
|
@ -53,6 +53,7 @@ import org.sufficientlysecure.keychain.support.KeyringBuilder;
|
|||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
import org.sufficientlysecure.keychain.support.TestDataUtil;
|
import org.sufficientlysecure.keychain.support.TestDataUtil;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
import org.sufficientlysecure.keychain.util.TestingUtils;
|
import org.sufficientlysecure.keychain.util.TestingUtils;
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ import java.util.Random;
|
|||||||
public class PgpKeyOperationTest {
|
public class PgpKeyOperationTest {
|
||||||
|
|
||||||
static UncachedKeyRing staticRing;
|
static UncachedKeyRing staticRing;
|
||||||
final static String passphrase = TestingUtils.genPassphrase();
|
final static Passphrase passphrase = TestingUtils.genPassphrase();
|
||||||
|
|
||||||
UncachedKeyRing ring;
|
UncachedKeyRing ring;
|
||||||
PgpKeyOperation op;
|
PgpKeyOperation op;
|
||||||
@ -295,9 +296,9 @@ public class PgpKeyOperationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
String badphrase = "";
|
Passphrase badphrase = new Passphrase();
|
||||||
if (badphrase.equals(passphrase)) {
|
if (badphrase.equals(passphrase)) {
|
||||||
badphrase = "a";
|
badphrase = new Passphrase("a");
|
||||||
}
|
}
|
||||||
|
|
||||||
assertModifyFailure("keyring modification with bad passphrase should fail",
|
assertModifyFailure("keyring modification with bad passphrase should fail",
|
||||||
@ -1036,7 +1037,7 @@ public class PgpKeyOperationTest {
|
|||||||
public void testPassphraseChange() throws Exception {
|
public void testPassphraseChange() throws Exception {
|
||||||
|
|
||||||
// change passphrase to empty
|
// change passphrase to empty
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel("");
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
|
||||||
// note that canonicalization here necessarily strips the empty notation packet
|
// note that canonicalization here necessarily strips the empty notation packet
|
||||||
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB,
|
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB,
|
||||||
passphrase);
|
passphrase);
|
||||||
@ -1050,9 +1051,9 @@ public class PgpKeyOperationTest {
|
|||||||
PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
|
PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
|
||||||
|
|
||||||
// modify keyring, change to non-empty passphrase
|
// modify keyring, change to non-empty passphrase
|
||||||
String otherPassphrase = TestingUtils.genPassphrase(true);
|
Passphrase otherPassphrase = TestingUtils.genPassphrase(true);
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel(otherPassphrase);
|
parcel.mNewUnlock = new ChangeUnlockParcel(otherPassphrase);
|
||||||
modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, "");
|
modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, new Passphrase());
|
||||||
|
|
||||||
Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
|
Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
|
||||||
3, onlyB.size());
|
3, onlyB.size());
|
||||||
@ -1075,7 +1076,7 @@ public class PgpKeyOperationTest {
|
|||||||
Assert.assertEquals("extracted packet should be a secret subkey",
|
Assert.assertEquals("extracted packet should be a secret subkey",
|
||||||
PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
|
PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
|
||||||
|
|
||||||
String otherPassphrase2 = TestingUtils.genPassphrase(true);
|
Passphrase otherPassphrase2 = TestingUtils.genPassphrase(true);
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel(otherPassphrase2);
|
parcel.mNewUnlock = new ChangeUnlockParcel(otherPassphrase2);
|
||||||
{
|
{
|
||||||
// if we replace a secret key with one without passphrase
|
// if we replace a secret key with one without passphrase
|
||||||
@ -1112,7 +1113,7 @@ public class PgpKeyOperationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testUnlockPin() throws Exception {
|
public void testUnlockPin() throws Exception {
|
||||||
|
|
||||||
String pin = "5235125";
|
Passphrase pin = new Passphrase("5235125");
|
||||||
|
|
||||||
// change passphrase to a pin type
|
// change passphrase to a pin type
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel(null, pin);
|
parcel.mNewUnlock = new ChangeUnlockParcel(null, pin);
|
||||||
@ -1138,7 +1139,7 @@ public class PgpKeyOperationTest {
|
|||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
||||||
{
|
{
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel("phrayse", null);
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase("phrayse"), null);
|
||||||
applyModificationWithChecks(parcel, modified, onlyA, onlyB, pin, true, false);
|
applyModificationWithChecks(parcel, modified, onlyA, onlyB, pin, true, false);
|
||||||
|
|
||||||
Assert.assertEquals("exactly four packets should have been removed (the secret keys + notation packet)",
|
Assert.assertEquals("exactly four packets should have been removed (the secret keys + notation packet)",
|
||||||
@ -1171,7 +1172,7 @@ public class PgpKeyOperationTest {
|
|||||||
UncachedKeyRing ring,
|
UncachedKeyRing ring,
|
||||||
ArrayList<RawPacket> onlyA,
|
ArrayList<RawPacket> onlyA,
|
||||||
ArrayList<RawPacket> onlyB,
|
ArrayList<RawPacket> onlyB,
|
||||||
String passphrase) {
|
Passphrase passphrase) {
|
||||||
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
|
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1180,7 +1181,7 @@ public class PgpKeyOperationTest {
|
|||||||
UncachedKeyRing ring,
|
UncachedKeyRing ring,
|
||||||
ArrayList<RawPacket> onlyA,
|
ArrayList<RawPacket> onlyA,
|
||||||
ArrayList<RawPacket> onlyB,
|
ArrayList<RawPacket> onlyB,
|
||||||
String passphrase,
|
Passphrase passphrase,
|
||||||
boolean canonicalize,
|
boolean canonicalize,
|
||||||
boolean constantCanonicalize) {
|
boolean constantCanonicalize) {
|
||||||
|
|
||||||
@ -1257,7 +1258,7 @@ public class PgpKeyOperationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assertModifyFailure(String reason, UncachedKeyRing ring,
|
private void assertModifyFailure(String reason, UncachedKeyRing ring,
|
||||||
SaveKeyringParcel parcel, String passphrase, LogType expected)
|
SaveKeyringParcel parcel, Passphrase passphrase, LogType expected)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
|
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
|
||||||
|
@ -61,6 +61,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
@ -111,7 +112,7 @@ public class UncachedKeyringCanonicalizeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel("");
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
|
||||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||||
|
|
||||||
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
||||||
@ -546,7 +547,7 @@ public class UncachedKeyringCanonicalizeTest {
|
|||||||
CanonicalizedSecretKeyRing canonicalized = (CanonicalizedSecretKeyRing) ring.canonicalize(log, 0);
|
CanonicalizedSecretKeyRing canonicalized = (CanonicalizedSecretKeyRing) ring.canonicalize(log, 0);
|
||||||
|
|
||||||
CanonicalizedSecretKey masterSecretKey = canonicalized.getSecretKey();
|
CanonicalizedSecretKey masterSecretKey = canonicalized.getSecretKey();
|
||||||
masterSecretKey.unlock("");
|
masterSecretKey.unlock(new Passphrase());
|
||||||
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
|
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
|
||||||
PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature(
|
PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature(
|
||||||
masterPublicKey, masterSecretKey.getPrivateKey(), masterSecretKey.getPrivateKey(),
|
masterPublicKey, masterSecretKey.getPrivateKey(), masterSecretKey.getPrivateKey(),
|
||||||
|
@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -105,7 +106,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel("");
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
|
||||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||||
|
|
||||||
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
||||||
@ -122,7 +123,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
|
|
||||||
parcel.mAddUserIds.add("shy");
|
parcel.mAddUserIds.add("shy");
|
||||||
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel("");
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
|
||||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||||
|
|
||||||
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
||||||
@ -185,11 +186,11 @@ public class UncachedKeyringMergeTest {
|
|||||||
|
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddUserIds.add("flim");
|
parcel.mAddUserIds.add("flim");
|
||||||
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modifiedA = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
|
||||||
|
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddUserIds.add("flam");
|
parcel.mAddUserIds.add("flam");
|
||||||
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modifiedB = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // merge A into base
|
{ // merge A into base
|
||||||
@ -226,8 +227,8 @@ public class UncachedKeyringMergeTest {
|
|||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modifiedA = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
|
||||||
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modifiedB = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
|
||||||
|
|
||||||
subKeyIdA = KeyringTestingHelper.getSubkeyId(modifiedA, 2);
|
subKeyIdA = KeyringTestingHelper.getSubkeyId(modifiedA, 2);
|
||||||
subKeyIdB = KeyringTestingHelper.getSubkeyId(modifiedB, 2);
|
subKeyIdB = KeyringTestingHelper.getSubkeyId(modifiedB, 2);
|
||||||
@ -268,7 +269,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(ringA, 1));
|
parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(ringA, 1));
|
||||||
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
|
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
|
||||||
ringA.getEncoded(), false, 0);
|
ringA.getEncoded(), false, 0);
|
||||||
modified = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modified = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -293,7 +294,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
|
|
||||||
CanonicalizedSecretKey secretKey = new CanonicalizedSecretKeyRing(
|
CanonicalizedSecretKey secretKey = new CanonicalizedSecretKeyRing(
|
||||||
ringB.getEncoded(), false, 0).getSecretKey();
|
ringB.getEncoded(), false, 0).getSecretKey();
|
||||||
secretKey.unlock("");
|
secretKey.unlock(new Passphrase());
|
||||||
// sign all user ids
|
// sign all user ids
|
||||||
modified = secretKey.certifyUserIds(publicRing, publicRing.getPublicKey().getUnorderedUserIds(), null, null);
|
modified = secretKey.certifyUserIds(publicRing, publicRing.getPublicKey().getUnorderedUserIds(), null, null);
|
||||||
}
|
}
|
||||||
@ -362,7 +363,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
|
|
||||||
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
|
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
|
||||||
ringA.getEncoded(), false, 0);
|
ringA.getEncoded(), false, 0);
|
||||||
modified = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modified = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@ -70,7 +71,7 @@ public class UncachedKeyringTest {
|
|||||||
parcel.mAddUserAttribute.add(uat);
|
parcel.mAddUserAttribute.add(uat);
|
||||||
}
|
}
|
||||||
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel("");
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
|
||||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||||
|
|
||||||
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
||||||
|
@ -1,16 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.util;
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by valodim on 9/15/14.
|
|
||||||
*/
|
|
||||||
public class TestingUtils {
|
public class TestingUtils {
|
||||||
public static String genPassphrase() {
|
public static Passphrase genPassphrase() {
|
||||||
return genPassphrase(false);
|
return genPassphrase(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String genPassphrase(boolean noEmpty) {
|
public static Passphrase genPassphrase(boolean noEmpty) {
|
||||||
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
|
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
StringBuilder passbuilder = new StringBuilder();
|
StringBuilder passbuilder = new StringBuilder();
|
||||||
@ -19,6 +33,6 @@ public class TestingUtils {
|
|||||||
passbuilder.append(chars.charAt(r.nextInt(chars.length())));
|
passbuilder.append(chars.charAt(r.nextInt(chars.length())));
|
||||||
}
|
}
|
||||||
System.out.println("Generated passphrase: '" + passbuilder.toString() + "'");
|
System.out.println("Generated passphrase: '" + passbuilder.toString() + "'");
|
||||||
return passbuilder.toString();
|
return new Passphrase(passbuilder.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,16 +86,10 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
|
||||||
android:name=".ui.FirstTimeActivity"
|
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.CreateKeyActivity"
|
android:name=".ui.CreateKeyActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:label="@string/title_create_key"
|
android:label="@string/title_manage_my_keys"
|
||||||
android:parentActivityName=".ui.MainActivity">
|
android:parentActivityName=".ui.MainActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
@ -70,6 +70,8 @@ public class ImportKeysList extends ArrayList<ImportKeysListEntry> {
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keep track if this key result is from a HKP keyserver
|
||||||
|
boolean incomingFromHkpServer = true;
|
||||||
// we’re going to want to try to fetch the key from everywhere we found it, so remember
|
// we’re going to want to try to fetch the key from everywhere we found it, so remember
|
||||||
// all the origins
|
// all the origins
|
||||||
for (String origin : incoming.getOrigins()) {
|
for (String origin : incoming.getOrigins()) {
|
||||||
@ -78,13 +80,24 @@ public class ImportKeysList extends ArrayList<ImportKeysListEntry> {
|
|||||||
// to work properly, Keybase-sourced entries need to pass along the extra
|
// to work properly, Keybase-sourced entries need to pass along the extra
|
||||||
if (KeybaseKeyserver.ORIGIN.equals(origin)) {
|
if (KeybaseKeyserver.ORIGIN.equals(origin)) {
|
||||||
existing.setExtraData(incoming.getExtraData());
|
existing.setExtraData(incoming.getExtraData());
|
||||||
|
// one of the origins is not a HKP keyserver
|
||||||
|
incomingFromHkpServer = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<String> incomingIDs = incoming.getUserIds();
|
ArrayList<String> incomingIDs = incoming.getUserIds();
|
||||||
ArrayList<String> existingIDs = existing.getUserIds();
|
ArrayList<String> existingIDs = existing.getUserIds();
|
||||||
for (String incomingID : incomingIDs) {
|
for (String incomingID : incomingIDs) {
|
||||||
if (!existingIDs.contains(incomingID)) {
|
if (!existingIDs.contains(incomingID)) {
|
||||||
existingIDs.add(incomingID);
|
// prepend HKP server results to the start of the list,
|
||||||
|
// so that the UI (for cloud key search, which is picking the first list item)
|
||||||
|
// shows the right main email address, as mail addresses returned by HKP servers
|
||||||
|
// are preferred over keybase.io IDs
|
||||||
|
if (incomingFromHkpServer) {
|
||||||
|
existingIDs.add(0, incomingID);
|
||||||
|
} else {
|
||||||
|
existingIDs.add(incomingID);
|
||||||
|
}
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
|
|||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ public abstract class BaseOperation implements PassphraseCacheInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
|
public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
|
||||||
try {
|
try {
|
||||||
long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId);
|
long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId);
|
||||||
return getCachedPassphrase(masterKeyId, subKeyId);
|
return getCachedPassphrase(masterKeyId, subKeyId);
|
||||||
@ -111,7 +112,7 @@ public abstract class BaseOperation implements PassphraseCacheInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException {
|
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException {
|
||||||
try {
|
try {
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
return PassphraseCacheService.getCachedPassphrase(
|
||||||
mContext, masterKeyId, subKeyId);
|
mContext, masterKeyId, subKeyId);
|
||||||
|
@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
|||||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@ -83,7 +84,7 @@ public class CertifyOperation extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// certification is always with the master key id, so use that one
|
// certification is always with the master key id, so use that one
|
||||||
char[] passphrase = parcel.mCryptoInput.getPassphrase();
|
Passphrase passphrase = parcel.mCryptoInput.getPassphrase();
|
||||||
|
|
||||||
if (!certificationKey.unlock(passphrase)) {
|
if (!certificationKey.unlock(passphrase)) {
|
||||||
log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2);
|
log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2);
|
||||||
|
@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
@ -22,6 +22,7 @@ import android.os.Parcel;
|
|||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpMetadata;
|
import org.openintents.openpgp.OpenPgpMetadata;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
public class DecryptVerifyResult extends OperationResult {
|
public class DecryptVerifyResult extends OperationResult {
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ public class DecryptVerifyResult extends OperationResult {
|
|||||||
|
|
||||||
long mNfcSubKeyId;
|
long mNfcSubKeyId;
|
||||||
byte[] mNfcSessionKey;
|
byte[] mNfcSessionKey;
|
||||||
String mNfcPassphrase;
|
Passphrase mNfcPassphrase;
|
||||||
|
|
||||||
OpenPgpSignatureResult mSignatureResult;
|
OpenPgpSignatureResult mSignatureResult;
|
||||||
OpenPgpMetadata mDecryptMetadata;
|
OpenPgpMetadata mDecryptMetadata;
|
||||||
@ -53,7 +54,7 @@ public class DecryptVerifyResult extends OperationResult {
|
|||||||
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
|
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNfcState(long subKeyId, byte[] sessionKey, String passphrase) {
|
public void setNfcState(long subKeyId, byte[] sessionKey, Passphrase passphrase) {
|
||||||
mNfcSubKeyId = subKeyId;
|
mNfcSubKeyId = subKeyId;
|
||||||
mNfcSessionKey = sessionKey;
|
mNfcSessionKey = sessionKey;
|
||||||
mNfcPassphrase = passphrase;
|
mNfcPassphrase = passphrase;
|
||||||
@ -67,7 +68,7 @@ public class DecryptVerifyResult extends OperationResult {
|
|||||||
return mNfcSessionKey;
|
return mNfcSessionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNfcPassphrase() {
|
public Passphrase getNfcPassphrase() {
|
||||||
return mNfcPassphrase;
|
return mNfcPassphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +110,7 @@ public class DecryptVerifyResult extends OperationResult {
|
|||||||
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
||||||
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
|
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
|
||||||
mNfcSessionKey = source.readInt() != 0 ? source.createByteArray() : null;
|
mNfcSessionKey = source.readInt() != 0 ? source.createByteArray() : null;
|
||||||
mNfcPassphrase = source.readString();
|
mNfcPassphrase = source.readParcelable(Passphrase.class.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
@ -127,7 +128,7 @@ public class DecryptVerifyResult extends OperationResult {
|
|||||||
} else {
|
} else {
|
||||||
dest.writeInt(0);
|
dest.writeInt(0);
|
||||||
}
|
}
|
||||||
dest.writeString(mNfcPassphrase);
|
dest.writeParcelable(mNfcPassphrase, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<DecryptVerifyResult> CREATOR = new Creator<DecryptVerifyResult>() {
|
public static final Creator<DecryptVerifyResult> CREATOR = new Creator<DecryptVerifyResult>() {
|
||||||
|
@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.operations.results;
|
|||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class PgpSignEncryptResult extends OperationResult {
|
public class PgpSignEncryptResult extends OperationResult {
|
||||||
@ -35,7 +37,7 @@ public class PgpSignEncryptResult extends OperationResult {
|
|||||||
long mNfcKeyId;
|
long mNfcKeyId;
|
||||||
byte[] mNfcHash;
|
byte[] mNfcHash;
|
||||||
int mNfcAlgo;
|
int mNfcAlgo;
|
||||||
String mNfcPassphrase;
|
Passphrase mNfcPassphrase;
|
||||||
byte[] mDetachedSignature;
|
byte[] mDetachedSignature;
|
||||||
|
|
||||||
public long getKeyIdPassphraseNeeded() {
|
public long getKeyIdPassphraseNeeded() {
|
||||||
@ -46,7 +48,7 @@ public class PgpSignEncryptResult extends OperationResult {
|
|||||||
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
|
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, String passphrase) {
|
public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Passphrase passphrase) {
|
||||||
mNfcKeyId = nfcKeyId;
|
mNfcKeyId = nfcKeyId;
|
||||||
mNfcHash = nfcHash;
|
mNfcHash = nfcHash;
|
||||||
mNfcAlgo = nfcAlgo;
|
mNfcAlgo = nfcAlgo;
|
||||||
@ -69,7 +71,7 @@ public class PgpSignEncryptResult extends OperationResult {
|
|||||||
return mNfcAlgo;
|
return mNfcAlgo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNfcPassphrase() {
|
public Passphrase getNfcPassphrase() {
|
||||||
return mNfcPassphrase;
|
return mNfcPassphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,4 +125,4 @@ public class PgpSignEncryptResult extends OperationResult {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -149,14 +150,10 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean unlock(String passphrase) throws PgpGeneralException {
|
|
||||||
return unlock(passphrase.toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true on right passphrase
|
* Returns true on right passphrase
|
||||||
*/
|
*/
|
||||||
public boolean unlock(char[] passphrase) throws PgpGeneralException {
|
public boolean unlock(Passphrase passphrase) throws PgpGeneralException {
|
||||||
// handle keys on OpenPGP cards like they were unlocked
|
// handle keys on OpenPGP cards like they were unlocked
|
||||||
if (mSecretKey.getS2K() != null
|
if (mSecretKey.getS2K() != null
|
||||||
&& mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K
|
&& mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K
|
||||||
@ -168,7 +165,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
|||||||
// try to extract keys using the passphrase
|
// try to extract keys using the passphrase
|
||||||
try {
|
try {
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
|
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
|
||||||
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
|
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
|
||||||
mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED;
|
mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
|
@ -18,14 +18,16 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
public interface PassphraseCacheInterface {
|
public interface PassphraseCacheInterface {
|
||||||
public static class NoSecretKeyException extends Exception {
|
public static class NoSecretKeyException extends Exception {
|
||||||
public NoSecretKeyException() {
|
public NoSecretKeyException() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException;
|
public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException;
|
||||||
|
|
||||||
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException;
|
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
@ -83,7 +84,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
private OutputStream mOutStream;
|
private OutputStream mOutStream;
|
||||||
|
|
||||||
private boolean mAllowSymmetricDecryption;
|
private boolean mAllowSymmetricDecryption;
|
||||||
private String mPassphrase;
|
private Passphrase mPassphrase;
|
||||||
private Set<Long> mAllowedKeyIds;
|
private Set<Long> mAllowedKeyIds;
|
||||||
private boolean mDecryptMetadataOnly;
|
private boolean mDecryptMetadataOnly;
|
||||||
private byte[] mDecryptedSessionKey;
|
private byte[] mDecryptedSessionKey;
|
||||||
@ -118,7 +119,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
private OutputStream mOutStream = null;
|
private OutputStream mOutStream = null;
|
||||||
private Progressable mProgressable = null;
|
private Progressable mProgressable = null;
|
||||||
private boolean mAllowSymmetricDecryption = true;
|
private boolean mAllowSymmetricDecryption = true;
|
||||||
private String mPassphrase = null;
|
private Passphrase mPassphrase = null;
|
||||||
private Set<Long> mAllowedKeyIds = null;
|
private Set<Long> mAllowedKeyIds = null;
|
||||||
private boolean mDecryptMetadataOnly = false;
|
private boolean mDecryptMetadataOnly = false;
|
||||||
private byte[] mDecryptedSessionKey = null;
|
private byte[] mDecryptedSessionKey = null;
|
||||||
@ -159,7 +160,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setPassphrase(String passphrase) {
|
public Builder setPassphrase(Passphrase passphrase) {
|
||||||
mPassphrase = passphrase;
|
mPassphrase = passphrase;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -572,7 +573,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
|
||||||
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
|
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
|
||||||
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||||
mPassphrase.toCharArray());
|
mPassphrase.getCharArray());
|
||||||
|
|
||||||
clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
|
clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
|
||||||
encryptedData = encryptedDataSymmetric;
|
encryptedData = encryptedDataSymmetric;
|
||||||
|
@ -63,6 +63,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSign
|
|||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.Primes;
|
import org.sufficientlysecure.keychain.util.Primes;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
@ -328,7 +329,7 @@ public class PgpKeyOperation {
|
|||||||
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
|
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
|
||||||
|
|
||||||
subProgressPush(50, 100);
|
subProgressPush(50, 100);
|
||||||
CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date(), "");
|
mCryptoInput = new CryptoInputParcel(new Date(), new Passphrase(""));
|
||||||
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, log);
|
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, log);
|
||||||
|
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
@ -444,7 +445,7 @@ public class PgpKeyOperation {
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mCryptoInput.getPassphrase());
|
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mCryptoInput.getPassphrase().getCharArray());
|
||||||
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
|
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
|
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
|
||||||
@ -815,7 +816,7 @@ public class PgpKeyOperation {
|
|||||||
|
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||||
mCryptoInput.getPassphrase());
|
mCryptoInput.getPassphrase().getCharArray());
|
||||||
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
|
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
|
||||||
PGPSignature sig = generateSubkeyBindingSignature(
|
PGPSignature sig = generateSubkeyBindingSignature(
|
||||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||||
@ -911,17 +912,14 @@ public class PgpKeyOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PGPSecretKey sKey; {
|
PGPSecretKey sKey; {
|
||||||
char[] passphrase = mCryptoInput.getPassphrase();
|
|
||||||
if (passphrase == null) {
|
|
||||||
passphrase = new char[] { };
|
|
||||||
}
|
|
||||||
// Build key encrypter and decrypter based on passphrase
|
// Build key encrypter and decrypter based on passphrase
|
||||||
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
|
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
|
||||||
.build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
|
.build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
|
||||||
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||||
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
||||||
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
|
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||||
|
mCryptoInput.getPassphrase().getCharArray());
|
||||||
|
|
||||||
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
|
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
|
||||||
.build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
|
.build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
|
||||||
@ -1055,7 +1053,7 @@ public class PgpKeyOperation {
|
|||||||
PGPSecretKeyRing sKR,
|
PGPSecretKeyRing sKR,
|
||||||
PGPPublicKey masterPublicKey,
|
PGPPublicKey masterPublicKey,
|
||||||
PGPPrivateKey masterPrivateKey,
|
PGPPrivateKey masterPrivateKey,
|
||||||
char[] passphrase,
|
Passphrase passphrase,
|
||||||
ChangeUnlockParcel newUnlock,
|
ChangeUnlockParcel newUnlock,
|
||||||
OperationLog log, int indent) throws PGPException {
|
OperationLog log, int indent) throws PGPException {
|
||||||
|
|
||||||
@ -1139,20 +1137,19 @@ public class PgpKeyOperation {
|
|||||||
private static PGPSecretKeyRing applyNewPassphrase(
|
private static PGPSecretKeyRing applyNewPassphrase(
|
||||||
PGPSecretKeyRing sKR,
|
PGPSecretKeyRing sKR,
|
||||||
PGPPublicKey masterPublicKey,
|
PGPPublicKey masterPublicKey,
|
||||||
char[] passphrase,
|
Passphrase passphrase,
|
||||||
String newPassphrase,
|
Passphrase newPassphrase,
|
||||||
OperationLog log, int indent) throws PGPException {
|
OperationLog log, int indent) throws PGPException {
|
||||||
|
|
||||||
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
|
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
|
||||||
.get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
|
.get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
|
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
|
||||||
// Build key encryptor based on new passphrase
|
// Build key encryptor based on new passphrase
|
||||||
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
|
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
|
||||||
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
||||||
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
|
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
|
||||||
newPassphrase.toCharArray());
|
|
||||||
|
|
||||||
// noinspection unchecked
|
// noinspection unchecked
|
||||||
for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) {
|
for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) {
|
||||||
|
@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.pgp;
|
|||||||
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -36,12 +37,12 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
protected boolean mEnableAsciiArmorOutput = false;
|
protected boolean mEnableAsciiArmorOutput = false;
|
||||||
protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED;
|
protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED;
|
||||||
protected long[] mEncryptionMasterKeyIds = null;
|
protected long[] mEncryptionMasterKeyIds = null;
|
||||||
protected String mSymmetricPassphrase = null;
|
protected Passphrase mSymmetricPassphrase = null;
|
||||||
protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED;
|
protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED;
|
||||||
protected long mSignatureMasterKeyId = Constants.key.none;
|
protected long mSignatureMasterKeyId = Constants.key.none;
|
||||||
protected Long mSignatureSubKeyId = null;
|
protected Long mSignatureSubKeyId = null;
|
||||||
protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED;
|
protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED;
|
||||||
protected String mSignaturePassphrase = null;
|
protected Passphrase mSignaturePassphrase = null;
|
||||||
protected long mAdditionalEncryptId = Constants.key.none;
|
protected long mAdditionalEncryptId = Constants.key.none;
|
||||||
protected boolean mFailOnMissingEncryptionKeyIds = false;
|
protected boolean mFailOnMissingEncryptionKeyIds = false;
|
||||||
protected String mCharset;
|
protected String mCharset;
|
||||||
@ -56,17 +57,19 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
|
|
||||||
PgpSignEncryptInputParcel(Parcel source) {
|
PgpSignEncryptInputParcel(Parcel source) {
|
||||||
|
|
||||||
|
ClassLoader loader = getClass().getClassLoader();
|
||||||
|
|
||||||
// we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable
|
// we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable
|
||||||
mVersionHeader = source.readString();
|
mVersionHeader = source.readString();
|
||||||
mEnableAsciiArmorOutput = source.readInt() == 1;
|
mEnableAsciiArmorOutput = source.readInt() == 1;
|
||||||
mCompressionId = source.readInt();
|
mCompressionId = source.readInt();
|
||||||
mEncryptionMasterKeyIds = source.createLongArray();
|
mEncryptionMasterKeyIds = source.createLongArray();
|
||||||
mSymmetricPassphrase = source.readString();
|
mSymmetricPassphrase = source.readParcelable(loader);
|
||||||
mSymmetricEncryptionAlgorithm = source.readInt();
|
mSymmetricEncryptionAlgorithm = source.readInt();
|
||||||
mSignatureMasterKeyId = source.readLong();
|
mSignatureMasterKeyId = source.readLong();
|
||||||
mSignatureSubKeyId = source.readInt() == 1 ? source.readLong() : null;
|
mSignatureSubKeyId = source.readInt() == 1 ? source.readLong() : null;
|
||||||
mSignatureHashAlgorithm = source.readInt();
|
mSignatureHashAlgorithm = source.readInt();
|
||||||
mSignaturePassphrase = source.readString();
|
mSignaturePassphrase = source.readParcelable(loader);
|
||||||
mAdditionalEncryptId = source.readLong();
|
mAdditionalEncryptId = source.readLong();
|
||||||
mFailOnMissingEncryptionKeyIds = source.readInt() == 1;
|
mFailOnMissingEncryptionKeyIds = source.readInt() == 1;
|
||||||
mCharset = source.readString();
|
mCharset = source.readString();
|
||||||
@ -74,7 +77,7 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
mDetachedSignature = source.readInt() == 1;
|
mDetachedSignature = source.readInt() == 1;
|
||||||
mHiddenRecipients = source.readInt() == 1;
|
mHiddenRecipients = source.readInt() == 1;
|
||||||
|
|
||||||
mCryptoInput = source.readParcelable(PgpSignEncryptInputParcel.class.getClassLoader());
|
mCryptoInput = source.readParcelable(loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -88,7 +91,7 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0);
|
dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0);
|
||||||
dest.writeInt(mCompressionId);
|
dest.writeInt(mCompressionId);
|
||||||
dest.writeLongArray(mEncryptionMasterKeyIds);
|
dest.writeLongArray(mEncryptionMasterKeyIds);
|
||||||
dest.writeString(mSymmetricPassphrase);
|
dest.writeParcelable(mSymmetricPassphrase, 0);
|
||||||
dest.writeInt(mSymmetricEncryptionAlgorithm);
|
dest.writeInt(mSymmetricEncryptionAlgorithm);
|
||||||
dest.writeLong(mSignatureMasterKeyId);
|
dest.writeLong(mSignatureMasterKeyId);
|
||||||
if (mSignatureSubKeyId != null) {
|
if (mSignatureSubKeyId != null) {
|
||||||
@ -98,7 +101,7 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
dest.writeInt(0);
|
dest.writeInt(0);
|
||||||
}
|
}
|
||||||
dest.writeInt(mSignatureHashAlgorithm);
|
dest.writeInt(mSignatureHashAlgorithm);
|
||||||
dest.writeString(mSignaturePassphrase);
|
dest.writeParcelable(mSignaturePassphrase, 0);
|
||||||
dest.writeLong(mAdditionalEncryptId);
|
dest.writeLong(mAdditionalEncryptId);
|
||||||
dest.writeInt(mFailOnMissingEncryptionKeyIds ? 1 : 0);
|
dest.writeInt(mFailOnMissingEncryptionKeyIds ? 1 : 0);
|
||||||
dest.writeString(mCharset);
|
dest.writeString(mCharset);
|
||||||
@ -130,11 +133,11 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSignaturePassphrase() {
|
public Passphrase getSignaturePassphrase() {
|
||||||
return mSignaturePassphrase;
|
return mSignaturePassphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PgpSignEncryptInputParcel setSignaturePassphrase(String signaturePassphrase) {
|
public PgpSignEncryptInputParcel setSignaturePassphrase(Passphrase signaturePassphrase) {
|
||||||
mSignaturePassphrase = signaturePassphrase;
|
mSignaturePassphrase = signaturePassphrase;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -175,11 +178,11 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSymmetricPassphrase() {
|
public Passphrase getSymmetricPassphrase() {
|
||||||
return mSymmetricPassphrase;
|
return mSymmetricPassphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PgpSignEncryptInputParcel setSymmetricPassphrase(String symmetricPassphrase) {
|
public PgpSignEncryptInputParcel setSymmetricPassphrase(Passphrase symmetricPassphrase) {
|
||||||
mSymmetricPassphrase = symmetricPassphrase;
|
mSymmetricPassphrase = symmetricPassphrase;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
|
|||||||
log.add(LogType.MSG_PSE_SYMMETRIC, indent);
|
log.add(LogType.MSG_PSE_SYMMETRIC, indent);
|
||||||
|
|
||||||
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
|
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
|
||||||
new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().toCharArray());
|
new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().getCharArray());
|
||||||
cPk.addMethod(symmetricEncryptionGenerator);
|
cPk.addMethod(symmetricEncryptionGenerator);
|
||||||
} else {
|
} else {
|
||||||
log.add(LogType.MSG_PSE_ASYMMETRIC, indent);
|
log.add(LogType.MSG_PSE_ASYMMETRIC, indent);
|
||||||
|
@ -21,6 +21,8 @@ package org.sufficientlysecure.keychain.pgp;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
|
|||||||
import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
|
import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -180,7 +181,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, String pin, byte[] hashToSign, int hashAlgo) {
|
private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, Passphrase pin, byte[] hashToSign, int hashAlgo) {
|
||||||
// build PendingIntent for Yubikey NFC operations
|
// build PendingIntent for Yubikey NFC operations
|
||||||
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
|
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
|
||||||
intent.setAction(NfcActivity.ACTION_SIGN_HASH);
|
intent.setAction(NfcActivity.ACTION_SIGN_HASH);
|
||||||
@ -196,7 +197,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, String pin, byte[] encryptedSessionKey) {
|
private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, Passphrase pin, byte[] encryptedSessionKey) {
|
||||||
// build PendingIntent for Yubikey NFC operations
|
// build PendingIntent for Yubikey NFC operations
|
||||||
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
|
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
|
||||||
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
|
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
|
||||||
@ -519,7 +520,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
||||||
}
|
}
|
||||||
|
|
||||||
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
Passphrase passphrase = data.getParcelableExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
long inputLength = is.available();
|
long inputLength = is.available();
|
||||||
InputData inputData = new InputData(is, inputLength);
|
InputData inputData = new InputData(is, inputLength);
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ import org.sufficientlysecure.keychain.util.FileHelper;
|
|||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@ -283,7 +284,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
/* Input */
|
/* Input */
|
||||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE);
|
||||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||||
|
|
||||||
InputData inputData = createDecryptInputData(data);
|
InputData inputData = createDecryptInputData(data);
|
||||||
@ -413,7 +414,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
/* Input */
|
/* Input */
|
||||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE);
|
||||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||||
|
|
||||||
InputData inputData = createDecryptInputData(data);
|
InputData inputData = createDecryptInputData(data);
|
||||||
|
@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
|||||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -121,7 +122,7 @@ public class PassphraseCacheService extends Service {
|
|||||||
* new events to the alarm manager for new passphrases to let them timeout in the future.
|
* new events to the alarm manager for new passphrases to let them timeout in the future.
|
||||||
*/
|
*/
|
||||||
public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId,
|
public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId,
|
||||||
String passphrase,
|
Passphrase passphrase,
|
||||||
String primaryUserId) {
|
String primaryUserId) {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId);
|
Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId);
|
||||||
|
|
||||||
@ -143,7 +144,7 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
* @return passphrase or null (if no passphrase is cached for this keyId)
|
* @return passphrase or null (if no passphrase is cached for this keyId)
|
||||||
*/
|
*/
|
||||||
public static String getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException {
|
public static Passphrase getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() for masterKeyId "
|
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() for masterKeyId "
|
||||||
+ masterKeyId + ", subKeyId " + subKeyId);
|
+ masterKeyId + ", subKeyId " + subKeyId);
|
||||||
|
|
||||||
@ -190,7 +191,9 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
switch (returnMessage.what) {
|
switch (returnMessage.what) {
|
||||||
case MSG_PASSPHRASE_CACHE_GET_OKAY:
|
case MSG_PASSPHRASE_CACHE_GET_OKAY:
|
||||||
return returnMessage.getData().getString(EXTRA_PASSPHRASE);
|
Bundle returnData = returnMessage.getData();
|
||||||
|
returnData.setClassLoader(context.getClassLoader());
|
||||||
|
return returnData.getParcelable(EXTRA_PASSPHRASE);
|
||||||
case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND:
|
case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND:
|
||||||
throw new KeyNotFoundException();
|
throw new KeyNotFoundException();
|
||||||
default:
|
default:
|
||||||
@ -202,11 +205,11 @@ public class PassphraseCacheService extends Service {
|
|||||||
/**
|
/**
|
||||||
* Internal implementation to get cached passphrase.
|
* Internal implementation to get cached passphrase.
|
||||||
*/
|
*/
|
||||||
private String getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException {
|
private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException {
|
||||||
// passphrase for symmetric encryption?
|
// passphrase for symmetric encryption?
|
||||||
if (masterKeyId == Constants.key.symmetric) {
|
if (masterKeyId == Constants.key.symmetric) {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
|
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
|
||||||
String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
|
Passphrase cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
|
||||||
if (cachedPassphrase == null) {
|
if (cachedPassphrase == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -232,13 +235,13 @@ public class PassphraseCacheService extends Service {
|
|||||||
case DIVERT_TO_CARD:
|
case DIVERT_TO_CARD:
|
||||||
if (Preferences.getPreferences(this).useDefaultYubikeyPin()) {
|
if (Preferences.getPreferences(this).useDefaultYubikeyPin()) {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService: Using default Yubikey PIN: 123456");
|
Log.d(Constants.TAG, "PassphraseCacheService: Using default Yubikey PIN: 123456");
|
||||||
return "123456"; // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/
|
return new Passphrase("123456"); // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/
|
||||||
} else {
|
} else {
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService: NOT using default Yubikey PIN");
|
Log.d(Constants.TAG, "PassphraseCacheService: NOT using default Yubikey PIN");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PASSPHRASE_EMPTY:
|
case PASSPHRASE_EMPTY:
|
||||||
return "";
|
return new Passphrase("");
|
||||||
case UNAVAILABLE:
|
case UNAVAILABLE:
|
||||||
throw new ProviderHelper.NotFoundException("secret key for this subkey is not available");
|
throw new ProviderHelper.NotFoundException("secret key for this subkey is not available");
|
||||||
case GNU_DUMMY:
|
case GNU_DUMMY:
|
||||||
@ -331,7 +334,7 @@ public class PassphraseCacheService extends Service {
|
|||||||
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
||||||
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
|
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
|
||||||
|
|
||||||
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
|
Passphrase passphrase = intent.getParcelableExtra(EXTRA_PASSPHRASE);
|
||||||
String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);
|
String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);
|
||||||
|
|
||||||
Log.d(Constants.TAG,
|
Log.d(Constants.TAG,
|
||||||
@ -373,10 +376,10 @@ public class PassphraseCacheService extends Service {
|
|||||||
Log.e(Constants.TAG, "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!");
|
Log.e(Constants.TAG, "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!");
|
||||||
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
|
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
|
||||||
} else {
|
} else {
|
||||||
String passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId);
|
Passphrase passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId);
|
||||||
msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
|
msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putString(EXTRA_PASSPHRASE, passphrase);
|
bundle.putParcelable(EXTRA_PASSPHRASE, passphrase);
|
||||||
msg.setData(bundle);
|
msg.setData(bundle);
|
||||||
}
|
}
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
@ -412,7 +415,10 @@ public class PassphraseCacheService extends Service {
|
|||||||
* Called when one specific passphrase for keyId timed out
|
* Called when one specific passphrase for keyId timed out
|
||||||
*/
|
*/
|
||||||
private void timeout(Context context, long keyId) {
|
private void timeout(Context context, long keyId) {
|
||||||
// remove passphrase corresponding to keyId from memory
|
CachedPassphrase cPass = mPassphraseCache.get(keyId);
|
||||||
|
// clean internal char[] from memory!
|
||||||
|
cPass.getPassphrase().removeFromMemory();
|
||||||
|
// remove passphrase object
|
||||||
mPassphraseCache.remove(keyId);
|
mPassphraseCache.remove(keyId);
|
||||||
|
|
||||||
Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!");
|
Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!");
|
||||||
@ -517,9 +523,9 @@ public class PassphraseCacheService extends Service {
|
|||||||
|
|
||||||
public class CachedPassphrase {
|
public class CachedPassphrase {
|
||||||
private String primaryUserID;
|
private String primaryUserID;
|
||||||
private String passphrase;
|
private Passphrase passphrase;
|
||||||
|
|
||||||
public CachedPassphrase(String passphrase, String primaryUserID) {
|
public CachedPassphrase(Passphrase passphrase, String primaryUserID) {
|
||||||
setPassphrase(passphrase);
|
setPassphrase(passphrase);
|
||||||
setPrimaryUserID(primaryUserID);
|
setPrimaryUserID(primaryUserID);
|
||||||
}
|
}
|
||||||
@ -528,7 +534,7 @@ public class PassphraseCacheService extends Service {
|
|||||||
return primaryUserID;
|
return primaryUserID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPassphrase() {
|
public Passphrase getPassphrase() {
|
||||||
return passphrase;
|
return passphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +542,7 @@ public class PassphraseCacheService extends Service {
|
|||||||
this.primaryUserID = primaryUserID;
|
this.primaryUserID = primaryUserID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPassphrase(String passphrase) {
|
public void setPassphrase(Passphrase passphrase) {
|
||||||
this.passphrase = passphrase;
|
this.passphrase = passphrase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -296,33 +297,30 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
public static class ChangeUnlockParcel implements Parcelable {
|
public static class ChangeUnlockParcel implements Parcelable {
|
||||||
|
|
||||||
// The new passphrase to use
|
// The new passphrase to use
|
||||||
public final String mNewPassphrase;
|
public final Passphrase mNewPassphrase;
|
||||||
// A new pin to use. Must only contain [0-9]+
|
// A new pin to use. Must only contain [0-9]+
|
||||||
public final String mNewPin;
|
public final Passphrase mNewPin;
|
||||||
|
|
||||||
public ChangeUnlockParcel(String newPassphrase) {
|
public ChangeUnlockParcel(Passphrase newPassphrase) {
|
||||||
this(newPassphrase, null);
|
this(newPassphrase, null);
|
||||||
}
|
}
|
||||||
public ChangeUnlockParcel(String newPassphrase, String newPin) {
|
public ChangeUnlockParcel(Passphrase newPassphrase, Passphrase newPin) {
|
||||||
if (newPassphrase == null && newPin == null) {
|
if (newPassphrase == null && newPin == null) {
|
||||||
throw new RuntimeException("Cannot set both passphrase and pin. THIS IS A BUG!");
|
throw new RuntimeException("Cannot set both passphrase and pin. THIS IS A BUG!");
|
||||||
}
|
}
|
||||||
if (newPin != null && !newPin.matches("[0-9]+")) {
|
|
||||||
throw new RuntimeException("Pin must be numeric digits only. THIS IS A BUG!");
|
|
||||||
}
|
|
||||||
mNewPassphrase = newPassphrase;
|
mNewPassphrase = newPassphrase;
|
||||||
mNewPin = newPin;
|
mNewPin = newPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangeUnlockParcel(Parcel source) {
|
public ChangeUnlockParcel(Parcel source) {
|
||||||
mNewPassphrase = source.readString();
|
mNewPassphrase = source.readParcelable(Passphrase.class.getClassLoader());
|
||||||
mNewPin = source.readString();
|
mNewPin = source.readParcelable(Passphrase.class.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel destination, int flags) {
|
public void writeToParcel(Parcel destination, int flags) {
|
||||||
destination.writeString(mNewPassphrase);
|
destination.writeParcelable(mNewPassphrase, flags);
|
||||||
destination.writeString(mNewPin);
|
destination.writeParcelable(mNewPin, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -9,6 +9,8 @@ import java.util.Map;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
|
|
||||||
/** This is a base class for the input of crypto operations.
|
/** This is a base class for the input of crypto operations.
|
||||||
*
|
*
|
||||||
@ -16,13 +18,13 @@ import android.os.Parcelable;
|
|||||||
public class CryptoInputParcel implements Parcelable {
|
public class CryptoInputParcel implements Parcelable {
|
||||||
|
|
||||||
final Date mSignatureTime;
|
final Date mSignatureTime;
|
||||||
final String mPassphrase;
|
final Passphrase mPassphrase;
|
||||||
|
|
||||||
// this map contains both decrypted session keys and signed hashes to be
|
// this map contains both decrypted session keys and signed hashes to be
|
||||||
// used in the crypto operation described by this parcel.
|
// used in the crypto operation described by this parcel.
|
||||||
private HashMap<ByteBuffer,byte[]> mCryptoData = new HashMap<>();
|
private HashMap<ByteBuffer,byte[]> mCryptoData = new HashMap<>();
|
||||||
|
|
||||||
public CryptoInputParcel(Date signatureTime, String passphrase) {
|
public CryptoInputParcel(Date signatureTime, Passphrase passphrase) {
|
||||||
mSignatureTime = signatureTime == null ? new Date() : signatureTime;
|
mSignatureTime = signatureTime == null ? new Date() : signatureTime;
|
||||||
mPassphrase = passphrase;
|
mPassphrase = passphrase;
|
||||||
}
|
}
|
||||||
@ -34,7 +36,7 @@ public class CryptoInputParcel implements Parcelable {
|
|||||||
|
|
||||||
protected CryptoInputParcel(Parcel source) {
|
protected CryptoInputParcel(Parcel source) {
|
||||||
mSignatureTime = new Date(source.readLong());
|
mSignatureTime = new Date(source.readLong());
|
||||||
mPassphrase = source.readString();
|
mPassphrase = source.readParcelable(getClass().getClassLoader());
|
||||||
|
|
||||||
{
|
{
|
||||||
int count = source.readInt();
|
int count = source.readInt();
|
||||||
@ -56,7 +58,7 @@ public class CryptoInputParcel implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeLong(mSignatureTime.getTime());
|
dest.writeLong(mSignatureTime.getTime());
|
||||||
dest.writeString(mPassphrase);
|
dest.writeParcelable(mPassphrase, 0);
|
||||||
|
|
||||||
dest.writeInt(mCryptoData.size());
|
dest.writeInt(mCryptoData.size());
|
||||||
for (HashMap.Entry<ByteBuffer,byte[]> entry : mCryptoData.entrySet()) {
|
for (HashMap.Entry<ByteBuffer,byte[]> entry : mCryptoData.entrySet()) {
|
||||||
@ -81,8 +83,8 @@ public class CryptoInputParcel implements Parcelable {
|
|||||||
return mPassphrase != null;
|
return mPassphrase != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public char[] getPassphrase() {
|
public Passphrase getPassphrase() {
|
||||||
return mPassphrase == null ? null : mPassphrase.toCharArray();
|
return mPassphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<CryptoInputParcel> CREATOR = new Creator<CryptoInputParcel>() {
|
public static final Creator<CryptoInputParcel> CREATOR = new Creator<CryptoInputParcel>() {
|
||||||
|
@ -62,6 +62,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
|
|||||||
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
|
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
|
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -20,31 +20,74 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class CreateKeyActivity extends BaseActivity {
|
public class CreateKeyActivity extends BaseActivity {
|
||||||
|
|
||||||
public static final String EXTRA_NAME = "name";
|
public static final String EXTRA_NAME = "name";
|
||||||
public static final String EXTRA_EMAIL = "email";
|
public static final String EXTRA_EMAIL = "email";
|
||||||
|
public static final String EXTRA_FIRST_TIME = "first_time";
|
||||||
|
public static final String EXTRA_ADDITIONAL_EMAILS = "additional_emails";
|
||||||
|
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||||
|
|
||||||
public static enum FragAction {
|
public static final String FRAGMENT_TAG = "currentFragment";
|
||||||
START,
|
|
||||||
TO_RIGHT,
|
String mName;
|
||||||
TO_LEFT
|
String mEmail;
|
||||||
}
|
ArrayList<String> mAdditionalEmails;
|
||||||
|
Passphrase mPassphrase;
|
||||||
|
boolean mFirstTime;
|
||||||
|
|
||||||
|
Fragment mCurrentFragment;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// pass extras into fragment
|
// Check whether we're recreating a previously destroyed instance
|
||||||
CreateKeyNameFragment frag =
|
if (savedInstanceState != null) {
|
||||||
CreateKeyNameFragment.newInstance(
|
// Restore value of members from saved state
|
||||||
getIntent().getStringExtra(EXTRA_NAME),
|
mName = savedInstanceState.getString(EXTRA_NAME);
|
||||||
getIntent().getStringExtra(EXTRA_EMAIL)
|
mEmail = savedInstanceState.getString(EXTRA_EMAIL);
|
||||||
);
|
mAdditionalEmails = savedInstanceState.getStringArrayList(EXTRA_ADDITIONAL_EMAILS);
|
||||||
loadFragment(null, frag, FragAction.START);
|
mPassphrase = savedInstanceState.getParcelable(EXTRA_PASSPHRASE);
|
||||||
|
mFirstTime = savedInstanceState.getBoolean(EXTRA_FIRST_TIME);
|
||||||
|
|
||||||
|
mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||||
|
} else {
|
||||||
|
// Initialize members with default values for a new instance
|
||||||
|
mName = getIntent().getStringExtra(EXTRA_NAME);
|
||||||
|
mEmail = getIntent().getStringExtra(EXTRA_EMAIL);
|
||||||
|
mFirstTime = getIntent().getBooleanExtra(EXTRA_FIRST_TIME, false);
|
||||||
|
|
||||||
|
// Start with first fragment of wizard
|
||||||
|
CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance();
|
||||||
|
loadFragment(frag, FragAction.START);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFirstTime) {
|
||||||
|
setTitle(R.string.app_name);
|
||||||
|
setActionBarIcon(R.drawable.ic_launcher);
|
||||||
|
mToolbar.setNavigationOnClickListener(null);
|
||||||
|
} else {
|
||||||
|
setTitle(R.string.title_manage_my_keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
|
outState.putString(EXTRA_NAME, mName);
|
||||||
|
outState.putString(EXTRA_EMAIL, mEmail);
|
||||||
|
outState.putStringArrayList(EXTRA_ADDITIONAL_EMAILS, mAdditionalEmails);
|
||||||
|
outState.putParcelable(EXTRA_PASSPHRASE, mPassphrase);
|
||||||
|
outState.putBoolean(EXTRA_FIRST_TIME, mFirstTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -52,23 +95,23 @@ public class CreateKeyActivity extends BaseActivity {
|
|||||||
setContentView(R.layout.create_key_activity);
|
setContentView(R.layout.create_key_activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadFragment(Bundle savedInstanceState, Fragment fragment, FragAction action) {
|
public static enum FragAction {
|
||||||
// However, if we're being restored from a previous state,
|
START,
|
||||||
// then we don't need to do anything and should return or else
|
TO_RIGHT,
|
||||||
// we could end up with overlapping fragments.
|
TO_LEFT
|
||||||
if (savedInstanceState != null) {
|
}
|
||||||
return;
|
|
||||||
}
|
public void loadFragment(Fragment fragment, FragAction action) {
|
||||||
|
mCurrentFragment = fragment;
|
||||||
|
|
||||||
// Add the fragment to the 'fragment_container' FrameLayout
|
// Add the fragment to the 'fragment_container' FrameLayout
|
||||||
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
|
||||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case START:
|
case START:
|
||||||
transaction.setCustomAnimations(0, 0);
|
transaction.setCustomAnimations(0, 0);
|
||||||
transaction.replace(R.id.create_key_fragment_container, fragment)
|
transaction.replace(R.id.create_key_fragment_container, fragment, FRAGMENT_TAG)
|
||||||
.commitAllowingStateLoss();
|
.commit();
|
||||||
break;
|
break;
|
||||||
case TO_LEFT:
|
case TO_LEFT:
|
||||||
getSupportFragmentManager().popBackStackImmediate();
|
getSupportFragmentManager().popBackStackImmediate();
|
||||||
@ -77,8 +120,8 @@ public class CreateKeyActivity extends BaseActivity {
|
|||||||
transaction.setCustomAnimations(R.anim.frag_slide_in_from_right, R.anim.frag_slide_out_to_left,
|
transaction.setCustomAnimations(R.anim.frag_slide_in_from_right, R.anim.frag_slide_out_to_left,
|
||||||
R.anim.frag_slide_in_from_left, R.anim.frag_slide_out_to_right);
|
R.anim.frag_slide_in_from_left, R.anim.frag_slide_out_to_right);
|
||||||
transaction.addToBackStack(null);
|
transaction.addToBackStack(null);
|
||||||
transaction.replace(R.id.create_key_fragment_container, fragment)
|
transaction.replace(R.id.create_key_fragment_container, fragment, FRAGMENT_TAG)
|
||||||
.commitAllowingStateLoss();
|
.commit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,16 +46,12 @@ import java.util.List;
|
|||||||
|
|
||||||
public class CreateKeyEmailFragment extends Fragment {
|
public class CreateKeyEmailFragment extends Fragment {
|
||||||
|
|
||||||
public static final String ARG_NAME = "name";
|
|
||||||
public static final String ARG_EMAIL = "email";
|
|
||||||
|
|
||||||
CreateKeyActivity mCreateKeyActivity;
|
CreateKeyActivity mCreateKeyActivity;
|
||||||
EmailEditText mEmailEdit;
|
EmailEditText mEmailEdit;
|
||||||
RecyclerView mEmailsRecyclerView;
|
RecyclerView mEmailsRecyclerView;
|
||||||
View mBackButton;
|
View mBackButton;
|
||||||
View mNextButton;
|
View mNextButton;
|
||||||
|
|
||||||
String mName;
|
|
||||||
ArrayList<EmailAdapter.ViewModel> mAdditionalEmailModels;
|
ArrayList<EmailAdapter.ViewModel> mAdditionalEmailModels;
|
||||||
|
|
||||||
EmailAdapter mEmailAdapter;
|
EmailAdapter mEmailAdapter;
|
||||||
@ -63,13 +59,10 @@ public class CreateKeyEmailFragment extends Fragment {
|
|||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static CreateKeyEmailFragment newInstance(String name, String email) {
|
public static CreateKeyEmailFragment newInstance() {
|
||||||
CreateKeyEmailFragment frag = new CreateKeyEmailFragment();
|
CreateKeyEmailFragment frag = new CreateKeyEmailFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_NAME, name);
|
|
||||||
args.putString(ARG_EMAIL, email);
|
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
return frag;
|
return frag;
|
||||||
@ -85,7 +78,7 @@ public class CreateKeyEmailFragment extends Fragment {
|
|||||||
*/
|
*/
|
||||||
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
|
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
|
||||||
boolean output = true;
|
boolean output = true;
|
||||||
if (editText.getText().toString().length() == 0) {
|
if (editText.getText().length() == 0) {
|
||||||
editText.setError(context.getString(R.string.create_key_empty));
|
editText.setError(context.getString(R.string.create_key_empty));
|
||||||
editText.requestFocus();
|
editText.requestFocus();
|
||||||
output = false;
|
output = false;
|
||||||
@ -106,31 +99,33 @@ public class CreateKeyEmailFragment extends Fragment {
|
|||||||
mEmailsRecyclerView = (RecyclerView) view.findViewById(R.id.create_key_emails);
|
mEmailsRecyclerView = (RecyclerView) view.findViewById(R.id.create_key_emails);
|
||||||
|
|
||||||
// initial values
|
// initial values
|
||||||
mName = getArguments().getString(ARG_NAME);
|
mEmailEdit.setText(mCreateKeyActivity.mEmail);
|
||||||
String email = getArguments().getString(ARG_EMAIL);
|
|
||||||
mEmailEdit.setText(email);
|
|
||||||
|
|
||||||
// focus empty edit fields
|
// focus empty edit fields
|
||||||
if (email == null) {
|
if (mCreateKeyActivity.mEmail == null) {
|
||||||
mEmailEdit.requestFocus();
|
mEmailEdit.requestFocus();
|
||||||
}
|
}
|
||||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT);
|
mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mNextButton.setOnClickListener(new View.OnClickListener() {
|
mNextButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
createKeyCheck();
|
nextClicked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mEmailsRecyclerView.setHasFixedSize(true);
|
mEmailsRecyclerView.setHasFixedSize(true);
|
||||||
mEmailsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
mEmailsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
mEmailsRecyclerView.setItemAnimator(new DefaultItemAnimator());
|
mEmailsRecyclerView.setItemAnimator(new DefaultItemAnimator());
|
||||||
|
|
||||||
|
// initial values
|
||||||
mAdditionalEmailModels = new ArrayList<>();
|
mAdditionalEmailModels = new ArrayList<>();
|
||||||
|
if (mCreateKeyActivity.mAdditionalEmails != null) {
|
||||||
|
setAdditionalEmails(mCreateKeyActivity.mAdditionalEmails);
|
||||||
|
}
|
||||||
mEmailAdapter = new EmailAdapter(mAdditionalEmailModels, new View.OnClickListener() {
|
mEmailAdapter = new EmailAdapter(mAdditionalEmailModels, new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -171,25 +166,38 @@ public class CreateKeyEmailFragment extends Fragment {
|
|||||||
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createKeyCheck() {
|
private void nextClicked() {
|
||||||
if (isEditTextNotEmpty(getActivity(), mEmailEdit)) {
|
if (isEditTextNotEmpty(getActivity(), mEmailEdit)) {
|
||||||
|
// save state
|
||||||
|
mCreateKeyActivity.mEmail = mEmailEdit.getText().toString();
|
||||||
|
mCreateKeyActivity.mAdditionalEmails = getAdditionalEmails();
|
||||||
|
|
||||||
ArrayList<String> emails = new ArrayList<>();
|
CreateKeyPassphraseFragment frag = CreateKeyPassphraseFragment.newInstance();
|
||||||
for (EmailAdapter.ViewModel holder : mAdditionalEmailModels) {
|
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
|
||||||
emails.add(holder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateKeyPassphraseFragment frag =
|
|
||||||
CreateKeyPassphraseFragment.newInstance(
|
|
||||||
mName,
|
|
||||||
mEmailEdit.getText().toString(),
|
|
||||||
emails
|
|
||||||
);
|
|
||||||
|
|
||||||
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArrayList<String> getAdditionalEmails() {
|
||||||
|
ArrayList<String> emails = new ArrayList<>();
|
||||||
|
for (EmailAdapter.ViewModel holder : mAdditionalEmailModels) {
|
||||||
|
emails.add(holder.toString());
|
||||||
|
}
|
||||||
|
return emails;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAdditionalEmails(ArrayList<String> emails) {
|
||||||
|
for (String email : emails) {
|
||||||
|
mAdditionalEmailModels.add(new EmailAdapter.ViewModel(email));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
// save state in activity
|
||||||
|
mCreateKeyActivity.mAdditionalEmails = getAdditionalEmails();
|
||||||
|
}
|
||||||
|
|
||||||
public static class EmailAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
public static class EmailAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
private List<ViewModel> mDataset;
|
private List<ViewModel> mDataset;
|
||||||
private View.OnClickListener mFooterOnClickListener;
|
private View.OnClickListener mFooterOnClickListener;
|
||||||
|
@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
|||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -64,32 +65,15 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
TextView mEditText;
|
TextView mEditText;
|
||||||
View mEditButton;
|
View mEditButton;
|
||||||
|
|
||||||
public static final String ARG_NAME = "name";
|
|
||||||
public static final String ARG_EMAIL = "email";
|
|
||||||
public static final String ARG_ADDITIONAL_EMAILS = "emails";
|
|
||||||
public static final String ARG_PASSPHRASE = "passphrase";
|
|
||||||
|
|
||||||
String mName;
|
|
||||||
String mEmail;
|
|
||||||
ArrayList<String> mAdditionalEmails;
|
|
||||||
String mPassphrase;
|
|
||||||
|
|
||||||
SaveKeyringParcel mSaveKeyringParcel;
|
SaveKeyringParcel mSaveKeyringParcel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static CreateKeyFinalFragment newInstance(String name, String email,
|
public static CreateKeyFinalFragment newInstance() {
|
||||||
ArrayList<String> additionalEmails,
|
|
||||||
String passphrase) {
|
|
||||||
CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
|
CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_NAME, name);
|
|
||||||
args.putString(ARG_EMAIL, email);
|
|
||||||
args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails);
|
|
||||||
args.putString(ARG_PASSPHRASE, passphrase);
|
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
return frag;
|
return frag;
|
||||||
@ -107,17 +91,11 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
mEditText = (TextView) view.findViewById(R.id.create_key_edit_text);
|
mEditText = (TextView) view.findViewById(R.id.create_key_edit_text);
|
||||||
mEditButton = view.findViewById(R.id.create_key_edit_button);
|
mEditButton = view.findViewById(R.id.create_key_edit_button);
|
||||||
|
|
||||||
// get args
|
|
||||||
mName = getArguments().getString(ARG_NAME);
|
|
||||||
mEmail = getArguments().getString(ARG_EMAIL);
|
|
||||||
mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS);
|
|
||||||
mPassphrase = getArguments().getString(ARG_PASSPHRASE);
|
|
||||||
|
|
||||||
// set values
|
// set values
|
||||||
mNameEdit.setText(mName);
|
mNameEdit.setText(mCreateKeyActivity.mName);
|
||||||
if (mAdditionalEmails != null && mAdditionalEmails.size() > 0) {
|
if (mCreateKeyActivity.mAdditionalEmails != null && mCreateKeyActivity.mAdditionalEmails.size() > 0) {
|
||||||
String emailText = mEmail + ", ";
|
String emailText = mCreateKeyActivity.mEmail + ", ";
|
||||||
Iterator<?> it = mAdditionalEmails.iterator();
|
Iterator<?> it = mCreateKeyActivity.mAdditionalEmails.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Object next = it.next();
|
Object next = it.next();
|
||||||
emailText += next;
|
emailText += next;
|
||||||
@ -127,7 +105,7 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
mEmailEdit.setText(emailText);
|
mEmailEdit.setText(emailText);
|
||||||
} else {
|
} else {
|
||||||
mEmailEdit.setText(mEmail);
|
mEmailEdit.setText(mCreateKeyActivity.mEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCreateButton.setOnClickListener(new View.OnClickListener() {
|
mCreateButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@ -140,7 +118,7 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT);
|
mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -156,6 +134,12 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
@ -186,17 +170,22 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
Algorithm.RSA, 4096, null, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 4096, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
Algorithm.RSA, 4096, null, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
|
Algorithm.RSA, 4096, null, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
|
||||||
String userId = KeyRing.createUserId(new KeyRing.UserId(mName, mEmail, null));
|
String userId = KeyRing.createUserId(
|
||||||
|
new KeyRing.UserId(mCreateKeyActivity.mName, mCreateKeyActivity.mEmail, null)
|
||||||
|
);
|
||||||
mSaveKeyringParcel.mAddUserIds.add(userId);
|
mSaveKeyringParcel.mAddUserIds.add(userId);
|
||||||
mSaveKeyringParcel.mChangePrimaryUserId = userId;
|
mSaveKeyringParcel.mChangePrimaryUserId = userId;
|
||||||
if (mAdditionalEmails != null && mAdditionalEmails.size() > 0) {
|
if (mCreateKeyActivity.mAdditionalEmails != null
|
||||||
for (String email : mAdditionalEmails) {
|
&& mCreateKeyActivity.mAdditionalEmails.size() > 0) {
|
||||||
String thisUserId = KeyRing.createUserId(new KeyRing.UserId(mName, email, null));
|
for (String email : mCreateKeyActivity.mAdditionalEmails) {
|
||||||
|
String thisUserId = KeyRing.createUserId(
|
||||||
|
new KeyRing.UserId(mCreateKeyActivity.mName, email, null)
|
||||||
|
);
|
||||||
mSaveKeyringParcel.mAddUserIds.add(thisUserId);
|
mSaveKeyringParcel.mAddUserIds.add(thisUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mSaveKeyringParcel.mNewUnlock = mPassphrase != null
|
mSaveKeyringParcel.mNewUnlock = mCreateKeyActivity.mPassphrase != null
|
||||||
? new ChangeUnlockParcel(mPassphrase, null)
|
? new ChangeUnlockParcel(mCreateKeyActivity.mPassphrase, null)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,34 +24,26 @@ import android.support.v4.app.Fragment;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
|
|
||||||
import org.sufficientlysecure.keychain.ui.widget.NameEditText;
|
import org.sufficientlysecure.keychain.ui.widget.NameEditText;
|
||||||
|
|
||||||
public class CreateKeyNameFragment extends Fragment {
|
public class CreateKeyNameFragment extends Fragment {
|
||||||
|
|
||||||
public static final String ARG_NAME = "name";
|
|
||||||
public static final String ARG_EMAIL = "email";
|
|
||||||
|
|
||||||
CreateKeyActivity mCreateKeyActivity;
|
CreateKeyActivity mCreateKeyActivity;
|
||||||
NameEditText mNameEdit;
|
NameEditText mNameEdit;
|
||||||
|
View mBackButton;
|
||||||
View mNextButton;
|
View mNextButton;
|
||||||
|
|
||||||
String mEmail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static CreateKeyNameFragment newInstance(String name, String email) {
|
public static CreateKeyNameFragment newInstance() {
|
||||||
CreateKeyNameFragment frag = new CreateKeyNameFragment();
|
CreateKeyNameFragment frag = new CreateKeyNameFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_NAME, name);
|
|
||||||
args.putString(ARG_EMAIL, email);
|
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
@ -68,7 +60,7 @@ public class CreateKeyNameFragment extends Fragment {
|
|||||||
*/
|
*/
|
||||||
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
|
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
|
||||||
boolean output = true;
|
boolean output = true;
|
||||||
if (editText.getText().toString().length() == 0) {
|
if (editText.getText().length() == 0) {
|
||||||
editText.setError(context.getString(R.string.create_key_empty));
|
editText.setError(context.getString(R.string.create_key_empty));
|
||||||
editText.requestFocus();
|
editText.requestFocus();
|
||||||
output = false;
|
output = false;
|
||||||
@ -79,39 +71,31 @@ public class CreateKeyNameFragment extends Fragment {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
|
|
||||||
boolean output = true;
|
|
||||||
if (!editText1.getText().toString().equals(editText2.getText().toString())) {
|
|
||||||
editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
|
|
||||||
editText2.requestFocus();
|
|
||||||
output = false;
|
|
||||||
} else {
|
|
||||||
editText2.setError(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.create_key_name_fragment, container, false);
|
View view = inflater.inflate(R.layout.create_key_name_fragment, container, false);
|
||||||
|
|
||||||
mNameEdit = (NameEditText) view.findViewById(R.id.create_key_name);
|
mNameEdit = (NameEditText) view.findViewById(R.id.create_key_name);
|
||||||
|
mBackButton = view.findViewById(R.id.create_key_back_button);
|
||||||
mNextButton = view.findViewById(R.id.create_key_next_button);
|
mNextButton = view.findViewById(R.id.create_key_next_button);
|
||||||
|
|
||||||
// initial values
|
// initial values
|
||||||
String name = getArguments().getString(ARG_NAME);
|
mNameEdit.setText(mCreateKeyActivity.mName);
|
||||||
mEmail = getArguments().getString(ARG_EMAIL);
|
|
||||||
mNameEdit.setText(name);
|
|
||||||
|
|
||||||
// focus empty edit fields
|
// focus empty edit fields
|
||||||
if (name == null) {
|
if (mCreateKeyActivity.mName == null) {
|
||||||
mNameEdit.requestFocus();
|
mNameEdit.requestFocus();
|
||||||
}
|
}
|
||||||
|
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
|
||||||
|
}
|
||||||
|
});
|
||||||
mNextButton.setOnClickListener(new View.OnClickListener() {
|
mNextButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
createKeyCheck();
|
nextClicked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -124,16 +108,13 @@ public class CreateKeyNameFragment extends Fragment {
|
|||||||
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createKeyCheck() {
|
private void nextClicked() {
|
||||||
if (isEditTextNotEmpty(getActivity(), mNameEdit)) {
|
if (isEditTextNotEmpty(getActivity(), mNameEdit)) {
|
||||||
|
// save state
|
||||||
|
mCreateKeyActivity.mName = mNameEdit.getText().toString();
|
||||||
|
|
||||||
CreateKeyEmailFragment frag =
|
CreateKeyEmailFragment frag = CreateKeyEmailFragment.newInstance();
|
||||||
CreateKeyEmailFragment.newInstance(
|
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
|
||||||
mNameEdit.getText().toString(),
|
|
||||||
mEmail
|
|
||||||
);
|
|
||||||
|
|
||||||
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.text.Editable;
|
||||||
import android.text.method.HideReturnsTransformationMethod;
|
import android.text.method.HideReturnsTransformationMethod;
|
||||||
import android.text.method.PasswordTransformationMethod;
|
import android.text.method.PasswordTransformationMethod;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -34,20 +35,13 @@ import android.widget.EditText;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
|
import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class CreateKeyPassphraseFragment extends Fragment {
|
public class CreateKeyPassphraseFragment extends Fragment {
|
||||||
|
|
||||||
public static final String ARG_NAME = "name";
|
|
||||||
public static final String ARG_EMAIL = "email";
|
|
||||||
public static final String ARG_ADDITIONAL_EMAILS = "emails";
|
|
||||||
|
|
||||||
// model
|
|
||||||
String mName;
|
|
||||||
String mEmail;
|
|
||||||
ArrayList<String> mAdditionalEmails;
|
|
||||||
|
|
||||||
// view
|
// view
|
||||||
CreateKeyActivity mCreateKeyActivity;
|
CreateKeyActivity mCreateKeyActivity;
|
||||||
PassphraseEditText mPassphraseEdit;
|
PassphraseEditText mPassphraseEdit;
|
||||||
@ -59,15 +53,10 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static CreateKeyPassphraseFragment newInstance(String name, String email,
|
public static CreateKeyPassphraseFragment newInstance() {
|
||||||
ArrayList<String> additionalEmails) {
|
|
||||||
CreateKeyPassphraseFragment frag = new CreateKeyPassphraseFragment();
|
CreateKeyPassphraseFragment frag = new CreateKeyPassphraseFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_NAME, name);
|
|
||||||
args.putString(ARG_EMAIL, email);
|
|
||||||
args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails);
|
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
return frag;
|
return frag;
|
||||||
@ -83,7 +72,7 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
*/
|
*/
|
||||||
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
|
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
|
||||||
boolean output = true;
|
boolean output = true;
|
||||||
if (editText.getText().toString().length() == 0) {
|
if (editText.getText().length() == 0) {
|
||||||
editText.setError(context.getString(R.string.create_key_empty));
|
editText.setError(context.getString(R.string.create_key_empty));
|
||||||
editText.requestFocus();
|
editText.requestFocus();
|
||||||
output = false;
|
output = false;
|
||||||
@ -95,11 +84,13 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
|
private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
|
||||||
boolean output = true;
|
Passphrase p1 = new Passphrase(editText1);
|
||||||
if (!editText1.getText().toString().equals(editText2.getText().toString())) {
|
Passphrase p2 = new Passphrase(editText2);
|
||||||
|
boolean output = (p1.equals(p2));
|
||||||
|
|
||||||
|
if (!output) {
|
||||||
editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
|
editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
|
||||||
editText2.requestFocus();
|
editText2.requestFocus();
|
||||||
output = false;
|
|
||||||
} else {
|
} else {
|
||||||
editText2.setError(null);
|
editText2.setError(null);
|
||||||
}
|
}
|
||||||
@ -118,9 +109,12 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
mNextButton = view.findViewById(R.id.create_key_next_button);
|
mNextButton = view.findViewById(R.id.create_key_next_button);
|
||||||
|
|
||||||
// initial values
|
// initial values
|
||||||
mName = getArguments().getString(ARG_NAME);
|
// TODO: using String here is unsafe...
|
||||||
mEmail = getArguments().getString(ARG_EMAIL);
|
if (mCreateKeyActivity.mPassphrase != null) {
|
||||||
mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS);
|
mPassphraseEdit.setText(Arrays.toString(mCreateKeyActivity.mPassphrase.getCharArray()));
|
||||||
|
mPassphraseEditAgain.setText(Arrays.toString(mCreateKeyActivity.mPassphrase.getCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
mPassphraseEdit.requestFocus();
|
mPassphraseEdit.requestFocus();
|
||||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -131,7 +125,7 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
mNextButton.setOnClickListener(new View.OnClickListener() {
|
mNextButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
createKeyCheck();
|
nextClicked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mShowPassphrase.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
mShowPassphrase.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
@ -159,23 +153,19 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
|
|
||||||
private void back() {
|
private void back() {
|
||||||
hideKeyboard();
|
hideKeyboard();
|
||||||
mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT);
|
mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createKeyCheck() {
|
private void nextClicked() {
|
||||||
if (isEditTextNotEmpty(getActivity(), mPassphraseEdit)
|
if (isEditTextNotEmpty(getActivity(), mPassphraseEdit)
|
||||||
&& areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) {
|
&& areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) {
|
||||||
|
|
||||||
CreateKeyFinalFragment frag =
|
// save state
|
||||||
CreateKeyFinalFragment.newInstance(
|
mCreateKeyActivity.mPassphrase = new Passphrase(mPassphraseEdit);
|
||||||
mName,
|
|
||||||
mEmail,
|
|
||||||
mAdditionalEmails,
|
|
||||||
mPassphraseEdit.getText().toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance();
|
||||||
hideKeyboard();
|
hideKeyboard();
|
||||||
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
|
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.widget.DefaultItemAnimator;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.AddEmailDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CreateKeyStartFragment extends Fragment {
|
||||||
|
|
||||||
|
CreateKeyActivity mCreateKeyActivity;
|
||||||
|
|
||||||
|
View mCreateKey;
|
||||||
|
View mImportKey;
|
||||||
|
View mYubiKey;
|
||||||
|
TextView mCancel;
|
||||||
|
public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new instance of this fragment
|
||||||
|
*/
|
||||||
|
public static CreateKeyStartFragment newInstance() {
|
||||||
|
CreateKeyStartFragment frag = new CreateKeyStartFragment();
|
||||||
|
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
|
||||||
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.create_key_start_fragment, container, false);
|
||||||
|
|
||||||
|
mCreateKey = view.findViewById(R.id.create_key_create_key_button);
|
||||||
|
mImportKey = view.findViewById(R.id.create_key_import_button);
|
||||||
|
// mYubiKey = view.findViewById(R.id.create_key_yubikey_button);
|
||||||
|
mCancel = (TextView) view.findViewById(R.id.create_key_cancel);
|
||||||
|
|
||||||
|
if (mCreateKeyActivity.mFirstTime) {
|
||||||
|
mCancel.setText(R.string.first_time_skip);
|
||||||
|
} else {
|
||||||
|
mCancel.setText(R.string.btn_do_not_save);
|
||||||
|
}
|
||||||
|
|
||||||
|
mCreateKey.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
CreateKeyNameFragment frag = CreateKeyNameFragment.newInstance();
|
||||||
|
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mImportKey.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent(mCreateKeyActivity, ImportKeysActivity.class);
|
||||||
|
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mCancel.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
finishSetup(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void finishSetup(Intent srcData) {
|
||||||
|
if (mCreateKeyActivity.mFirstTime) {
|
||||||
|
Preferences prefs = Preferences.getPreferences(mCreateKeyActivity);
|
||||||
|
prefs.setFirstTime(false);
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(mCreateKeyActivity, MainActivity.class);
|
||||||
|
// give intent through to display notify
|
||||||
|
if (srcData != null) {
|
||||||
|
intent.putExtras(srcData);
|
||||||
|
}
|
||||||
|
startActivity(intent);
|
||||||
|
mCreateKeyActivity.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for https://code.google.com/p/android/issues/detail?id=61394
|
||||||
|
// @Override
|
||||||
|
// public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
|
// return keyCode == KeyEvent.KEYCODE_MENU || super.onKeyDown(keyCode, event);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (requestCode == REQUEST_CODE_CREATE_OR_IMPORT_KEY) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
finishSetup(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(Constants.TAG, "No valid request code!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -191,7 +191,7 @@ public class DecryptFilesFragment extends DecryptFragment {
|
|||||||
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
||||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
||||||
|
|
||||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
||||||
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
@ -265,7 +265,7 @@ public class DecryptFilesFragment extends DecryptFragment {
|
|||||||
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
||||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
||||||
|
|
||||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
||||||
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
@ -341,7 +341,7 @@ public class DecryptFilesFragment extends DecryptFragment {
|
|||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_CODE_PASSPHRASE: {
|
case REQUEST_CODE_PASSPHRASE: {
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||||
mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
|
mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
|
||||||
decryptOriginalFilename();
|
decryptOriginalFilename();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
public abstract class DecryptFragment extends Fragment {
|
public abstract class DecryptFragment extends Fragment {
|
||||||
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
|
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
|
||||||
@ -57,7 +58,7 @@ public abstract class DecryptFragment extends Fragment {
|
|||||||
|
|
||||||
|
|
||||||
// State
|
// State
|
||||||
protected String mPassphrase;
|
protected Passphrase mPassphrase;
|
||||||
protected byte[] mNfcDecryptedSessionKey;
|
protected byte[] mNfcDecryptedSessionKey;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -100,7 +101,7 @@ public abstract class DecryptFragment extends Fragment {
|
|||||||
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
|
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void startNfcDecrypt(long subKeyId, String pin, byte[] encryptedSessionKey) {
|
protected void startNfcDecrypt(long subKeyId, Passphrase pin, byte[] encryptedSessionKey) {
|
||||||
// build PendingIntent for Yubikey NFC operations
|
// build PendingIntent for Yubikey NFC operations
|
||||||
Intent intent = new Intent(getActivity(), NfcActivity.class);
|
Intent intent = new Intent(getActivity(), NfcActivity.class);
|
||||||
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
|
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
|
||||||
|
@ -161,7 +161,7 @@ public class DecryptTextFragment extends DecryptFragment {
|
|||||||
// data
|
// data
|
||||||
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
|
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
||||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
||||||
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
@ -247,7 +247,7 @@ public class DecryptTextFragment extends DecryptFragment {
|
|||||||
|
|
||||||
case REQUEST_CODE_PASSPHRASE: {
|
case REQUEST_CODE_PASSPHRASE: {
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||||
mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
|
mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
|
||||||
decryptStart();
|
decryptStart();
|
||||||
} else {
|
} else {
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
|
@ -69,6 +69,8 @@ import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment;
|
|||||||
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
|
|
||||||
public class EditKeyFragment extends CryptoOperationFragment implements
|
public class EditKeyFragment extends CryptoOperationFragment implements
|
||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
@ -337,7 +339,7 @@ public class EditKeyFragment extends CryptoOperationFragment implements
|
|||||||
|
|
||||||
// cache new returned passphrase!
|
// cache new returned passphrase!
|
||||||
mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(
|
mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(
|
||||||
data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE),
|
(Passphrase) data.getParcelable(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
|||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
|
|
||||||
public abstract class EncryptActivity extends BaseActivity {
|
public abstract class EncryptActivity extends BaseActivity {
|
||||||
@ -41,7 +42,7 @@ public abstract class EncryptActivity extends BaseActivity {
|
|||||||
public static final int REQUEST_CODE_NFC = 0x00008002;
|
public static final int REQUEST_CODE_NFC = 0x00008002;
|
||||||
|
|
||||||
// For NFC data
|
// For NFC data
|
||||||
protected String mSigningKeyPassphrase = null;
|
protected Passphrase mSigningKeyPassphrase = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@ -76,7 +77,7 @@ public abstract class EncryptActivity extends BaseActivity {
|
|||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_CODE_PASSPHRASE: {
|
case REQUEST_CODE_PASSPHRASE: {
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
mSigningKeyPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
|
mSigningKeyPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
|
||||||
startEncrypt();
|
startEncrypt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public interface EncryptActivityInterface {
|
public interface EncryptActivityInterface {
|
||||||
@ -39,7 +41,7 @@ public interface EncryptActivityInterface {
|
|||||||
public void setEncryptionKeys(long[] encryptionKeys);
|
public void setEncryptionKeys(long[] encryptionKeys);
|
||||||
public void setEncryptionUsers(String[] encryptionUsers);
|
public void setEncryptionUsers(String[] encryptionUsers);
|
||||||
|
|
||||||
public void setPassphrase(String passphrase);
|
public void setPassphrase(Passphrase passphrase);
|
||||||
|
|
||||||
// ArrayList on purpose as only those are parcelable
|
// ArrayList on purpose as only those are parcelable
|
||||||
public ArrayList<Uri> getInputUris();
|
public ArrayList<Uri> getInputUris();
|
||||||
|
@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
|||||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ShareHelper;
|
import org.sufficientlysecure.keychain.util.ShareHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -72,7 +73,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
|
|||||||
private long mEncryptionKeyIds[] = null;
|
private long mEncryptionKeyIds[] = null;
|
||||||
private String mEncryptionUserIds[] = null;
|
private String mEncryptionUserIds[] = null;
|
||||||
private long mSigningKeyId = Constants.key.none;
|
private long mSigningKeyId = Constants.key.none;
|
||||||
private String mPassphrase = "";
|
private Passphrase mPassphrase = new Passphrase();
|
||||||
|
|
||||||
private ArrayList<Uri> mInputUris;
|
private ArrayList<Uri> mInputUris;
|
||||||
private ArrayList<Uri> mOutputUris;
|
private ArrayList<Uri> mOutputUris;
|
||||||
@ -136,7 +137,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPassphrase(String passphrase) {
|
public void setPassphrase(Passphrase passphrase) {
|
||||||
mPassphrase = passphrase;
|
mPassphrase = passphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,8 +244,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
|
|||||||
|
|
||||||
if (isModeSymmetric()) {
|
if (isModeSymmetric()) {
|
||||||
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||||
String passphrase = mPassphrase;
|
Passphrase passphrase = mPassphrase;
|
||||||
if (passphrase.length() == 0) {
|
if (passphrase.isEmpty()) {
|
||||||
passphrase = null;
|
passphrase = null;
|
||||||
}
|
}
|
||||||
data.setSymmetricPassphrase(passphrase);
|
data.setSymmetricPassphrase(passphrase);
|
||||||
|
@ -28,6 +28,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
|
public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
|
||||||
|
|
||||||
@ -67,8 +68,13 @@ public class EncryptSymmetricFragment extends Fragment implements EncryptActivit
|
|||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
// update passphrase in EncryptActivity
|
// update passphrase in EncryptActivity
|
||||||
if (mPassphrase.getText().toString().equals(mPassphraseAgain.getText().toString())) {
|
Passphrase p1 = new Passphrase(mPassphrase.getText());
|
||||||
mEncryptInterface.setPassphrase(s.toString());
|
Passphrase p2 = new Passphrase(mPassphraseAgain.getText());
|
||||||
|
boolean passesEquals = (p1.equals(p2));
|
||||||
|
p1.removeFromMemory();
|
||||||
|
p2.removeFromMemory();
|
||||||
|
if (passesEquals) {
|
||||||
|
mEncryptInterface.setPassphrase(new Passphrase(mPassphrase.getText()));
|
||||||
} else {
|
} else {
|
||||||
mEncryptInterface.setPassphrase(null);
|
mEncryptInterface.setPassphrase(null);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.PgpConstants;
|
|||||||
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ShareHelper;
|
import org.sufficientlysecure.keychain.util.ShareHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -70,7 +71,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
|
|||||||
private String mEncryptionUserIds[] = null;
|
private String mEncryptionUserIds[] = null;
|
||||||
// TODO Constants.key.none? What's wrong with a null value?
|
// TODO Constants.key.none? What's wrong with a null value?
|
||||||
private long mSigningKeyId = Constants.key.none;
|
private long mSigningKeyId = Constants.key.none;
|
||||||
private String mPassphrase = "";
|
private Passphrase mPassphrase = new Passphrase();
|
||||||
|
|
||||||
private ArrayList<Uri> mInputUris;
|
private ArrayList<Uri> mInputUris;
|
||||||
private ArrayList<Uri> mOutputUris;
|
private ArrayList<Uri> mOutputUris;
|
||||||
@ -134,7 +135,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPassphrase(String passphrase) {
|
public void setPassphrase(Passphrase passphrase) {
|
||||||
|
mPassphrase.removeFromMemory();
|
||||||
mPassphrase = passphrase;
|
mPassphrase = passphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,8 +225,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
|
|||||||
|
|
||||||
if (isModeSymmetric()) {
|
if (isModeSymmetric()) {
|
||||||
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||||
String passphrase = mPassphrase;
|
Passphrase passphrase = mPassphrase;
|
||||||
if (passphrase.length() == 0) {
|
if (passphrase.isEmpty()) {
|
||||||
passphrase = null;
|
passphrase = null;
|
||||||
}
|
}
|
||||||
data.setSymmetricPassphrase(passphrase);
|
data.setSymmetricPassphrase(passphrase);
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Window;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
|
||||||
|
|
||||||
public class FirstTimeActivity extends BaseActivity {
|
|
||||||
|
|
||||||
View mCreateKey;
|
|
||||||
View mImportKey;
|
|
||||||
View mSkipSetup;
|
|
||||||
|
|
||||||
public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
mCreateKey = findViewById(R.id.first_time_create_key);
|
|
||||||
mImportKey = findViewById(R.id.first_time_import_key);
|
|
||||||
mSkipSetup = findViewById(R.id.first_time_cancel);
|
|
||||||
|
|
||||||
mSkipSetup.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
finishSetup(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mImportKey.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent intent = new Intent(FirstTimeActivity.this, ImportKeysActivity.class);
|
|
||||||
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
|
|
||||||
startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mCreateKey.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent intent = new Intent(FirstTimeActivity.this, CreateKeyActivity.class);
|
|
||||||
startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void initLayout() {
|
|
||||||
setContentView(R.layout.first_time_activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
|
|
||||||
if (requestCode == REQUEST_CODE_CREATE_OR_IMPORT_KEY) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
finishSetup(data);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(Constants.TAG, "No valid request code!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishSetup(Intent srcData) {
|
|
||||||
Preferences prefs = Preferences.getPreferences(this);
|
|
||||||
prefs.setFirstTime(false);
|
|
||||||
Intent intent = new Intent(this, MainActivity.class);
|
|
||||||
// give intent through to display notify
|
|
||||||
if (srcData != null) {
|
|
||||||
intent.putExtras(srcData);
|
|
||||||
}
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
// workaround for https://code.google.com/p/android/issues/detail?id=61394
|
|
||||||
@Override
|
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
||||||
return keyCode == KeyEvent.KEYCODE_MENU || super.onKeyDown(keyCode, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -489,7 +489,8 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
case R.id.menu_key_list_debug_first_time:
|
case R.id.menu_key_list_debug_first_time:
|
||||||
Preferences prefs = Preferences.getPreferences(getActivity());
|
Preferences prefs = Preferences.getPreferences(getActivity());
|
||||||
prefs.setFirstTime(true);
|
prefs.setFirstTime(true);
|
||||||
Intent intent = new Intent(getActivity(), FirstTimeActivity.class);
|
Intent intent = new Intent(getActivity(), CreateKeyActivity.class);
|
||||||
|
intent.putExtra(CreateKeyActivity.EXTRA_FIRST_TIME, true);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,7 +54,9 @@ public class MainActivity extends MaterialNavigationDrawer implements FabContain
|
|||||||
// if this is the first time show first time activity
|
// if this is the first time show first time activity
|
||||||
Preferences prefs = Preferences.getPreferences(this);
|
Preferences prefs = Preferences.getPreferences(this);
|
||||||
if (prefs.isFirstTime()) {
|
if (prefs.isFirstTime()) {
|
||||||
startActivity(new Intent(this, FirstTimeActivity.class));
|
Intent intent = new Intent(this, CreateKeyActivity.class);
|
||||||
|
intent.putExtra(CreateKeyActivity.EXTRA_FIRST_TIME, true);
|
||||||
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
|||||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
|
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,7 +334,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
positive.setOnClickListener(new View.OnClickListener() {
|
positive.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
final String passphrase = mPassphraseEditText.getText().toString();
|
final Passphrase passphrase = new Passphrase(mPassphraseEditText);
|
||||||
|
|
||||||
// Early breakout if we are dealing with a symmetric key
|
// Early breakout if we are dealing with a symmetric key
|
||||||
if (mSecretRing == null) {
|
if (mSecretRing == null) {
|
||||||
@ -410,7 +411,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishCaching(String passphrase) {
|
private void finishCaching(Passphrase passphrase) {
|
||||||
// any indication this isn't needed anymore, don't do it.
|
// any indication this isn't needed anymore, don't do it.
|
||||||
if (mIsCancelled || getActivity() == null) {
|
if (mIsCancelled || getActivity() == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -21,18 +21,12 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import android.animation.ArgbEvaluator;
|
import android.animation.ArgbEvaluator;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.nfc.NdefMessage;
|
|
||||||
import android.nfc.NdefRecord;
|
|
||||||
import android.nfc.NfcAdapter;
|
|
||||||
import android.nfc.NfcEvent;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -40,7 +34,6 @@ import android.os.Handler;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
@ -58,9 +51,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.getbase.floatingactionbutton.FloatingActionButton;
|
import com.getbase.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
@ -74,6 +65,8 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
|
||||||
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
@ -82,6 +75,7 @@ import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
|||||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.NfcHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -91,8 +85,8 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
|
|
||||||
static final int REQUEST_QR_FINGERPRINT = 1;
|
static final int REQUEST_QR_FINGERPRINT = 1;
|
||||||
static final int REQUEST_DELETE= 2;
|
static final int REQUEST_DELETE = 2;
|
||||||
static final int REQUEST_EXPORT= 3;
|
static final int REQUEST_EXPORT = 3;
|
||||||
|
|
||||||
ExportHelper mExportHelper;
|
ExportHelper mExportHelper;
|
||||||
ProviderHelper mProviderHelper;
|
ProviderHelper mProviderHelper;
|
||||||
@ -113,11 +107,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
private CardView mQrCodeLayout;
|
private CardView mQrCodeLayout;
|
||||||
|
|
||||||
// NFC
|
// NFC
|
||||||
private NfcAdapter mNfcAdapter;
|
private NfcHelper mNfcHelper;
|
||||||
private NfcAdapter.CreateNdefMessageCallback mNdefCallback;
|
|
||||||
private NfcAdapter.OnNdefPushCompleteCallback mNdefCompleteCallback;
|
|
||||||
private byte[] mNfcKeyringBytes;
|
|
||||||
private static final int NFC_SENT = 1;
|
|
||||||
|
|
||||||
private static final int LOADER_ID_UNIFIED = 0;
|
private static final int LOADER_ID_UNIFIED = 0;
|
||||||
|
|
||||||
@ -254,7 +244,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
mActionNfc.setOnClickListener(new View.OnClickListener() {
|
mActionNfc.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
invokeNfcBeam();
|
mNfcHelper.invokeNfcBeam();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -262,7 +252,8 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
// or start new ones.
|
// or start new ones.
|
||||||
getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
||||||
|
|
||||||
initNfc(mDataUri);
|
mNfcHelper = new NfcHelper(this, mProviderHelper);
|
||||||
|
mNfcHelper.initNfc(mDataUri);
|
||||||
|
|
||||||
startFragment(savedInstanceState, mDataUri);
|
startFragment(savedInstanceState, mDataUri);
|
||||||
}
|
}
|
||||||
@ -310,31 +301,31 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_view_export_file: {
|
case R.id.menu_key_view_export_file: {
|
||||||
Intent mIntent = new Intent(this,PassphraseDialogActivity.class);
|
|
||||||
long keyId=0;
|
|
||||||
try {
|
try {
|
||||||
keyId = new ProviderHelper(this)
|
if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) {
|
||||||
.getCachedPublicKeyRing(mDataUri)
|
exportToFile(mDataUri, mExportHelper, mProviderHelper);
|
||||||
.extractOrGetMasterKeyId();
|
return true;
|
||||||
} catch (PgpKeyNotFoundException e) {
|
}
|
||||||
e.printStackTrace();
|
|
||||||
|
startPassphraseActivity(REQUEST_EXPORT);
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
// This happens when the master key is stripped
|
||||||
|
exportToFile(mDataUri, mExportHelper, mProviderHelper);
|
||||||
}
|
}
|
||||||
mIntent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID,keyId);
|
|
||||||
startActivityForResult(mIntent,REQUEST_EXPORT);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_view_delete: {
|
case R.id.menu_key_view_delete: {
|
||||||
Intent mIntent = new Intent(this,PassphraseDialogActivity.class);
|
|
||||||
long keyId=0;
|
|
||||||
try {
|
try {
|
||||||
keyId = new ProviderHelper(this)
|
if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) {
|
||||||
.getCachedPublicKeyRing(mDataUri)
|
deleteKey();
|
||||||
.extractOrGetMasterKeyId();
|
return true;
|
||||||
} catch (PgpKeyNotFoundException e) {
|
}
|
||||||
e.printStackTrace();
|
|
||||||
|
startPassphraseActivity(REQUEST_DELETE);
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
// This happens when the master key is stripped
|
||||||
|
deleteKey();
|
||||||
}
|
}
|
||||||
mIntent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID,keyId);
|
|
||||||
startActivityForResult(mIntent,REQUEST_DELETE);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_view_advanced: {
|
case R.id.menu_key_view_advanced: {
|
||||||
@ -373,41 +364,6 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
private void invokeNfcBeam() {
|
|
||||||
// Check if device supports NFC
|
|
||||||
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
|
|
||||||
Notify.createNotify(this, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check for available NFC Adapter
|
|
||||||
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
|
||||||
if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) {
|
|
||||||
Notify.createNotify(this, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void onAction() {
|
|
||||||
Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS);
|
|
||||||
startActivity(intentSettings);
|
|
||||||
}
|
|
||||||
}, R.string.menu_nfc_preferences).show();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mNfcAdapter.isNdefPushEnabled()) {
|
|
||||||
Notify.createNotify(this, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void onAction() {
|
|
||||||
Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS);
|
|
||||||
startActivity(intentSettings);
|
|
||||||
}
|
|
||||||
}, R.string.menu_beam_preferences).show();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mNfcAdapter.invokeBeam(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scanQrCode() {
|
private void scanQrCode() {
|
||||||
Intent scanQrCode = new Intent(this, ImportKeysProxyActivity.class);
|
Intent scanQrCode = new Intent(this, ImportKeysProxyActivity.class);
|
||||||
@ -424,7 +380,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
|
|
||||||
private void certifyImmediate() {
|
private void certifyImmediate() {
|
||||||
Intent intent = new Intent(this, CertifyKeyActivity.class);
|
Intent intent = new Intent(this, CertifyKeyActivity.class);
|
||||||
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId});
|
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[] {mMasterKeyId});
|
||||||
|
|
||||||
startCertifyIntent(intent);
|
startCertifyIntent(intent);
|
||||||
}
|
}
|
||||||
@ -473,22 +429,32 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
ActivityCompat.startActivity(this, qrCodeIntent, opts);
|
ActivityCompat.startActivity(this, qrCodeIntent, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper)
|
private void startPassphraseActivity(int requestCode) {
|
||||||
throws ProviderHelper.NotFoundException {
|
Intent intent = new Intent(this, PassphraseDialogActivity.class);
|
||||||
Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri);
|
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mMasterKeyId);
|
||||||
|
startActivityForResult(intent, requestCode);
|
||||||
HashMap<String, Object> data = providerHelper.getGenericData(
|
|
||||||
baseUri,
|
|
||||||
new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET},
|
|
||||||
new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER});
|
|
||||||
|
|
||||||
exportHelper.showExportKeysDialog(
|
|
||||||
new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
|
|
||||||
Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteKey(Uri dataUri, ExportHelper exportHelper) {
|
private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) {
|
||||||
|
try {
|
||||||
|
Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri);
|
||||||
|
|
||||||
|
HashMap<String, Object> data = providerHelper.getGenericData(
|
||||||
|
baseUri,
|
||||||
|
new String[] {KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET},
|
||||||
|
new int[] {ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER});
|
||||||
|
|
||||||
|
exportHelper.showExportKeysDialog(
|
||||||
|
new long[] {(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
|
||||||
|
Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)
|
||||||
|
);
|
||||||
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
|
Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
|
||||||
|
Log.e(Constants.TAG, "Key not found", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteKey() {
|
||||||
// Message is received after key is deleted
|
// Message is received after key is deleted
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
@ -500,7 +466,11 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exportHelper.deleteKey(dataUri, returnHandler);
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(returnHandler);
|
||||||
|
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
|
||||||
|
new long[] {mMasterKeyId});
|
||||||
|
deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -530,18 +500,13 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK){
|
if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) {
|
||||||
deleteKey(mDataUri, mExportHelper);
|
deleteKey();
|
||||||
}
|
|
||||||
if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK){
|
|
||||||
try {
|
|
||||||
exportToFile(mDataUri, mExportHelper, mProviderHelper);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
|
|
||||||
Log.e(Constants.TAG, "Key not found", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) {
|
||||||
|
exportToFile(mDataUri, mExportHelper, mProviderHelper);
|
||||||
|
}
|
||||||
|
|
||||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||||
@ -561,7 +526,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
long keyId = new ProviderHelper(this)
|
long keyId = new ProviderHelper(this)
|
||||||
.getCachedPublicKeyRing(dataUri)
|
.getCachedPublicKeyRing(dataUri)
|
||||||
.extractOrGetMasterKeyId();
|
.extractOrGetMasterKeyId();
|
||||||
long[] encryptionKeyIds = new long[]{keyId};
|
long[] encryptionKeyIds = new long[] {keyId};
|
||||||
Intent intent;
|
Intent intent;
|
||||||
if (text) {
|
if (text) {
|
||||||
intent = new Intent(this, EncryptTextActivity.class);
|
intent = new Intent(this, EncryptTextActivity.class);
|
||||||
@ -699,98 +664,9 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
loadTask.execute();
|
loadTask.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* NFC: Initialize NFC sharing if OS and device supports it
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
|
||||||
private void initNfc(final Uri dataUri) {
|
|
||||||
// check if NFC Beam is supported (>= Android 4.1)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
||||||
|
|
||||||
// Implementation for the CreateNdefMessageCallback interface
|
|
||||||
mNdefCallback = new NfcAdapter.CreateNdefMessageCallback() {
|
|
||||||
@Override
|
|
||||||
public NdefMessage createNdefMessage(NfcEvent event) {
|
|
||||||
/*
|
|
||||||
* When a device receives a push with an AAR in it, the application specified in the AAR is
|
|
||||||
* guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to
|
|
||||||
* guarantee that this activity starts when receiving a beamed message. For now, this code
|
|
||||||
* uses the tag dispatch system.
|
|
||||||
*/
|
|
||||||
return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
|
|
||||||
mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implementation for the OnNdefPushCompleteCallback interface
|
|
||||||
mNdefCompleteCallback = new NfcAdapter.OnNdefPushCompleteCallback() {
|
|
||||||
@Override
|
|
||||||
public void onNdefPushComplete(NfcEvent event) {
|
|
||||||
// A handler is needed to send messages to the activity when this
|
|
||||||
// callback occurs, because it happens from a binder thread
|
|
||||||
mNfcHandler.obtainMessage(NFC_SENT).sendToTarget();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check for available NFC Adapter
|
|
||||||
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
|
||||||
if (mNfcAdapter != null) {
|
|
||||||
/*
|
|
||||||
* Retrieve mNfcKeyringBytes here asynchronously (to not block the UI)
|
|
||||||
* and init nfc adapter afterwards.
|
|
||||||
* mNfcKeyringBytes can not be retrieved in createNdefMessage, because this process
|
|
||||||
* has no permissions to query the Uri.
|
|
||||||
*/
|
|
||||||
AsyncTask<Void, Void, Void> initTask =
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
|
||||||
protected Void doInBackground(Void... unused) {
|
|
||||||
try {
|
|
||||||
Uri blobUri =
|
|
||||||
KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
|
|
||||||
mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData(
|
|
||||||
blobUri,
|
|
||||||
KeychainContract.KeyRingData.KEY_RING_DATA,
|
|
||||||
ProviderHelper.FIELD_TYPE_BLOB);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
Log.e(Constants.TAG, "key not found!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// no AsyncTask return (Void)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPostExecute(Void unused) {
|
|
||||||
// Register callback to set NDEF message
|
|
||||||
mNfcAdapter.setNdefPushMessageCallback(mNdefCallback,
|
|
||||||
ViewKeyActivity.this);
|
|
||||||
// Register callback to listen for message-sent success
|
|
||||||
mNfcAdapter.setOnNdefPushCompleteCallback(mNdefCompleteCallback,
|
|
||||||
ViewKeyActivity.this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
initTask.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NFC: This handler receives a message from onNdefPushComplete
|
|
||||||
*/
|
|
||||||
private final Handler mNfcHandler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
switch (msg.what) {
|
|
||||||
case NFC_SENT:
|
|
||||||
Notify.showNotify(
|
|
||||||
ViewKeyActivity.this, R.string.nfc_successful, Notify.Style.INFO);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// These are the rows that we will retrieve.
|
// These are the rows that we will retrieve.
|
||||||
static final String[] PROJECTION = new String[]{
|
static final String[] PROJECTION = new String[] {
|
||||||
KeychainContract.KeyRings._ID,
|
KeychainContract.KeyRings._ID,
|
||||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||||
KeychainContract.KeyRings.USER_ID,
|
KeychainContract.KeyRings.USER_ID,
|
||||||
@ -1007,4 +883,4 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
public void onLoaderReset(Loader<Cursor> loader) {
|
public void onLoaderReset(Loader<Cursor> loader) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.NfcHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -68,10 +69,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
private View mFingerprintClipboardButton;
|
private View mFingerprintClipboardButton;
|
||||||
private View mKeyShareButton;
|
private View mKeyShareButton;
|
||||||
private View mKeyClipboardButton;
|
private View mKeyClipboardButton;
|
||||||
|
private View mKeyNfcButton;
|
||||||
private ImageButton mKeySafeSlingerButton;
|
private ImageButton mKeySafeSlingerButton;
|
||||||
private View mKeyUploadButton;
|
private View mKeyUploadButton;
|
||||||
|
|
||||||
ProviderHelper mProviderHelper;
|
ProviderHelper mProviderHelper;
|
||||||
|
NfcHelper mNfcHelper;
|
||||||
|
|
||||||
private static final int LOADER_ID_UNIFIED = 0;
|
private static final int LOADER_ID_UNIFIED = 0;
|
||||||
|
|
||||||
@ -83,6 +86,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer());
|
View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer());
|
||||||
|
|
||||||
mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity());
|
mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity());
|
||||||
|
mNfcHelper = new NfcHelper(getActivity(), mProviderHelper);
|
||||||
|
|
||||||
mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint);
|
mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint);
|
||||||
mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code);
|
mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code);
|
||||||
@ -90,6 +94,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
|
mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
|
||||||
mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
|
mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
|
||||||
mKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
|
mKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
|
||||||
|
mKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
|
||||||
mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
|
mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
|
||||||
mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
|
mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
|
||||||
mKeyUploadButton = view.findViewById(R.id.view_key_action_upload);
|
mKeyUploadButton = view.findViewById(R.id.view_key_action_upload);
|
||||||
@ -128,6 +133,14 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
share(mDataUri, mProviderHelper, false, true);
|
share(mDataUri, mProviderHelper, false, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mKeyNfcButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
mNfcHelper.invokeNfcBeam();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() {
|
mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -255,9 +268,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
// Prepare the loaders. Either re-connect with an existing ones,
|
// Prepare the loaders. Either re-connect with an existing ones,
|
||||||
// or start new ones.
|
// or start new ones.
|
||||||
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
||||||
|
|
||||||
|
// Prepare the NfcHelper
|
||||||
|
mNfcHelper.initNfc(mDataUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String[] UNIFIED_PROJECTION = new String[]{
|
static final String[] UNIFIED_PROJECTION = new String[] {
|
||||||
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
|
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
|
||||||
KeyRings.USER_ID, KeyRings.FINGERPRINT,
|
KeyRings.USER_ID, KeyRings.FINGERPRINT,
|
||||||
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED,
|
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED,
|
||||||
@ -362,4 +378,5 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
startActivityForResult(uploadIntent, 0);
|
startActivityForResult(uploadIntent, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
}
|
@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
|
import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
|
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
|
||||||
private static final String ARG_MESSENGER = "messenger";
|
private static final String ARG_MESSENGER = "messenger";
|
||||||
@ -113,12 +114,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
|||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
dismiss();
|
dismiss();
|
||||||
|
|
||||||
String passphrase1;
|
Passphrase passphrase1 = new Passphrase();
|
||||||
if (mNoPassphraseCheckBox.isChecked()) {
|
if (mNoPassphraseCheckBox.isChecked()) {
|
||||||
passphrase1 = "";
|
passphrase1.setEmpty();
|
||||||
} else {
|
} else {
|
||||||
passphrase1 = mPassphraseEditText.getText().toString();
|
passphrase1 = new Passphrase(mPassphraseEditText);
|
||||||
String passphrase2 = mPassphraseAgainEditText.getText().toString();
|
Passphrase passphrase2 = new Passphrase(mPassphraseAgainEditText);
|
||||||
if (!passphrase1.equals(passphrase2)) {
|
if (!passphrase1.equals(passphrase2)) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
activity,
|
activity,
|
||||||
@ -129,7 +130,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passphrase1.equals("")) {
|
if (passphrase1.isEmpty()) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
activity,
|
activity,
|
||||||
getString(R.string.error_message,
|
getString(R.string.error_message,
|
||||||
@ -142,7 +143,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
|||||||
|
|
||||||
// return resulting data back to activity
|
// return resulting data back to activity
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1);
|
data.putParcelable(MESSAGE_NEW_PASSPHRASE, passphrase1);
|
||||||
|
|
||||||
sendMessageToHandler(MESSAGE_OKAY, data);
|
sendMessageToHandler(MESSAGE_OKAY, data);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,11 @@ package org.sufficientlysecure.keychain.ui.util;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.nispok.snackbar.Snackbar;
|
import com.nispok.snackbar.Snackbar;
|
||||||
import com.nispok.snackbar.Snackbar.SnackbarDuration;
|
import com.nispok.snackbar.Snackbar.SnackbarDuration;
|
||||||
@ -61,11 +66,11 @@ public class Notify {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SnackbarManager.show(bar);
|
showSnackbar(activity, bar);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Showable createNotify (Activity activity, int resId, int duration, Style style) {
|
public static Showable createNotify (final Activity activity, int resId, int duration, Style style) {
|
||||||
final Snackbar bar = getSnackbar(activity)
|
final Snackbar bar = getSnackbar(activity)
|
||||||
.text(resId);
|
.text(resId);
|
||||||
|
|
||||||
@ -90,7 +95,7 @@ public class Notify {
|
|||||||
return new Showable () {
|
return new Showable () {
|
||||||
@Override
|
@Override
|
||||||
public void show() {
|
public void show() {
|
||||||
SnackbarManager.show(bar);
|
showSnackbar(activity, bar);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -104,7 +109,7 @@ public class Notify {
|
|||||||
return createNotify(activity, msg, duration, style, null, 0);
|
return createNotify(activity, msg, duration, style, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Showable createNotify(Activity activity, String msg, int duration, Style style,
|
public static Showable createNotify(final Activity activity, String msg, int duration, Style style,
|
||||||
final ActionListener listener, int resIdAction) {
|
final ActionListener listener, int resIdAction) {
|
||||||
|
|
||||||
final Snackbar bar = getSnackbar(activity)
|
final Snackbar bar = getSnackbar(activity)
|
||||||
@ -141,7 +146,7 @@ public class Notify {
|
|||||||
return new Showable () {
|
return new Showable () {
|
||||||
@Override
|
@Override
|
||||||
public void show() {
|
public void show() {
|
||||||
SnackbarManager.show(bar);
|
showSnackbar(activity, bar);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,6 +183,26 @@ public class Notify {
|
|||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void showSnackbar(Activity activity, Snackbar snackbar) {
|
||||||
|
if (activity instanceof FragmentActivity) {
|
||||||
|
FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager();
|
||||||
|
|
||||||
|
int count = fragmentManager.getBackStackEntryCount();
|
||||||
|
Fragment fragment = fragmentManager.getFragments().get(count > 0 ? count - 1 : 0);
|
||||||
|
|
||||||
|
if (fragment != null) {
|
||||||
|
View view = fragment.getView();
|
||||||
|
|
||||||
|
if (view != null) {
|
||||||
|
SnackbarManager.show(snackbar, (ViewGroup) view);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SnackbarManager.show(snackbar);
|
||||||
|
}
|
||||||
|
|
||||||
public interface Showable {
|
public interface Showable {
|
||||||
public void show();
|
public void show();
|
||||||
|
|
||||||
|
@ -58,9 +58,10 @@ public class EmailEditText extends AutoCompleteTextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
|
setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
|
||||||
this.addTextChangedListener(textWatcher);
|
reenableKeyboardSuggestions();
|
||||||
removeFlag();
|
|
||||||
|
addTextChangedListener(textWatcher);
|
||||||
initAdapter();
|
initAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ public class EmailEditText extends AutoCompleteTextView {
|
|||||||
* Hack to re-enable keyboard auto correction in AutoCompleteTextView.
|
* Hack to re-enable keyboard auto correction in AutoCompleteTextView.
|
||||||
* From http://stackoverflow.com/a/22512858
|
* From http://stackoverflow.com/a/22512858
|
||||||
*/
|
*/
|
||||||
private void removeFlag() {
|
private void reenableKeyboardSuggestions() {
|
||||||
int inputType = getInputType();
|
int inputType = getInputType();
|
||||||
inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
|
inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
|
||||||
setRawInputType(inputType);
|
setRawInputType(inputType);
|
||||||
|
@ -50,7 +50,7 @@ public class NameEditText extends AutoCompleteTextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
removeFlag();
|
reenableKeyboardSuggestions();
|
||||||
initAdapter();
|
initAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,10 +62,10 @@ public class NameEditText extends AutoCompleteTextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hack to re-enable keyboard auto correction in AutoCompleteTextView.
|
* Hack to re-enable keyboard suggestions in AutoCompleteTextView.
|
||||||
* From http://stackoverflow.com/a/22512858
|
* From http://stackoverflow.com/a/22512858
|
||||||
*/
|
*/
|
||||||
private void removeFlag() {
|
private void reenableKeyboardSuggestions() {
|
||||||
int inputType = getInputType();
|
int inputType = getInputType();
|
||||||
inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
|
inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
|
||||||
setRawInputType(inputType);
|
setRawInputType(inputType);
|
||||||
|
@ -47,21 +47,6 @@ public class ExportHelper {
|
|||||||
this.mActivity = activity;
|
this.mActivity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteKey(Uri dataUri, Handler deleteHandler) {
|
|
||||||
try {
|
|
||||||
long masterKeyId = new ProviderHelper(mActivity).getCachedPublicKeyRing(dataUri)
|
|
||||||
.extractOrGetMasterKeyId();
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(deleteHandler);
|
|
||||||
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
|
|
||||||
new long[]{ masterKeyId });
|
|
||||||
deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog");
|
|
||||||
} catch (PgpKeyNotFoundException e) {
|
|
||||||
Log.e(Constants.TAG, "key not found!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show dialog where to export keys
|
* Show dialog where to export keys
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Kent Nguyen <kentnguyen@moneylover.me>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.nfc.NdefMessage;
|
||||||
|
import android.nfc.NdefRecord;
|
||||||
|
import android.nfc.NfcAdapter;
|
||||||
|
import android.nfc.NfcEvent;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class contains NFC functionality that can be shared across Fragments or Activities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class NfcHelper {
|
||||||
|
|
||||||
|
private Activity mActivity;
|
||||||
|
private ProviderHelper mProviderHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NFC: This handler receives a message from onNdefPushComplete
|
||||||
|
*/
|
||||||
|
private static NfcHandler mNfcHandler;
|
||||||
|
|
||||||
|
private NfcAdapter mNfcAdapter;
|
||||||
|
private NfcAdapter.CreateNdefMessageCallback mNdefCallback;
|
||||||
|
private NfcAdapter.OnNdefPushCompleteCallback mNdefCompleteCallback;
|
||||||
|
private byte[] mNfcKeyringBytes;
|
||||||
|
private static final int NFC_SENT = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the NfcHelper.
|
||||||
|
*/
|
||||||
|
public NfcHelper(final Activity activity, final ProviderHelper providerHelper) {
|
||||||
|
mActivity = activity;
|
||||||
|
mProviderHelper = providerHelper;
|
||||||
|
|
||||||
|
mNfcHandler = new NfcHandler(mActivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the NFC Adapter of this Helper has any features enabled.
|
||||||
|
*
|
||||||
|
* @return true if this NFC Adapter has any features enabled
|
||||||
|
*/
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return mNfcAdapter.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NFC: Initialize NFC sharing if OS and device supports it
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
public void initNfc(final Uri dataUri) {
|
||||||
|
// check if NFC Beam is supported (>= Android 4.1)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
|
|
||||||
|
// Implementation for the CreateNdefMessageCallback interface
|
||||||
|
mNdefCallback = new NfcAdapter.CreateNdefMessageCallback() {
|
||||||
|
@Override
|
||||||
|
public NdefMessage createNdefMessage(NfcEvent event) {
|
||||||
|
/*
|
||||||
|
* When a device receives a push with an AAR in it, the application specified in the AAR is
|
||||||
|
* guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to
|
||||||
|
* guarantee that this activity starts when receiving a beamed message. For now, this code
|
||||||
|
* uses the tag dispatch system.
|
||||||
|
*/
|
||||||
|
return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
|
||||||
|
mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation for the OnNdefPushCompleteCallback interface
|
||||||
|
mNdefCompleteCallback = new NfcAdapter.OnNdefPushCompleteCallback() {
|
||||||
|
@Override
|
||||||
|
public void onNdefPushComplete(NfcEvent event) {
|
||||||
|
// A handler is needed to send messages to the activity when this
|
||||||
|
// callback occurs, because it happens from a binder thread
|
||||||
|
mNfcHandler.obtainMessage(NFC_SENT).sendToTarget();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for available NFC Adapter
|
||||||
|
mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity);
|
||||||
|
if (mNfcAdapter != null) {
|
||||||
|
/*
|
||||||
|
* Retrieve mNfcKeyringBytes here asynchronously (to not block the UI)
|
||||||
|
* and init nfc adapter afterwards.
|
||||||
|
* mNfcKeyringBytes can not be retrieved in createNdefMessage, because this process
|
||||||
|
* has no permissions to query the Uri.
|
||||||
|
*/
|
||||||
|
AsyncTask<Void, Void, Void> initTask =
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
protected Void doInBackground(Void... unused) {
|
||||||
|
try {
|
||||||
|
Uri blobUri =
|
||||||
|
KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
|
||||||
|
mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData(
|
||||||
|
blobUri,
|
||||||
|
KeychainContract.KeyRingData.KEY_RING_DATA,
|
||||||
|
ProviderHelper.FIELD_TYPE_BLOB);
|
||||||
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
|
Log.e(Constants.TAG, "key not found!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no AsyncTask return (Void)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(Void unused) {
|
||||||
|
// Register callback to set NDEF message
|
||||||
|
mNfcAdapter.setNdefPushMessageCallback(mNdefCallback,
|
||||||
|
mActivity);
|
||||||
|
// Register callback to listen for message-sent success
|
||||||
|
mNfcAdapter.setOnNdefPushCompleteCallback(mNdefCompleteCallback,
|
||||||
|
mActivity);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
initTask.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public void invokeNfcBeam() {
|
||||||
|
// Check if device supports NFC
|
||||||
|
if (!mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
|
||||||
|
Notify.createNotify(mActivity, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check for available NFC Adapter
|
||||||
|
mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity);
|
||||||
|
if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) {
|
||||||
|
Notify.createNotify(mActivity, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onAction() {
|
||||||
|
Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS);
|
||||||
|
mActivity.startActivity(intentSettings);
|
||||||
|
}
|
||||||
|
}, R.string.menu_nfc_preferences).show();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mNfcAdapter.isNdefPushEnabled()) {
|
||||||
|
Notify.createNotify(mActivity, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onAction() {
|
||||||
|
Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS);
|
||||||
|
mActivity.startActivity(intentSettings);
|
||||||
|
}
|
||||||
|
}, R.string.menu_beam_preferences).show();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mNfcAdapter.invokeBeam(mActivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static subclass of {@link Handler} with a {@link WeakReference} to an {@link Activity} to avoid memory leaks.
|
||||||
|
*/
|
||||||
|
private static class NfcHandler extends Handler {
|
||||||
|
private final WeakReference<Activity> mActivityReference;
|
||||||
|
|
||||||
|
public NfcHandler(Activity activity) {
|
||||||
|
mActivityReference = new WeakReference<>(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
Activity activity = mActivityReference.get();
|
||||||
|
|
||||||
|
if (activity != null) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case NFC_SENT:
|
||||||
|
Notify.showNotify(
|
||||||
|
activity, R.string.nfc_successful, Notify.Style.INFO);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Passwords should not be stored as Strings in memory.
|
||||||
|
* This class wraps a char[] that can be erased after it is no longer used.
|
||||||
|
* See also:
|
||||||
|
* <p/>
|
||||||
|
* http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#PBEEx
|
||||||
|
* https://github.com/c-a-m/passfault/blob/master/core/src/main/java/org/owasp/passfault/SecureString.java
|
||||||
|
* http://stackoverflow.com/q/8881291
|
||||||
|
* http://stackoverflow.com/a/15844273
|
||||||
|
*/
|
||||||
|
public class Passphrase implements Parcelable {
|
||||||
|
private char[] mPassphrase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* According to http://stackoverflow.com/a/15844273 EditText is not using String internally
|
||||||
|
* but char[]. Thus, we can get the char[] directly from it.
|
||||||
|
*/
|
||||||
|
public Passphrase(Editable editable) {
|
||||||
|
int pl = editable.length();
|
||||||
|
mPassphrase = new char[pl];
|
||||||
|
editable.getChars(0, pl, mPassphrase, 0);
|
||||||
|
// TODO: clean up internal char[] of EditText after getting the passphrase?
|
||||||
|
// editText.getText().replace()
|
||||||
|
}
|
||||||
|
|
||||||
|
public Passphrase(EditText editText) {
|
||||||
|
this(editText.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Passphrase(char[] passphrase) {
|
||||||
|
mPassphrase = passphrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Passphrase(String passphrase) {
|
||||||
|
mPassphrase = passphrase.toCharArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a passphrase object with an empty ("") passphrase
|
||||||
|
*/
|
||||||
|
public Passphrase() {
|
||||||
|
setEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getCharArray() {
|
||||||
|
return mPassphrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmpty() {
|
||||||
|
removeFromMemory();
|
||||||
|
mPassphrase = new char[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return (length() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int length() {
|
||||||
|
return mPassphrase.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char charAt(int index) {
|
||||||
|
return mPassphrase[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually clear the underlying array holding the characters
|
||||||
|
*/
|
||||||
|
public void removeFromMemory() {
|
||||||
|
if (mPassphrase != null) {
|
||||||
|
Arrays.fill(mPassphrase, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finalize() throws Throwable {
|
||||||
|
removeFromMemory();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (Constants.DEBUG) {
|
||||||
|
return "Passphrase{" +
|
||||||
|
"mPassphrase=" + Arrays.toString(mPassphrase) +
|
||||||
|
'}';
|
||||||
|
} else {
|
||||||
|
return "Passphrase: hidden";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Passphrase that = (Passphrase) o;
|
||||||
|
if (!Arrays.equals(mPassphrase, that.mPassphrase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mPassphrase != null ? Arrays.hashCode(mPassphrase) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Passphrase(Parcel source) {
|
||||||
|
mPassphrase = source.createCharArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeCharArray(mPassphrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<Passphrase> CREATOR = new Creator<Passphrase>() {
|
||||||
|
public Passphrase createFromParcel(final Parcel source) {
|
||||||
|
return new Passphrase(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Passphrase[] newArray(final int size) {
|
||||||
|
return new Passphrase[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_nfc_grey_24dp.png
Normal file
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_nfc_grey_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
OpenKeychain/src/main/res/drawable-mdpi/ic_nfc_grey_24dp.png
Normal file
BIN
OpenKeychain/src/main/res/drawable-mdpi/ic_nfc_grey_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 701 B |
BIN
OpenKeychain/src/main/res/drawable-xhdpi/ic_nfc_grey_24dp.png
Normal file
BIN
OpenKeychain/src/main/res/drawable-xhdpi/ic_nfc_grey_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
OpenKeychain/src/main/res/drawable-xxhdpi/ic_nfc_grey_24dp.png
Normal file
BIN
OpenKeychain/src/main/res/drawable-xxhdpi/ic_nfc_grey_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
OpenKeychain/src/main/res/drawable-xxxhdpi/ic_nfc_grey_24dp.png
Normal file
BIN
OpenKeychain/src/main/res/drawable-xxxhdpi/ic_nfc_grey_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
@ -56,11 +56,13 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:text="@string/btn_back"
|
||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
|
||||||
android:drawablePadding="8dp"
|
android:drawablePadding="8dp"
|
||||||
android:gravity="left|center_vertical"
|
android:gravity="left|center_vertical"
|
||||||
android:clickable="false"
|
android:clickable="true"
|
||||||
style="?android:attr/borderlessButtonStyle" />
|
style="?android:attr/borderlessButtonStyle" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
104
OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
Normal file
104
OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_above="@+id/create_key_buttons">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:src="@drawable/first_time_1"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:background="@color/holo_gray_bright"
|
||||||
|
android:id="@+id/create_key_buttons">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/create_key_create_key_button"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/first_time_create_key"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:gravity="right|center_vertical"
|
||||||
|
android:clickable="true"
|
||||||
|
style="?android:attr/borderlessButtonStyle" />
|
||||||
|
|
||||||
|
<!--<TextView-->
|
||||||
|
<!--android:id="@+id/create_key_yubikey_button"-->
|
||||||
|
<!--android:paddingLeft="16dp"-->
|
||||||
|
<!--android:paddingRight="16dp"-->
|
||||||
|
<!--android:textAppearance="?android:attr/textAppearanceMedium"-->
|
||||||
|
<!--android:layout_width="match_parent"-->
|
||||||
|
<!--android:layout_height="wrap_content"-->
|
||||||
|
<!--android:layout_weight="1"-->
|
||||||
|
<!--android:text="@string/first_time_yubikey"-->
|
||||||
|
<!--android:textAllCaps="true"-->
|
||||||
|
<!--android:minHeight="?android:attr/listPreferredItemHeight"-->
|
||||||
|
<!--android:drawableRight="@drawable/ic_chevron_right_grey_24dp"-->
|
||||||
|
<!--android:drawablePadding="8dp"-->
|
||||||
|
<!--android:gravity="right|center_vertical"-->
|
||||||
|
<!--android:clickable="true"-->
|
||||||
|
<!--style="?android:attr/borderlessButtonStyle" />-->
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/create_key_import_button"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/first_time_import_key"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:gravity="right|center_vertical"
|
||||||
|
android:clickable="true"
|
||||||
|
style="?android:attr/borderlessButtonStyle" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/create_key_cancel"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/btn_do_not_save"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:drawableRight="@drawable/ic_close_grey_24dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:gravity="right|center_vertical"
|
||||||
|
android:clickable="true"
|
||||||
|
style="?android:attr/borderlessButtonStyle" />
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
@ -1,137 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingTop="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/status_bar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/statusbar_height" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/first_time_buttons"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:paddingRight="16dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dip"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/first_time_import_key"
|
|
||||||
android:paddingLeft="8dp"
|
|
||||||
android:paddingRight="8dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/first_time_import_key"
|
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
|
||||||
android:drawableRight="@drawable/ic_folder_grey_24dp"
|
|
||||||
android:drawablePadding="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:clickable="true"
|
|
||||||
android:background="?android:selectableItemBackground" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="1dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/first_time_create_key"
|
|
||||||
android:paddingLeft="8dp"
|
|
||||||
android:paddingRight="8dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/first_time_create_key"
|
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
|
||||||
android:drawableRight="@drawable/ic_key_plus_grey600_24dp"
|
|
||||||
android:drawablePadding="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:clickable="true"
|
|
||||||
android:background="?android:selectableItemBackground" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dip"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/first_time_cancel"
|
|
||||||
android:paddingLeft="8dp"
|
|
||||||
android:paddingRight="8dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/first_time_skip"
|
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
|
||||||
android:gravity="center"
|
|
||||||
android:clickable="true"
|
|
||||||
android:background="?android:selectableItemBackground"
|
|
||||||
android:layout_gravity="center_horizontal" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_below="@+id/status_bar"
|
|
||||||
android:layout_above="@+id/first_time_buttons">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
|
||||||
android:text="@string/app_name"
|
|
||||||
android:drawableLeft="@drawable/ic_launcher"
|
|
||||||
android:drawablePadding="8dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_gravity="center_horizontal" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:src="@drawable/first_time_1"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="64dp"
|
|
||||||
android:layout_marginRight="64dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:text="@string/first_time_text1"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:layout_marginBottom="16dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -99,14 +99,12 @@
|
|||||||
android:layout_weight="1" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/view_key_action_key_share"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||||
android:clickable="true"
|
|
||||||
android:background="?android:selectableItemBackground"
|
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/view_key_action_key_share"
|
||||||
android:paddingLeft="8dp"
|
android:paddingLeft="8dp"
|
||||||
android:paddingRight="8dp"
|
android:paddingRight="8dp"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
@ -116,7 +114,25 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:drawableRight="@drawable/ic_share_grey_24dp"
|
android:drawableRight="@drawable/ic_share_grey_24dp"
|
||||||
android:drawablePadding="8dp"
|
android:drawablePadding="8dp"
|
||||||
android:gravity="center_vertical" />
|
android:gravity="center_vertical"
|
||||||
|
android:background="?android:selectableItemBackground"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dip"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="right"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/view_key_action_key_nfc"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_nfc_grey_24dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="?android:selectableItemBackground" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="1dip"
|
android:layout_width="1dip"
|
||||||
@ -154,6 +170,7 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dip"
|
android:layout_height="1dip"
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_key_list_create"
|
android:id="@+id/menu_key_list_create"
|
||||||
android:title="@string/menu_create_key"
|
android:title="@string/menu_manage_keys"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
<string name="menu_help">Nápověda</string>
|
<string name="menu_help">Nápověda</string>
|
||||||
<string name="menu_export_key">Exportovat do souboru</string>
|
<string name="menu_export_key">Exportovat do souboru</string>
|
||||||
<string name="menu_delete_key">Smazat klíč</string>
|
<string name="menu_delete_key">Smazat klíč</string>
|
||||||
<string name="menu_create_key">Vytvořit moje klíče</string>
|
<string name="menu_manage_keys">Vytvořit moje klíče</string>
|
||||||
<string name="menu_import_existing_key">Importovat ze souboru</string>
|
<string name="menu_import_existing_key">Importovat ze souboru</string>
|
||||||
<string name="menu_search">Hledat</string>
|
<string name="menu_search">Hledat</string>
|
||||||
<string name="menu_beam_preferences">Beam settings</string>
|
<string name="menu_beam_preferences">Beam settings</string>
|
||||||
|
@ -88,7 +88,7 @@
|
|||||||
<string name="menu_help">Hilfe</string>
|
<string name="menu_help">Hilfe</string>
|
||||||
<string name="menu_export_key">In Datei exportieren</string>
|
<string name="menu_export_key">In Datei exportieren</string>
|
||||||
<string name="menu_delete_key">Schlüssel löschen</string>
|
<string name="menu_delete_key">Schlüssel löschen</string>
|
||||||
<string name="menu_create_key">Erzeuge meinen Schlüssel</string>
|
<string name="menu_manage_keys">Erzeuge meinen Schlüssel</string>
|
||||||
<string name="menu_import_existing_key">Von Datei importieren</string>
|
<string name="menu_import_existing_key">Von Datei importieren</string>
|
||||||
<string name="menu_search">Suchen</string>
|
<string name="menu_search">Suchen</string>
|
||||||
<string name="menu_nfc_preferences">NFC-Einstellungen</string>
|
<string name="menu_nfc_preferences">NFC-Einstellungen</string>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<string name="menu_help">Ayuda</string>
|
<string name="menu_help">Ayuda</string>
|
||||||
<string name="menu_export_key">Exportar hacia archivo</string>
|
<string name="menu_export_key">Exportar hacia archivo</string>
|
||||||
<string name="menu_delete_key">Borrar clave</string>
|
<string name="menu_delete_key">Borrar clave</string>
|
||||||
<string name="menu_create_key">Crear mi clave</string>
|
<string name="menu_manage_keys">Crear mi clave</string>
|
||||||
<string name="menu_import_existing_key">Importar desde fichero</string>
|
<string name="menu_import_existing_key">Importar desde fichero</string>
|
||||||
<string name="menu_search">Buscar</string>
|
<string name="menu_search">Buscar</string>
|
||||||
<string name="menu_nfc_preferences">Configuraciones NFC</string>
|
<string name="menu_nfc_preferences">Configuraciones NFC</string>
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
<string name="menu_help">Laguntza</string>
|
<string name="menu_help">Laguntza</string>
|
||||||
<string name="menu_export_key">Esportatu agirira</string>
|
<string name="menu_export_key">Esportatu agirira</string>
|
||||||
<string name="menu_delete_key">Ezabatu giltza</string>
|
<string name="menu_delete_key">Ezabatu giltza</string>
|
||||||
<string name="menu_create_key">Sortu nire giltza</string>
|
<string name="menu_manage_keys">Sortu nire giltza</string>
|
||||||
<string name="menu_import_existing_key">inportatu agiritik</string>
|
<string name="menu_import_existing_key">inportatu agiritik</string>
|
||||||
<string name="menu_search">Bilatu</string>
|
<string name="menu_search">Bilatu</string>
|
||||||
<string name="menu_nfc_preferences">NFC ezarpenak</string>
|
<string name="menu_nfc_preferences">NFC ezarpenak</string>
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<string name="menu_help">Apua</string>
|
<string name="menu_help">Apua</string>
|
||||||
<string name="menu_export_key">Vie tiedostoon</string>
|
<string name="menu_export_key">Vie tiedostoon</string>
|
||||||
<string name="menu_delete_key">Poista avain</string>
|
<string name="menu_delete_key">Poista avain</string>
|
||||||
<string name="menu_create_key">Luo minun avaimeni</string>
|
<string name="menu_manage_keys">Luo minun avaimeni</string>
|
||||||
<string name="menu_import_existing_key">Tuo tiedostosta</string>
|
<string name="menu_import_existing_key">Tuo tiedostosta</string>
|
||||||
<string name="menu_search">Etsi</string>
|
<string name="menu_search">Etsi</string>
|
||||||
<string name="menu_beam_preferences">Beam asetukset</string>
|
<string name="menu_beam_preferences">Beam asetukset</string>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<string name="menu_help">Aide</string>
|
<string name="menu_help">Aide</string>
|
||||||
<string name="menu_export_key">Exporter vers un fichier</string>
|
<string name="menu_export_key">Exporter vers un fichier</string>
|
||||||
<string name="menu_delete_key">Supprimer la clef</string>
|
<string name="menu_delete_key">Supprimer la clef</string>
|
||||||
<string name="menu_create_key">Créer ma clef</string>
|
<string name="menu_manage_keys">Créer ma clef</string>
|
||||||
<string name="menu_import_existing_key">Importer depuis un fichier</string>
|
<string name="menu_import_existing_key">Importer depuis un fichier</string>
|
||||||
<string name="menu_search">Rechercher</string>
|
<string name="menu_search">Rechercher</string>
|
||||||
<string name="menu_nfc_preferences">Paramètres NFC</string>
|
<string name="menu_nfc_preferences">Paramètres NFC</string>
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
<string name="menu_help">Aiuto</string>
|
<string name="menu_help">Aiuto</string>
|
||||||
<string name="menu_export_key">Esporta su un file</string>
|
<string name="menu_export_key">Esporta su un file</string>
|
||||||
<string name="menu_delete_key">Cancella chiave</string>
|
<string name="menu_delete_key">Cancella chiave</string>
|
||||||
<string name="menu_create_key">Crea mia chiave</string>
|
<string name="menu_manage_keys">Crea mia chiave</string>
|
||||||
<string name="menu_import_existing_key">Importa da file</string>
|
<string name="menu_import_existing_key">Importa da file</string>
|
||||||
<string name="menu_search">Cerca</string>
|
<string name="menu_search">Cerca</string>
|
||||||
<string name="menu_beam_preferences">Impostazioni Beam</string>
|
<string name="menu_beam_preferences">Impostazioni Beam</string>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<string name="menu_help">ヘルプ</string>
|
<string name="menu_help">ヘルプ</string>
|
||||||
<string name="menu_export_key">ファイルへのエクスポート</string>
|
<string name="menu_export_key">ファイルへのエクスポート</string>
|
||||||
<string name="menu_delete_key">鍵の削除</string>
|
<string name="menu_delete_key">鍵の削除</string>
|
||||||
<string name="menu_create_key">自分の鍵の生成</string>
|
<string name="menu_manage_keys">自分の鍵の生成</string>
|
||||||
<string name="menu_import_existing_key">ファイルからインポート</string>
|
<string name="menu_import_existing_key">ファイルからインポート</string>
|
||||||
<string name="menu_search">検索</string>
|
<string name="menu_search">検索</string>
|
||||||
<string name="menu_nfc_preferences">NFC設定</string>
|
<string name="menu_nfc_preferences">NFC設定</string>
|
||||||
|
@ -96,7 +96,7 @@
|
|||||||
<string name="menu_help">Help</string>
|
<string name="menu_help">Help</string>
|
||||||
<string name="menu_export_key">Exporteren naar bestand</string>
|
<string name="menu_export_key">Exporteren naar bestand</string>
|
||||||
<string name="menu_delete_key">Sleutel verwijderen</string>
|
<string name="menu_delete_key">Sleutel verwijderen</string>
|
||||||
<string name="menu_create_key">Mijn sleutel aanmaken</string>
|
<string name="menu_manage_keys">Mijn sleutel aanmaken</string>
|
||||||
<string name="menu_import_existing_key">Importeren van bestand</string>
|
<string name="menu_import_existing_key">Importeren van bestand</string>
|
||||||
<string name="menu_search">Zoeken</string>
|
<string name="menu_search">Zoeken</string>
|
||||||
<string name="menu_nfc_preferences">NFC-instellingen</string>
|
<string name="menu_nfc_preferences">NFC-instellingen</string>
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
<string name="menu_help">Pomoc</string>
|
<string name="menu_help">Pomoc</string>
|
||||||
<string name="menu_export_key">Eksportuj do pliku</string>
|
<string name="menu_export_key">Eksportuj do pliku</string>
|
||||||
<string name="menu_delete_key">Usuń klucz</string>
|
<string name="menu_delete_key">Usuń klucz</string>
|
||||||
<string name="menu_create_key">Utwórz mój klucz</string>
|
<string name="menu_manage_keys">Utwórz mój klucz</string>
|
||||||
<string name="menu_import_existing_key">Importuj z pliku</string>
|
<string name="menu_import_existing_key">Importuj z pliku</string>
|
||||||
<string name="menu_search">Szukaj</string>
|
<string name="menu_search">Szukaj</string>
|
||||||
<string name="menu_beam_preferences">Ustawienia Beam</string>
|
<string name="menu_beam_preferences">Ustawienia Beam</string>
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
<string name="menu_help">Помощь</string>
|
<string name="menu_help">Помощь</string>
|
||||||
<string name="menu_export_key">Экспорт в файл</string>
|
<string name="menu_export_key">Экспорт в файл</string>
|
||||||
<string name="menu_delete_key">Удалить ключ</string>
|
<string name="menu_delete_key">Удалить ключ</string>
|
||||||
<string name="menu_create_key">Создать свой ключ</string>
|
<string name="menu_manage_keys">Создать свой ключ</string>
|
||||||
<string name="menu_import_existing_key">Импорт из файла</string>
|
<string name="menu_import_existing_key">Импорт из файла</string>
|
||||||
<string name="menu_search">Поиск</string>
|
<string name="menu_search">Поиск</string>
|
||||||
<string name="menu_nfc_preferences">Настройки NFC</string>
|
<string name="menu_nfc_preferences">Настройки NFC</string>
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
<string name="menu_help">Pomoč</string>
|
<string name="menu_help">Pomoč</string>
|
||||||
<string name="menu_export_key">Izvozi v datoteko</string>
|
<string name="menu_export_key">Izvozi v datoteko</string>
|
||||||
<string name="menu_delete_key">Izbriši ključ</string>
|
<string name="menu_delete_key">Izbriši ključ</string>
|
||||||
<string name="menu_create_key">Ustvari zasebni ključ</string>
|
<string name="menu_manage_keys">Ustvari zasebni ključ</string>
|
||||||
<string name="menu_import_existing_key">Uvozi iz datoteke</string>
|
<string name="menu_import_existing_key">Uvozi iz datoteke</string>
|
||||||
<string name="menu_search">Išči</string>
|
<string name="menu_search">Išči</string>
|
||||||
<string name="menu_beam_preferences">Nastavitve Beam</string>
|
<string name="menu_beam_preferences">Nastavitve Beam</string>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<string name="menu_help">Помоћ</string>
|
<string name="menu_help">Помоћ</string>
|
||||||
<string name="menu_export_key">Извези у фајл</string>
|
<string name="menu_export_key">Извези у фајл</string>
|
||||||
<string name="menu_delete_key">Обриши кључ</string>
|
<string name="menu_delete_key">Обриши кључ</string>
|
||||||
<string name="menu_create_key">Направи ми кључ</string>
|
<string name="menu_manage_keys">Направи ми кључ</string>
|
||||||
<string name="menu_import_existing_key">Увези из фајла</string>
|
<string name="menu_import_existing_key">Увези из фајла</string>
|
||||||
<string name="menu_search">Претрага</string>
|
<string name="menu_search">Претрага</string>
|
||||||
<string name="menu_nfc_preferences">НФЦ поставке</string>
|
<string name="menu_nfc_preferences">НФЦ поставке</string>
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
<string name="menu_help">Hjälp</string>
|
<string name="menu_help">Hjälp</string>
|
||||||
<string name="menu_export_key">Exportera till fil</string>
|
<string name="menu_export_key">Exportera till fil</string>
|
||||||
<string name="menu_delete_key">Radera nyckel</string>
|
<string name="menu_delete_key">Radera nyckel</string>
|
||||||
<string name="menu_create_key">Skapa min nyckel</string>
|
<string name="menu_manage_keys">Skapa min nyckel</string>
|
||||||
<string name="menu_import_existing_key">Importera från fil</string>
|
<string name="menu_import_existing_key">Importera från fil</string>
|
||||||
<string name="menu_search">Sök</string>
|
<string name="menu_search">Sök</string>
|
||||||
<string name="menu_beam_preferences">Beam-inställningar</string>
|
<string name="menu_beam_preferences">Beam-inställningar</string>
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
<string name="menu_help">Yardım</string>
|
<string name="menu_help">Yardım</string>
|
||||||
<string name="menu_export_key">Dosyaya ver</string>
|
<string name="menu_export_key">Dosyaya ver</string>
|
||||||
<string name="menu_delete_key">Anahtar sil</string>
|
<string name="menu_delete_key">Anahtar sil</string>
|
||||||
<string name="menu_create_key">Anahtarımı oluştur</string>
|
<string name="menu_manage_keys">Anahtarımı oluştur</string>
|
||||||
<string name="menu_import_existing_key">Dosyadan al</string>
|
<string name="menu_import_existing_key">Dosyadan al</string>
|
||||||
<string name="menu_search">Ara</string>
|
<string name="menu_search">Ara</string>
|
||||||
<string name="menu_beam_preferences">NFC ayarları</string>
|
<string name="menu_beam_preferences">NFC ayarları</string>
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
<string name="menu_help">Довідка</string>
|
<string name="menu_help">Довідка</string>
|
||||||
<string name="menu_export_key">Експорт до файлу</string>
|
<string name="menu_export_key">Експорт до файлу</string>
|
||||||
<string name="menu_delete_key">Вилучити ключ</string>
|
<string name="menu_delete_key">Вилучити ключ</string>
|
||||||
<string name="menu_create_key">Створити мій ключ</string>
|
<string name="menu_manage_keys">Створити мій ключ</string>
|
||||||
<string name="menu_import_existing_key">Імпорт з файлу</string>
|
<string name="menu_import_existing_key">Імпорт з файлу</string>
|
||||||
<string name="menu_search">Пошук</string>
|
<string name="menu_search">Пошук</string>
|
||||||
<string name="menu_beam_preferences">Налаштування променя</string>
|
<string name="menu_beam_preferences">Налаштування променя</string>
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
<string name="menu_help">說明</string>
|
<string name="menu_help">說明</string>
|
||||||
<string name="menu_export_key">匯出到檔案</string>
|
<string name="menu_export_key">匯出到檔案</string>
|
||||||
<string name="menu_delete_key">刪除金鑰</string>
|
<string name="menu_delete_key">刪除金鑰</string>
|
||||||
<string name="menu_create_key">建立金鑰</string>
|
<string name="menu_manage_keys">建立金鑰</string>
|
||||||
<string name="menu_import_existing_key">從檔案匯入</string>
|
<string name="menu_import_existing_key">從檔案匯入</string>
|
||||||
<string name="menu_search">搜尋</string>
|
<string name="menu_search">搜尋</string>
|
||||||
<string name="menu_beam_preferences">Beam 設定</string>
|
<string name="menu_beam_preferences">Beam 設定</string>
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
<string name="menu_help">帮助</string>
|
<string name="menu_help">帮助</string>
|
||||||
<string name="menu_export_key">导出密钥</string>
|
<string name="menu_export_key">导出密钥</string>
|
||||||
<string name="menu_delete_key">删除密钥</string>
|
<string name="menu_delete_key">删除密钥</string>
|
||||||
<string name="menu_create_key">创建密钥</string>
|
<string name="menu_manage_keys">创建密钥</string>
|
||||||
<string name="menu_search">搜索</string>
|
<string name="menu_search">搜索</string>
|
||||||
<string name="menu_beam_preferences">参数</string>
|
<string name="menu_beam_preferences">参数</string>
|
||||||
<string name="menu_key_edit_cancel">取消</string>
|
<string name="menu_key_edit_cancel">取消</string>
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
<string name="title_keys">"Keys"</string>
|
<string name="title_keys">"Keys"</string>
|
||||||
<string name="title_delete_secret_key">"Delete YOUR key '%s'?"</string>
|
<string name="title_delete_secret_key">"Delete YOUR key '%s'?"</string>
|
||||||
<string name="title_export_log">"Export Log"</string>
|
<string name="title_export_log">"Export Log"</string>
|
||||||
|
<string name="title_manage_my_keys">"Manage my keys"</string>
|
||||||
|
|
||||||
<!-- section -->
|
<!-- section -->
|
||||||
<string name="section_user_ids">"Identities"</string>
|
<string name="section_user_ids">"Identities"</string>
|
||||||
@ -106,7 +107,7 @@
|
|||||||
<string name="menu_help">"Help"</string>
|
<string name="menu_help">"Help"</string>
|
||||||
<string name="menu_export_key">"Export to file"</string>
|
<string name="menu_export_key">"Export to file"</string>
|
||||||
<string name="menu_delete_key">"Delete key"</string>
|
<string name="menu_delete_key">"Delete key"</string>
|
||||||
<string name="menu_create_key">"Create my key"</string>
|
<string name="menu_manage_keys">"Manage my keys"</string>
|
||||||
<string name="menu_import_existing_key">"Import from file"</string>
|
<string name="menu_import_existing_key">"Import from file"</string>
|
||||||
<string name="menu_search">"Search"</string>
|
<string name="menu_search">"Search"</string>
|
||||||
<string name="menu_nfc_preferences">"NFC settings"</string>
|
<string name="menu_nfc_preferences">"NFC settings"</string>
|
||||||
@ -1198,8 +1199,9 @@
|
|||||||
|
|
||||||
<!-- First Time -->
|
<!-- First Time -->
|
||||||
<string name="first_time_text1">"Take back your privacy with OpenKeychain!"</string>
|
<string name="first_time_text1">"Take back your privacy with OpenKeychain!"</string>
|
||||||
<string name="first_time_create_key">"Create my key"</string>
|
<string name="first_time_create_key">"Create my key (recommended)"</string>
|
||||||
<string name="first_time_import_key">"Import from file"</string>
|
<string name="first_time_import_key">"Import key from file"</string>
|
||||||
|
<string name="first_time_yubikey">"Use YubiKey NEO"</string>
|
||||||
<string name="first_time_skip">"Skip Setup"</string>
|
<string name="first_time_skip">"Skip Setup"</string>
|
||||||
|
|
||||||
<!-- unsorted -->
|
<!-- unsorted -->
|
||||||
|
Loading…
Reference in New Issue
Block a user