From 07e8729abf448bc47589dc34cd0591bec489d161 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 23 Sep 2014 23:49:18 +0200 Subject: [PATCH 1/3] fix nullpointer in previous swipetorefresh fix --- .../ui/widget/ListAwareSwipeRefreshLayout.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java index 818d92390..b3c3eb417 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java @@ -88,11 +88,15 @@ public class ListAwareSwipeRefreshLayout extends NoScrollableSwipeRefreshLayout */ @Override public boolean onTouchEvent(MotionEvent event) { - float ratioX = event.getX() / event.getDevice().getMotionRange(MotionEvent.AXIS_X).getMax(); - float ratioY = event.getY() / event.getDevice().getMotionRange(MotionEvent.AXIS_Y).getMax(); - // if this is the upper right corner, don't handle as pull to refresh event - if (ratioX > 0.85f && ratioY < 0.15f) { - return false; + // The device may be null. This actually happens + if (event.getDevice() != null) { + // MotionEvent.AXIS_X is api level 12, for some reason, so we use a constant 0 here + float ratioX = event.getX() / event.getDevice().getMotionRange(0).getMax(); + float ratioY = event.getY() / event.getDevice().getMotionRange(1).getMax(); + // if this is the upper right corner, don't handle as pull to refresh event + if (ratioX > 0.85f && ratioY < 0.15f) { + return false; + } } return super.onTouchEvent(event); } From d588b13255a7b7391c5f782a464c44bee4a3391b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 24 Sep 2014 01:37:28 +0200 Subject: [PATCH 2/3] fix signatures produced by yubikey The timestamp was only set on a second run. This led to a race condition whether the signature could be completed within the same timestamp. Fixes #834 --- .../keychain/pgp/CanonicalizedSecretKey.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 4106ab73d..697808d2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -199,14 +199,6 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, byte[] nfcSignedHash, Date nfcCreationTimestamp) { if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) { - // to sign using nfc PgpSignEncrypt is executed two times. - // the first time it stops to return the PendingIntent for nfc connection and signing the hash - // the second time the signed hash is used. - // to get the same hash we cache the timestamp for the second round! - if (nfcCreationTimestamp == null) { - nfcCreationTimestamp = new Date(); - } - // use synchronous "NFC based" SignerBuilder return new NfcSyncPGPContentSignerBuilder( mSecretKey.getPublicKey().getAlgorithm(), hashAlgo, @@ -226,6 +218,20 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { throw new PrivateKeyNotUnlockedException(); } + if (nfcSignedHash != null && nfcCreationTimestamp == null) { + throw new PgpGeneralException("Got nfc hash without timestamp!!"); + } + + // We explicitly create a signature creation timestamp in this place. + // That way, we can inject an artificial one from outside, ie the one + // used in previous runs of this function. + if (nfcCreationTimestamp == null) { + // to sign using nfc PgpSignEncrypt is executed two times. + // the first time it stops to return the PendingIntent for nfc connection and signing the hash + // the second time the signed hash is used. + // to get the same hash we cache the timestamp for the second round! + nfcCreationTimestamp = new Date(); + } PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgo, nfcSignedHash, nfcCreationTimestamp); @@ -244,10 +250,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); spGen.setSignerUserID(false, mRing.getPrimaryUserIdWithFallback()); - if (nfcCreationTimestamp != null) { - spGen.setSignatureCreationTime(false, nfcCreationTimestamp); - Log.d(Constants.TAG, "For NFC: set sig creation time to " + nfcCreationTimestamp); - } + spGen.setSignatureCreationTime(false, nfcCreationTimestamp); signatureGenerator.setHashedSubpackets(spGen.generate()); return signatureGenerator; } catch (PGPException e) { From 7654cd54fbba9fa6ecaf47f5ffc5fc21669d6e56 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 24 Sep 2014 01:41:40 +0200 Subject: [PATCH 3/3] fix signing in OK with yubikeys --- .../service/KeychainIntentService.java | 11 ++++++ .../keychain/ui/EncryptActivity.java | 4 +- .../keychain/ui/EncryptTextActivity.java | 37 ++++++++++++------- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 6d23c36b9..dc0d59e86 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -77,6 +77,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -133,6 +134,8 @@ public class KeychainIntentService extends IntentService implements Progressable // encrypt public static final String ENCRYPT_SIGNATURE_MASTER_ID = "secret_key_id"; public static final String ENCRYPT_SIGNATURE_KEY_PASSPHRASE = "secret_key_passphrase"; + public static final String ENCRYPT_SIGNATURE_NFC_TIMESTAMP = "signature_nfc_timestamp"; + public static final String ENCRYPT_SIGNATURE_NFC_HASH = "signature_nfc_hash"; public static final String ENCRYPT_USE_ASCII_ARMOR = "use_ascii_armor"; public static final String ENCRYPT_ENCRYPTION_KEYS_IDS = "encryption_keys_ids"; public static final String ENCRYPT_COMPRESSION_ID = "compression_id"; @@ -255,6 +258,10 @@ public class KeychainIntentService extends IntentService implements Progressable long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); + + byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); + Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); + String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); @@ -295,6 +302,10 @@ public class KeychainIntentService extends IntentService implements Progressable .setSignatureHashAlgorithm( Preferences.getPreferences(this).getDefaultHashAlgorithm()) .setAdditionalEncryptId(sigMasterKeyId); + if (nfcHash != null && nfcTimestamp != null) { + builder.setNfcState(nfcHash, nfcTimestamp); + } + } catch (PgpGeneralException e) { // encrypt-only // TODO Just silently drop the requested signature? Shouldn't we throw here? diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 836e7e268..cde31abdc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -4,6 +4,8 @@ import android.content.Intent; import org.sufficientlysecure.keychain.nfc.NfcActivity; +import java.util.Date; + public class EncryptActivity extends DrawerActivity { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; @@ -28,10 +30,10 @@ public class EncryptActivity extends DrawerActivity { // build PendingIntent for Yubikey NFC operations Intent intent = new Intent(this, NfcActivity.class); intent.setAction(NfcActivity.ACTION_SIGN_HASH); + // pass params through to activity that it can be returned again later to repeat pgp operation intent.putExtra(NfcActivity.EXTRA_DATA, data); intent.putExtra(NfcActivity.EXTRA_PIN, pin); - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign); intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 24e2c7f7b..6598ec50c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -28,6 +28,7 @@ import android.support.v4.app.Fragment; import android.view.Menu; import android.view.MenuItem; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; @@ -42,6 +43,7 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.ui.util.Notify; import java.util.ArrayList; +import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -70,6 +72,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv // TODO Constants.key.none? What's wrong with a null value? private long mSigningKeyId = Constants.key.none; private String mSigningKeyPassphrase = null; + private Date mNfcTimestamp = null; + private byte[] mNfcHash = null; private String mPassphrase = ""; private boolean mShareAfterEncrypt = false; private ArrayList mInputUris; @@ -202,28 +206,31 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == SignEncryptResult.RESULT_PENDING_NFC) { - // use after nfc sign -//// data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, result.getNfcTimestamp().getTime()); + mNfcTimestamp = pgpResult.getNfcTimestamp(); startNfcSign("123456", pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); } else { throw new RuntimeException("Unhandled pending result!"); } - } else if (pgpResult.success()) { - if (mShareAfterEncrypt) { - // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt(message)); + } else { + if (pgpResult.success()) { + if (mShareAfterEncrypt) { + // Share encrypted message/file + startActivity(sendWithChooserExcludingEncrypt(message)); + } else { + // Copy to clipboard + copyToClipboard(message); + pgpResult.createNotify(EncryptTextActivity.this).show(); + // Notify.showNotify(EncryptTextActivity.this, + // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO); + } } else { - // Copy to clipboard - copyToClipboard(message); pgpResult.createNotify(EncryptTextActivity.this).show(); - // Notify.showNotify(EncryptTextActivity.this, - // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO); } - // reset parameters, TODO: better state saving? + // no matter the result, reset parameters mSigningKeyPassphrase = null; - } else { - pgpResult.createNotify(EncryptTextActivity.this).show(); + mNfcHash = null; + mNfcTimestamp = null; } } } @@ -253,7 +260,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv case REQUEST_CODE_NFC: { if (resultCode == RESULT_OK && data != null) { - + mNfcHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); startEncrypt(); return; } @@ -292,6 +299,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, mEncryptionKeyIds); data.putString(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_PASSPHRASE, mSigningKeyPassphrase); data.putLongArray(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_PASSPHRASE, mEncryptionKeyIds); + data.putSerializable(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_TIMESTAMP, mNfcTimestamp); + data.putByteArray(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_HASH, mNfcHash); } return data; }