Merge branch 'master' into encrypted-export
This commit is contained in:
@@ -26,7 +26,7 @@ import java.io.InputStream;
|
||||
* general Java InputStream.
|
||||
* Like the various Stream-classes from Java, the BitInputStream
|
||||
* has to be created based on another Input stream. It provides
|
||||
* a function to read the next bit from the sream, as well as to read multiple
|
||||
* a function to read the next bit from the stream, as well as to read multiple
|
||||
* bits at once and write the resulting data into an integer value.
|
||||
* <p/>
|
||||
* source: http://developer.nokia.com/Community/Wiki/Bit_Input/Output_Stream_utility_classes_for_efficient_data_transfer
|
||||
@@ -69,11 +69,11 @@ public class BitInputStream {
|
||||
* @return integer value containing the bits read from the stream.
|
||||
* @throws IOException
|
||||
*/
|
||||
synchronized public int readBits(final int aNumberOfBits)
|
||||
synchronized public int readBits(final int aNumberOfBits, boolean stuffIfEnd)
|
||||
throws IOException {
|
||||
int value = 0;
|
||||
for (int i = aNumberOfBits - 1; i >= 0; i--) {
|
||||
value |= (readBit() << i);
|
||||
value |= (readBit(stuffIfEnd) << i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -92,15 +92,20 @@ public class BitInputStream {
|
||||
* @return 0 if the bit is 0, 1 if the bit is 1.
|
||||
* @throws IOException
|
||||
*/
|
||||
synchronized public int readBit() throws IOException {
|
||||
synchronized public int readBit(boolean stuffIfEnd) throws IOException {
|
||||
if (iIs == null)
|
||||
throw new IOException("Already closed");
|
||||
|
||||
if (iNextBit == 8) {
|
||||
iBuffer = iIs.read();
|
||||
|
||||
if (iBuffer == -1)
|
||||
throw new EOFException();
|
||||
if (iBuffer == -1) {
|
||||
if (stuffIfEnd) {
|
||||
return 1;
|
||||
} else {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
|
||||
iNextBit = 0;
|
||||
}
|
||||
|
||||
@@ -99,8 +99,12 @@ public class SentenceConfirm {
|
||||
*/
|
||||
private EntropyString getWord(List<String> words, BitInputStream bin) throws IOException {
|
||||
final int neededBits = log(words.size(), 2);
|
||||
Log.d(Constants.TAG, "need " + neededBits + " bits of entropy");
|
||||
int bits = bin.readBits(neededBits);
|
||||
Log.d(Constants.TAG, "need: " + neededBits + " bits of entropy");
|
||||
Log.d(Constants.TAG, "available: " + bin.available() + " bits");
|
||||
if (neededBits > bin.available()) {
|
||||
Log.d(Constants.TAG, "stuffed with " + (neededBits - bin.available()) + " ones!");
|
||||
}
|
||||
int bits = bin.readBits(neededBits, true);
|
||||
Log.d(Constants.TAG, "got word " + words.get(bits) + " with " + neededBits + " bits of entropy");
|
||||
return new EntropyString(words.get(bits), neededBits);
|
||||
}
|
||||
@@ -108,7 +112,7 @@ public class SentenceConfirm {
|
||||
private EntropyString getNounPhrase(BitInputStream bits) throws IOException {
|
||||
final EntropyString phrase = new EntropyString();
|
||||
phrase.append(getWord(art, bits)).append(" ");
|
||||
if (bits.readBit() != 0) {
|
||||
if (bits.readBit(true) != 0) {
|
||||
phrase.append(getWord(adj, bits)).append(" ");
|
||||
}
|
||||
phrase.incBits();
|
||||
@@ -121,7 +125,7 @@ public class SentenceConfirm {
|
||||
EntropyString getSentence(BitInputStream bits) throws IOException {
|
||||
final EntropyString sentence = new EntropyString();
|
||||
sentence.append(getNounPhrase(bits)); // Subject
|
||||
if (bits.readBit() != 0) {
|
||||
if (bits.readBit(true) != 0) {
|
||||
sentence.append(" ").append(getWord(vt, bits)); // Transitive verb
|
||||
sentence.append(" ").append(getNounPhrase(bits)); // Object of transitive verb
|
||||
} else {
|
||||
@@ -129,17 +133,17 @@ public class SentenceConfirm {
|
||||
}
|
||||
sentence.incBits();
|
||||
|
||||
if (bits.readBit() != 0) {
|
||||
if (bits.readBit(true) != 0) {
|
||||
sentence.append(" ").append(getWord(adv, bits)); // Adverb
|
||||
}
|
||||
|
||||
sentence.incBits();
|
||||
if (bits.readBit() != 0) {
|
||||
if (bits.readBit(true) != 0) {
|
||||
sentence.append(" ").append(getWord(p, bits)); // Preposition
|
||||
sentence.append(" ").append(getNounPhrase(bits)); // Object of preposition
|
||||
}
|
||||
sentence.incBits();
|
||||
Log.d(Constants.TAG, "got sentence " + sentence + " with " + sentence.getBits() + " bits of entropy");
|
||||
Log.d(Constants.TAG, "got sentence '" + sentence + "' with " + sentence.getBits() + " bits of entropy");
|
||||
|
||||
// uppercase first character, end with dot (without increasing the bits)
|
||||
sentence.getBuilder().replace(0, 1,
|
||||
|
||||
@@ -191,9 +191,10 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
|
||||
|
||||
String fingerprint;
|
||||
try {
|
||||
fingerprint = new SentenceConfirm(getActivity()).fromBytes(fingerprintBlob, 16);
|
||||
} catch (IOException ioe) {
|
||||
fingerprint = new SentenceConfirm(getActivity()).fromBytes(fingerprintBlob, 20);
|
||||
} catch (IOException e) {
|
||||
fingerprint = "-";
|
||||
Log.e(Constants.TAG, "Problem when creating sentence!", e);
|
||||
}
|
||||
|
||||
mFingerprint.setTextSize(18);
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
@@ -120,13 +119,9 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
||||
|
||||
setTitle(R.string.title_import_keys);
|
||||
} else {
|
||||
// Fragment frag = CreateYubiKeyBlankFragment.newInstance();
|
||||
// loadFragment(frag, FragAction.START);
|
||||
// setTitle(R.string.title_manage_my_keys);
|
||||
Notify.create(this,
|
||||
"YubiKey key creation is currently not supported. Please follow our FAQ.",
|
||||
Notify.Style.ERROR
|
||||
).show();
|
||||
Fragment frag = CreateYubiKeyBlankFragment.newInstance();
|
||||
loadFragment(frag, FragAction.START);
|
||||
setTitle(R.string.title_manage_my_keys);
|
||||
}
|
||||
|
||||
// done
|
||||
@@ -160,7 +155,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNfcPostExecute() throws IOException {
|
||||
protected void onNfcPostExecute() {
|
||||
if (mCurrentFragment instanceof NfcListenerFragment) {
|
||||
((NfcListenerFragment) mCurrentFragment).onNfcPostExecute();
|
||||
return;
|
||||
@@ -186,25 +181,23 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
||||
loadFragment(frag, FragAction.TO_RIGHT);
|
||||
}
|
||||
} else {
|
||||
// Fragment frag = CreateYubiKeyBlankFragment.newInstance();
|
||||
// loadFragment(frag, FragAction.TO_RIGHT);
|
||||
Notify.create(this,
|
||||
"YubiKey key creation is currently not supported. Please follow our FAQ.",
|
||||
Notify.Style.ERROR
|
||||
).show();
|
||||
Fragment frag = CreateYubiKeyBlankFragment.newInstance();
|
||||
loadFragment(frag, FragAction.TO_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsKeys(byte[] scannedFingerprints) {
|
||||
if (scannedFingerprints == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If all fingerprint bytes are 0, the card contains no keys.
|
||||
boolean cardContainsKeys = false;
|
||||
for (byte b : scannedFingerprints) {
|
||||
if (b != 0) {
|
||||
cardContainsKeys = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return cardContainsKeys;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -264,7 +257,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
||||
|
||||
interface NfcListenerFragment {
|
||||
void doNfcInBackground() throws IOException;
|
||||
void onNfcPostExecute() throws IOException;
|
||||
void onNfcPostExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -208,7 +208,7 @@ public class CreateYubiKeyImportFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNfcPostExecute() throws IOException {
|
||||
public void onNfcPostExecute() {
|
||||
|
||||
setData();
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ public class ImportKeysActivity extends BaseNfcActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNfcPostExecute() throws IOException {
|
||||
protected void onNfcPostExecute() {
|
||||
// either way, finish after NFC AsyncTask
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ViewAnimator;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
@@ -72,7 +73,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
||||
private RequiredInputParcel mRequiredInput;
|
||||
private Intent mServiceIntent;
|
||||
|
||||
private static final byte[] BLANK_FINGERPRINT = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
private static final byte[] BLANK_FINGERPRINT = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
private CryptoInputParcel mInputParcel;
|
||||
|
||||
@@ -245,7 +246,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNfcPostExecute() throws IOException {
|
||||
protected void onNfcPostExecute() {
|
||||
if (mServiceIntent != null) {
|
||||
// if we're triggered by OpenPgpService
|
||||
// save updated cryptoInputParcel in cache
|
||||
@@ -276,6 +277,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
@@ -292,25 +294,14 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
||||
vAnimator.setDisplayedChild(3);
|
||||
}
|
||||
|
||||
private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException {
|
||||
byte[] cardFingerprint = nfcGetFingerprint(idx);
|
||||
// Slot is empty, or contains this key already. PUT KEY operation is safe
|
||||
if (Arrays.equals(cardFingerprint, BLANK_FINGERPRINT) ||
|
||||
Arrays.equals(cardFingerprint, fingerprint)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Slot already contains a different key; don't overwrite it.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePinError() {
|
||||
public void onPinError() {
|
||||
|
||||
// avoid a loop
|
||||
Preferences prefs = Preferences.getPreferences(this);
|
||||
if (prefs.useDefaultYubiKeyPin()) {
|
||||
toast(getString(R.string.error_pin_nodefault));
|
||||
// use Toast because activity is finished afterwards
|
||||
Toast.makeText(this, R.string.error_pin_nodefault, Toast.LENGTH_LONG).show();
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return;
|
||||
@@ -321,4 +312,23 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
||||
this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
|
||||
}
|
||||
|
||||
private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException {
|
||||
byte[] cardFingerprint = nfcGetMasterKeyFingerprint(idx);
|
||||
|
||||
// Note: special case: This should not happen, but happens with
|
||||
// https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true
|
||||
if (cardFingerprint == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Slot is empty, or contains this key already. PUT KEY operation is safe
|
||||
if (Arrays.equals(cardFingerprint, BLANK_FINGERPRINT) ||
|
||||
Arrays.equals(cardFingerprint, fingerprint)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Slot already contains a different key; don't overwrite it.
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -555,7 +555,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNfcPostExecute() throws IOException {
|
||||
protected void onNfcPostExecute() {
|
||||
|
||||
long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
/**
|
||||
* Override to handle result of NFC operations (UI thread)
|
||||
*/
|
||||
protected void onNfcPostExecute() throws IOException {
|
||||
protected void onNfcPostExecute() {
|
||||
|
||||
final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
|
||||
|
||||
@@ -134,9 +134,19 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
Notify.create(this, error, Style.WARN).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to do something when PIN is wrong, e.g., clear passphrases (UI thread)
|
||||
*/
|
||||
protected void onPinError() {
|
||||
// use Toast because activity is finished afterwards
|
||||
Toast.makeText(this, R.string.error_pin_wrong, Toast.LENGTH_LONG).show();
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
||||
public void handleIntentInBackground(final Intent intent) {
|
||||
// Actual NFC operations are executed in doInBackground to not block the UI thread
|
||||
new AsyncTask<Void, Void, Exception>() {
|
||||
new AsyncTask<Void, Void, IOException>() {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
@@ -144,11 +154,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception doInBackground(Void... params) {
|
||||
protected IOException doInBackground(Void... params) {
|
||||
try {
|
||||
handleTagDiscoveredIntent(intent);
|
||||
} catch (CardException e) {
|
||||
return e;
|
||||
} catch (IOException e) {
|
||||
return e;
|
||||
}
|
||||
@@ -157,7 +165,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Exception exception) {
|
||||
protected void onPostExecute(IOException exception) {
|
||||
super.onPostExecute(exception);
|
||||
|
||||
if (exception != null) {
|
||||
@@ -165,11 +173,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
onNfcPostExecute();
|
||||
} catch (IOException e) {
|
||||
handleNfcError(e);
|
||||
}
|
||||
onNfcPostExecute();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
@@ -221,22 +225,30 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNfcError(Exception e) {
|
||||
Log.e(Constants.TAG, "nfc error", e);
|
||||
private void handleNfcError(IOException e) {
|
||||
|
||||
if (e instanceof TagLostException) {
|
||||
onNfcError(getString(R.string.error_nfc_tag_lost));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e instanceof IsoDepNotSupportedException) {
|
||||
onNfcError(getString(R.string.error_nfc_iso_dep_not_supported));
|
||||
return;
|
||||
}
|
||||
|
||||
short status;
|
||||
if (e instanceof CardException) {
|
||||
status = ((CardException) e).getResponseCode();
|
||||
} else {
|
||||
status = -1;
|
||||
}
|
||||
// When entering a PIN, a status of 63CX indicates X attempts remaining.
|
||||
if ((status & (short)0xFFF0) == 0x63C0) {
|
||||
|
||||
// Wrong PIN, a status of 63CX indicates X attempts remaining.
|
||||
if ((status & (short) 0xFFF0) == 0x63C0) {
|
||||
// hook to do something different when PIN is wrong
|
||||
onPinError();
|
||||
|
||||
int tries = status & 0x000F;
|
||||
onNfcError(getResources().getQuantityString(R.plurals.error_pin, tries, tries));
|
||||
return;
|
||||
@@ -307,12 +319,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
|
||||
}
|
||||
|
||||
public void handlePinError() {
|
||||
toast("Wrong PIN!");
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity,
|
||||
* disables NFC Foreground Dispatch
|
||||
@@ -337,7 +343,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
|
||||
protected void obtainYubiKeyPin(RequiredInputParcel requiredInput) {
|
||||
|
||||
// shortcut if we only use the default yubikey pin
|
||||
// shortcut if we only use the default YubiKey pin
|
||||
Preferences prefs = Preferences.getPreferences(this);
|
||||
if (prefs.useDefaultYubiKeyPin()) {
|
||||
mPin = new Passphrase("123456");
|
||||
@@ -345,10 +351,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
try {
|
||||
Passphrase phrase = PassphraseCacheService.getCachedPassphrase(this,
|
||||
Passphrase passphrase = PassphraseCacheService.getCachedPassphrase(this,
|
||||
requiredInput.getMasterKeyId(), requiredInput.getSubKeyId());
|
||||
if (phrase != null) {
|
||||
mPin = phrase;
|
||||
if (passphrase != null) {
|
||||
mPin = passphrase;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -363,10 +369,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
|
||||
}
|
||||
|
||||
protected void setYubiKeyPin(Passphrase pin) {
|
||||
mPin = pin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
@@ -406,6 +408,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
|
||||
// Connect to the detected tag, setting a couple of settings
|
||||
mIsoDep = IsoDep.get(detectedTag);
|
||||
if (mIsoDep == null) {
|
||||
throw new IsoDepNotSupportedException("Tag does not support ISO-DEP (ISO 14443-4)");
|
||||
}
|
||||
mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation
|
||||
mIsoDep.connect();
|
||||
|
||||
@@ -448,7 +453,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
* @return The long key id of the requested key, or null if not found.
|
||||
*/
|
||||
public Long nfcGetKeyId(int idx) throws IOException {
|
||||
byte[] fp = nfcGetFingerprint(idx);
|
||||
byte[] fp = nfcGetMasterKeyFingerprint(idx);
|
||||
if (fp == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -469,7 +474,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
byte[] buf = mIsoDep.transceive(Hex.decode(data));
|
||||
|
||||
Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true);
|
||||
Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint());
|
||||
Log.d(Constants.TAG, "nfcGetFingerprints() Iso7816TLV tlv data:\n" + tlv.prettyPrint());
|
||||
|
||||
Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5);
|
||||
if (fptlv == null) {
|
||||
@@ -494,8 +499,11 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
* @param idx Index of the key to return the fingerprint from.
|
||||
* @return The fingerprint of the requested key, or null if not found.
|
||||
*/
|
||||
public byte[] nfcGetFingerprint(int idx) throws IOException {
|
||||
public byte[] nfcGetMasterKeyFingerprint(int idx) throws IOException {
|
||||
byte[] data = nfcGetFingerprints();
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// return the master key fingerprint
|
||||
ByteBuffer fpbuf = ByteBuffer.wrap(data);
|
||||
@@ -507,14 +515,11 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
public byte[] nfcGetAid() throws IOException {
|
||||
|
||||
String info = "00CA004F00";
|
||||
return mIsoDep.transceive(Hex.decode(info));
|
||||
|
||||
}
|
||||
|
||||
public String nfcGetUserId() throws IOException {
|
||||
|
||||
String info = "00CA006500";
|
||||
return nfcGetHolderName(nfcCommunicate(info));
|
||||
}
|
||||
@@ -648,8 +653,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
|
||||
String decryptedSessionKey = nfcGetDataField(second);
|
||||
|
||||
Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey);
|
||||
|
||||
return Hex.decode(decryptedSessionKey);
|
||||
}
|
||||
|
||||
@@ -682,7 +685,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
+ Hex.toHexString(pin);
|
||||
String response = nfcCommunicate(login); // login
|
||||
if (!response.equals(accepted)) {
|
||||
handlePinError();
|
||||
throw new CardException("Bad PIN!", parseCardStatus(response));
|
||||
}
|
||||
|
||||
@@ -737,7 +739,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
+ getHex(newPin);
|
||||
String response = nfcCommunicate(changeReferenceDataApdu); // change PIN
|
||||
if (!response.equals("9000")) {
|
||||
handlePinError();
|
||||
throw new CardException("Failed to change PIN", parseCardStatus(response));
|
||||
}
|
||||
}
|
||||
@@ -905,15 +906,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message to the screen
|
||||
*
|
||||
* @param text the text which should be contained within the toast
|
||||
*/
|
||||
protected void toast(String text) {
|
||||
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive new NFC Intents to this activity only by enabling foreground dispatch.
|
||||
* This can only be done in onResume!
|
||||
@@ -930,12 +922,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
|
||||
};
|
||||
|
||||
// https://code.google.com/p/android/issues/detail?id=62918
|
||||
// maybe mNfcAdapter.enableReaderMode(); ?
|
||||
try {
|
||||
mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e);
|
||||
Log.i(Constants.TAG, "NfcForegroundDispatch Exception: Activity is not currently in the foreground?", e);
|
||||
}
|
||||
Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!");
|
||||
}
|
||||
@@ -952,14 +942,23 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
public String nfcGetHolderName(String name) {
|
||||
String slength;
|
||||
int ilength;
|
||||
name = name.substring(6);
|
||||
slength = name.substring(0, 2);
|
||||
ilength = Integer.parseInt(slength, 16) * 2;
|
||||
name = name.substring(2, ilength + 2);
|
||||
name = (new String(Hex.decode(name))).replace('<', ' ');
|
||||
return (name);
|
||||
try {
|
||||
String slength;
|
||||
int ilength;
|
||||
name = name.substring(6);
|
||||
slength = name.substring(0, 2);
|
||||
ilength = Integer.parseInt(slength, 16) * 2;
|
||||
name = name.substring(2, ilength + 2);
|
||||
name = (new String(Hex.decode(name))).replace('<', ' ');
|
||||
return name;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
// try-catch for https://github.com/FluffyKaon/OpenPGP-Card
|
||||
// Note: This should not happen, but happens with
|
||||
// https://github.com/FluffyKaon/OpenPGP-Card, thus return an empty string for now!
|
||||
|
||||
Log.e(Constants.TAG, "Couldn't get holder name, returning empty string!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String nfcGetDataField(String output) {
|
||||
@@ -974,6 +973,14 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
||||
return new String(Hex.encode(raw));
|
||||
}
|
||||
|
||||
public class IsoDepNotSupportedException extends IOException {
|
||||
|
||||
public IsoDepNotSupportedException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CardException extends IOException {
|
||||
private short mResponseCode;
|
||||
|
||||
|
||||
@@ -571,8 +571,9 @@ public class KeyFormattingUtils {
|
||||
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
|
||||
sigColor = R.color.key_flag_red;
|
||||
|
||||
sigActionText = R.string.decrypt_result_action_show;
|
||||
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
|
||||
// won't be used, but makes compiler happy
|
||||
sigActionText = 0;
|
||||
sigActionIcon = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -584,7 +585,8 @@ public class KeyFormattingUtils {
|
||||
holder.getSignatureStatusText().setText(sigText);
|
||||
holder.getSignatureStatusText().setTextColor(sigColorRes);
|
||||
|
||||
if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE) {
|
||||
if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE
|
||||
&& signatureResult.getResult() != OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE) {
|
||||
// has a signature, thus display layouts
|
||||
|
||||
holder.getSignatureLayout().setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -1535,8 +1535,10 @@
|
||||
<string name="error_nfc_chaining_error">"YubiKey expected last command in a chain."</string>
|
||||
<string name="error_nfc_header">"YubiKey reported invalid %s byte."</string>
|
||||
<string name="error_nfc_tag_lost">"YubiKey has been taken off too early. Keep the YubiKey at the back until the operation finishes."</string>
|
||||
<string name="error_nfc_iso_dep_not_supported">"Tag does not support ISO-DEP (ISO 14443-4)"</string>
|
||||
<string name="error_nfc_try_again">"Try again"</string>
|
||||
<string name="error_pin_nodefault">Default PIN was rejected!</string>
|
||||
<string name="error_pin_wrong">PIN is wrong!</string>
|
||||
<string name="error_temp_file">Error creating temporary file.</string>
|
||||
<string name="btn_delete_original">Delete original file</string>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowLog;
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.sufficientlysecure.keychain.BuildConfig;
|
||||
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
|
||||
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
||||
@@ -41,6 +42,7 @@ import org.sufficientlysecure.keychain.util.Passphrase;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.Security;
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -53,6 +55,7 @@ public class UncachedKeyringTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpOnce() throws Exception {
|
||||
Security.insertProviderAt(new BouncyCastleProvider(), 1);
|
||||
ShadowLog.stream = System.out;
|
||||
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
|
||||
2
extern/spongycastle
vendored
2
extern/spongycastle
vendored
Submodule extern/spongycastle updated: b767c5afff...432b7f1bfd
Reference in New Issue
Block a user