Change PIN and Admin PIN after move to key operation
This commit is contained in:
@@ -510,6 +510,8 @@ public abstract class OperationResult implements Parcelable {
|
|||||||
MSG_MF_NOTATION_PIN (LogLevel.DEBUG, R.string.msg_mf_notation_pin),
|
MSG_MF_NOTATION_PIN (LogLevel.DEBUG, R.string.msg_mf_notation_pin),
|
||||||
MSG_MF_NOTATION_EMPTY (LogLevel.DEBUG, R.string.msg_mf_notation_empty),
|
MSG_MF_NOTATION_EMPTY (LogLevel.DEBUG, R.string.msg_mf_notation_empty),
|
||||||
MSG_MF_PASSPHRASE (LogLevel.INFO, R.string.msg_mf_passphrase),
|
MSG_MF_PASSPHRASE (LogLevel.INFO, R.string.msg_mf_passphrase),
|
||||||
|
MSG_MF_PIN (LogLevel.INFO, R.string.msg_mf_pin),
|
||||||
|
MSG_MF_ADMIN_PIN (LogLevel.INFO, R.string.msg_mf_admin_pin),
|
||||||
MSG_MF_PASSPHRASE_KEY (LogLevel.DEBUG, R.string.msg_mf_passphrase_key),
|
MSG_MF_PASSPHRASE_KEY (LogLevel.DEBUG, R.string.msg_mf_passphrase_key),
|
||||||
MSG_MF_PASSPHRASE_EMPTY_RETRY (LogLevel.DEBUG, R.string.msg_mf_passphrase_empty_retry),
|
MSG_MF_PASSPHRASE_EMPTY_RETRY (LogLevel.DEBUG, R.string.msg_mf_passphrase_empty_retry),
|
||||||
MSG_MF_PASSPHRASE_FAIL (LogLevel.WARN, R.string.msg_mf_passphrase_fail),
|
MSG_MF_PASSPHRASE_FAIL (LogLevel.WARN, R.string.msg_mf_passphrase_fail),
|
||||||
|
|||||||
@@ -1039,6 +1039,26 @@ public class PgpKeyOperation {
|
|||||||
indent -= 1;
|
indent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 7. if requested, change PIN and/or Admin PIN on card
|
||||||
|
if (saveParcel.mCardPin != null) {
|
||||||
|
progress(R.string.progress_modify_pin, 90);
|
||||||
|
log.add(LogType.MSG_MF_PIN, indent);
|
||||||
|
indent += 1;
|
||||||
|
|
||||||
|
nfcKeyToCardOps.setPin(saveParcel.mCardPin);
|
||||||
|
|
||||||
|
indent -= 1;
|
||||||
|
}
|
||||||
|
if (saveParcel.mCardAdminPin != null) {
|
||||||
|
progress(R.string.progress_modify_admin_pin, 90);
|
||||||
|
log.add(LogType.MSG_MF_ADMIN_PIN, indent);
|
||||||
|
indent += 1;
|
||||||
|
|
||||||
|
nfcKeyToCardOps.setAdminPin(saveParcel.mCardAdminPin);
|
||||||
|
|
||||||
|
indent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "encountered IOException while modifying key", e);
|
Log.e(Constants.TAG, "encountered IOException while modifying key", e);
|
||||||
log.add(LogType.MSG_MF_ERROR_ENCODE, indent+1);
|
log.add(LogType.MSG_MF_ERROR_ENCODE, indent+1);
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
public ArrayList<String> mRevokeUserIds;
|
public ArrayList<String> mRevokeUserIds;
|
||||||
public ArrayList<Long> mRevokeSubKeys;
|
public ArrayList<Long> mRevokeSubKeys;
|
||||||
|
|
||||||
|
// if these are non-null, PINs will be changed on the card
|
||||||
|
public Passphrase mCardPin;
|
||||||
|
public Passphrase mCardAdminPin;
|
||||||
|
|
||||||
public SaveKeyringParcel() {
|
public SaveKeyringParcel() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
@@ -80,6 +84,8 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
mChangeSubKeys = new ArrayList<>();
|
mChangeSubKeys = new ArrayList<>();
|
||||||
mRevokeUserIds = new ArrayList<>();
|
mRevokeUserIds = new ArrayList<>();
|
||||||
mRevokeSubKeys = new ArrayList<>();
|
mRevokeSubKeys = new ArrayList<>();
|
||||||
|
mCardPin = null;
|
||||||
|
mCardAdminPin = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
@@ -225,6 +231,9 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
|
|
||||||
mRevokeUserIds = source.createStringArrayList();
|
mRevokeUserIds = source.createStringArrayList();
|
||||||
mRevokeSubKeys = (ArrayList<Long>) source.readSerializable();
|
mRevokeSubKeys = (ArrayList<Long>) source.readSerializable();
|
||||||
|
|
||||||
|
mCardPin = source.readParcelable(Passphrase.class.getClassLoader());
|
||||||
|
mCardAdminPin = source.readParcelable(Passphrase.class.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -236,7 +245,7 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
destination.writeByteArray(mFingerprint);
|
destination.writeByteArray(mFingerprint);
|
||||||
|
|
||||||
// yes, null values are ok for parcelables
|
// yes, null values are ok for parcelables
|
||||||
destination.writeParcelable(mNewUnlock, 0);
|
destination.writeParcelable(mNewUnlock, flags);
|
||||||
|
|
||||||
destination.writeStringList(mAddUserIds);
|
destination.writeStringList(mAddUserIds);
|
||||||
destination.writeSerializable(mAddUserAttribute);
|
destination.writeSerializable(mAddUserAttribute);
|
||||||
@@ -247,6 +256,9 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
|
|
||||||
destination.writeStringList(mRevokeUserIds);
|
destination.writeStringList(mRevokeUserIds);
|
||||||
destination.writeSerializable(mRevokeSubKeys);
|
destination.writeSerializable(mRevokeSubKeys);
|
||||||
|
|
||||||
|
destination.writeParcelable(mCardPin, flags);
|
||||||
|
destination.writeParcelable(mCardAdminPin, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() {
|
public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() {
|
||||||
@@ -274,7 +286,9 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
out += "mChangeSubKeys: " + mChangeSubKeys + "\n";
|
out += "mChangeSubKeys: " + mChangeSubKeys + "\n";
|
||||||
out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n";
|
out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n";
|
||||||
out += "mRevokeUserIds: " + mRevokeUserIds + "\n";
|
out += "mRevokeUserIds: " + mRevokeUserIds + "\n";
|
||||||
out += "mRevokeSubKeys: " + mRevokeSubKeys;
|
out += "mRevokeSubKeys: " + mRevokeSubKeys + "\n";
|
||||||
|
out += "mCardPin: " + mCardPin + "\n";
|
||||||
|
out += "mCardAdminPin: " + mCardAdminPin;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
package org.sufficientlysecure.keychain.service.input;
|
package org.sufficientlysecure.keychain.service.input;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import org.spongycastle.util.Arrays;
|
||||||
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
|
|
||||||
public class RequiredInputParcel implements Parcelable {
|
public class RequiredInputParcel implements Parcelable {
|
||||||
|
|
||||||
@@ -19,16 +22,16 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
|
|
||||||
public final RequiredInputType mType;
|
public final RequiredInputType mType;
|
||||||
|
|
||||||
public final byte[][] mInputHashes;
|
public final byte[][] mInputData;
|
||||||
public final int[] mSignAlgos;
|
public final int[] mSignAlgos;
|
||||||
|
|
||||||
private Long mMasterKeyId;
|
private Long mMasterKeyId;
|
||||||
private Long mSubKeyId;
|
private Long mSubKeyId;
|
||||||
|
|
||||||
private RequiredInputParcel(RequiredInputType type, byte[][] inputHashes,
|
private RequiredInputParcel(RequiredInputType type, byte[][] inputData,
|
||||||
int[] signAlgos, Date signatureTime, Long masterKeyId, Long subKeyId) {
|
int[] signAlgos, Date signatureTime, Long masterKeyId, Long subKeyId) {
|
||||||
mType = type;
|
mType = type;
|
||||||
mInputHashes = inputHashes;
|
mInputData = inputData;
|
||||||
mSignAlgos = signAlgos;
|
mSignAlgos = signAlgos;
|
||||||
mSignatureTime = signatureTime;
|
mSignatureTime = signatureTime;
|
||||||
mMasterKeyId = masterKeyId;
|
mMasterKeyId = masterKeyId;
|
||||||
@@ -38,25 +41,25 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
public RequiredInputParcel(Parcel source) {
|
public RequiredInputParcel(Parcel source) {
|
||||||
mType = RequiredInputType.values()[source.readInt()];
|
mType = RequiredInputType.values()[source.readInt()];
|
||||||
|
|
||||||
// 0 = none, 1 = both, 2 = only hashes (decrypt)
|
// 0 = none, 1 = signAlgos + inputData, 2 = only inputData (decrypt)
|
||||||
int hashTypes = source.readInt();
|
int inputDataType = source.readInt();
|
||||||
if (hashTypes != 0) {
|
if (inputDataType != 0) {
|
||||||
int count = source.readInt();
|
int count = source.readInt();
|
||||||
mInputHashes = new byte[count][];
|
mInputData = new byte[count][];
|
||||||
if (hashTypes == 1) {
|
if (inputDataType == 1) {
|
||||||
mSignAlgos = new int[count];
|
mSignAlgos = new int[count];
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
mInputHashes[i] = source.createByteArray();
|
mInputData[i] = source.createByteArray();
|
||||||
mSignAlgos[i] = source.readInt();
|
mSignAlgos[i] = source.readInt();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mSignAlgos = null;
|
mSignAlgos = null;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
mInputHashes[i] = source.createByteArray();
|
mInputData[i] = source.createByteArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mInputHashes = null;
|
mInputData = null;
|
||||||
mSignAlgos = null;
|
mSignAlgos = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,9 +86,9 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static RequiredInputParcel createNfcDecryptOperation(
|
public static RequiredInputParcel createNfcDecryptOperation(
|
||||||
long masterKeyId, long subKeyId, byte[] inputHash) {
|
long masterKeyId, long subKeyId, byte[] encryptedSessionKey) {
|
||||||
return new RequiredInputParcel(RequiredInputType.NFC_DECRYPT,
|
return new RequiredInputParcel(RequiredInputType.NFC_DECRYPT,
|
||||||
new byte[][] { inputHash }, null, null, masterKeyId, subKeyId);
|
new byte[][] { encryptedSessionKey }, null, null, masterKeyId, subKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequiredInputParcel createRequiredSignPassphrase(
|
public static RequiredInputParcel createRequiredSignPassphrase(
|
||||||
@@ -119,11 +122,11 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeInt(mType.ordinal());
|
dest.writeInt(mType.ordinal());
|
||||||
if (mInputHashes != null) {
|
if (mInputData != null) {
|
||||||
dest.writeInt(mSignAlgos != null ? 1 : 2);
|
dest.writeInt(mSignAlgos != null ? 1 : 2);
|
||||||
dest.writeInt(mInputHashes.length);
|
dest.writeInt(mInputData.length);
|
||||||
for (int i = 0; i < mInputHashes.length; i++) {
|
for (int i = 0; i < mInputData.length; i++) {
|
||||||
dest.writeByteArray(mInputHashes[i]);
|
dest.writeByteArray(mInputData[i]);
|
||||||
if (mSignAlgos != null) {
|
if (mSignAlgos != null) {
|
||||||
dest.writeInt(mSignAlgos[i]);
|
dest.writeInt(mSignAlgos[i]);
|
||||||
}
|
}
|
||||||
@@ -200,7 +203,7 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
throw new AssertionError("operation types must match, this is a progrmming error!");
|
throw new AssertionError("operation types must match, this is a progrmming error!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.addAll(mInputHashes, input.mInputHashes);
|
Collections.addAll(mInputHashes, input.mInputData);
|
||||||
for (int signAlgo : input.mSignAlgos) {
|
for (int signAlgo : input.mSignAlgos) {
|
||||||
mSignAlgos.add(signAlgo);
|
mSignAlgos.add(signAlgo);
|
||||||
}
|
}
|
||||||
@@ -215,19 +218,31 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
public static class NfcKeyToCardOperationsBuilder {
|
public static class NfcKeyToCardOperationsBuilder {
|
||||||
ArrayList<byte[]> mSubkeysToExport = new ArrayList<>();
|
ArrayList<byte[]> mSubkeysToExport = new ArrayList<>();
|
||||||
Long mMasterKeyId;
|
Long mMasterKeyId;
|
||||||
|
byte[] mPin;
|
||||||
|
byte[] mAdminPin;
|
||||||
|
|
||||||
public NfcKeyToCardOperationsBuilder(Long masterKeyId) {
|
public NfcKeyToCardOperationsBuilder(Long masterKeyId) {
|
||||||
mMasterKeyId = masterKeyId;
|
mMasterKeyId = masterKeyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequiredInputParcel build() {
|
public RequiredInputParcel build() {
|
||||||
byte[][] inputHashes = new byte[mSubkeysToExport.size()][];
|
byte[][] inputData = new byte[mSubkeysToExport.size() + 2][];
|
||||||
mSubkeysToExport.toArray(inputHashes);
|
|
||||||
|
// encode all subkeys into inputData
|
||||||
|
byte[][] subkeyData = new byte[mSubkeysToExport.size()][];
|
||||||
|
mSubkeysToExport.toArray(subkeyData);
|
||||||
|
|
||||||
|
// first two are PINs
|
||||||
|
inputData[0] = mPin;
|
||||||
|
inputData[1] = mAdminPin;
|
||||||
|
// then subkeys
|
||||||
|
System.arraycopy(subkeyData, 0, inputData, 2, subkeyData.length);
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(mSubkeysToExport.get(0));
|
ByteBuffer buf = ByteBuffer.wrap(mSubkeysToExport.get(0));
|
||||||
|
|
||||||
// We need to pass in a subkey here...
|
// We need to pass in a subkey here...
|
||||||
return new RequiredInputParcel(RequiredInputType.NFC_MOVE_KEY_TO_CARD,
|
return new RequiredInputParcel(RequiredInputType.NFC_MOVE_KEY_TO_CARD,
|
||||||
inputHashes, null, null, mMasterKeyId, buf.getLong());
|
inputData, null, null, mMasterKeyId, buf.getLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSubkey(long subkeyId) {
|
public void addSubkey(long subkeyId) {
|
||||||
@@ -237,6 +252,14 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
mSubkeysToExport.add(subKeyId);
|
mSubkeysToExport.add(subKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPin(Passphrase pin) {
|
||||||
|
mPin = pin.toStringUnsafe().getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdminPin(Passphrase adminPin) {
|
||||||
|
mAdminPin = adminPin.toStringUnsafe().getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
public void addAll(RequiredInputParcel input) {
|
public void addAll(RequiredInputParcel input) {
|
||||||
if (!mMasterKeyId.equals(input.mMasterKeyId)) {
|
if (!mMasterKeyId.equals(input.mMasterKeyId)) {
|
||||||
throw new AssertionError("Master keys must match, this is a programming error!");
|
throw new AssertionError("Master keys must match, this is a programming error!");
|
||||||
@@ -245,7 +268,7 @@ public class RequiredInputParcel implements Parcelable {
|
|||||||
throw new AssertionError("Operation types must match, this is a programming error!");
|
throw new AssertionError("Operation types must match, this is a programming error!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.addAll(mSubkeysToExport, input.mInputHashes);
|
Collections.addAll(mSubkeysToExport, input.mInputData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
Passphrase mPassphrase;
|
Passphrase mPassphrase;
|
||||||
boolean mFirstTime;
|
boolean mFirstTime;
|
||||||
boolean mCreateYubiKey;
|
boolean mCreateYubiKey;
|
||||||
String mYubiKeyPin;
|
Passphrase mYubiKeyPin;
|
||||||
String mYubiKeyAdminPin;
|
Passphrase mYubiKeyAdminPin;
|
||||||
|
|
||||||
Fragment mCurrentFragment;
|
Fragment mCurrentFragment;
|
||||||
|
|
||||||
@@ -93,8 +93,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
mPassphrase = savedInstanceState.getParcelable(EXTRA_PASSPHRASE);
|
mPassphrase = savedInstanceState.getParcelable(EXTRA_PASSPHRASE);
|
||||||
mFirstTime = savedInstanceState.getBoolean(EXTRA_FIRST_TIME);
|
mFirstTime = savedInstanceState.getBoolean(EXTRA_FIRST_TIME);
|
||||||
mCreateYubiKey = savedInstanceState.getBoolean(EXTRA_CREATE_YUBI_KEY);
|
mCreateYubiKey = savedInstanceState.getBoolean(EXTRA_CREATE_YUBI_KEY);
|
||||||
mYubiKeyPin = savedInstanceState.getString(EXTRA_YUBI_KEY_PIN);
|
mYubiKeyPin = savedInstanceState.getParcelable(EXTRA_YUBI_KEY_PIN);
|
||||||
mYubiKeyAdminPin = savedInstanceState.getString(EXTRA_YUBI_KEY_ADMIN_PIN);
|
mYubiKeyAdminPin = savedInstanceState.getParcelable(EXTRA_YUBI_KEY_ADMIN_PIN);
|
||||||
|
|
||||||
mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||||
} else {
|
} else {
|
||||||
@@ -200,8 +200,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
outState.putParcelable(EXTRA_PASSPHRASE, mPassphrase);
|
outState.putParcelable(EXTRA_PASSPHRASE, mPassphrase);
|
||||||
outState.putBoolean(EXTRA_FIRST_TIME, mFirstTime);
|
outState.putBoolean(EXTRA_FIRST_TIME, mFirstTime);
|
||||||
outState.putBoolean(EXTRA_CREATE_YUBI_KEY, mCreateYubiKey);
|
outState.putBoolean(EXTRA_CREATE_YUBI_KEY, mCreateYubiKey);
|
||||||
outState.putString(EXTRA_YUBI_KEY_PIN, mYubiKeyPin);
|
outState.putParcelable(EXTRA_YUBI_KEY_PIN, mYubiKeyPin);
|
||||||
outState.putString(EXTRA_YUBI_KEY_ADMIN_PIN, mYubiKeyAdminPin);
|
outState.putParcelable(EXTRA_YUBI_KEY_ADMIN_PIN, mYubiKeyAdminPin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -267,10 +267,11 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void moveToCard(final EditKeyResult saveKeyResult) {
|
private void moveToCard(final EditKeyResult saveKeyResult) {
|
||||||
CachedPublicKeyRing key = (new ProviderHelper(getActivity()))
|
final CreateKeyActivity createKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
.getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
|
|
||||||
|
|
||||||
final SaveKeyringParcel changeKeyringParcel;
|
final SaveKeyringParcel changeKeyringParcel;
|
||||||
|
CachedPublicKeyRing key = (new ProviderHelper(getActivity()))
|
||||||
|
.getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
|
||||||
try {
|
try {
|
||||||
changeKeyringParcel = new SaveKeyringParcel(key.getMasterKeyId(), key.getFingerprint());
|
changeKeyringParcel = new SaveKeyringParcel(key.getMasterKeyId(), key.getFingerprint());
|
||||||
} catch (PgpKeyNotFoundException e) {
|
} catch (PgpKeyNotFoundException e) {
|
||||||
@@ -278,6 +279,7 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// define subkeys that should be moved to the card
|
||||||
Cursor cursor = getActivity().getContentResolver().query(
|
Cursor cursor = getActivity().getContentResolver().query(
|
||||||
KeychainContract.Keys.buildKeysUri(changeKeyringParcel.mMasterKeyId),
|
KeychainContract.Keys.buildKeysUri(changeKeyringParcel.mMasterKeyId),
|
||||||
new String[]{KeychainContract.Keys.KEY_ID,}, null, null, null
|
new String[]{KeychainContract.Keys.KEY_ID,}, null, null, null
|
||||||
@@ -293,6 +295,10 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// define new PIN and Admin PIN for the card
|
||||||
|
changeKeyringParcel.mCardPin = createKeyActivity.mYubiKeyPin;
|
||||||
|
changeKeyringParcel.mCardAdminPin = createKeyActivity.mYubiKeyAdminPin;
|
||||||
|
|
||||||
CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult> callback
|
CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult> callback
|
||||||
= new CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult>() {
|
= new CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult>() {
|
||||||
|
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ public class CreateKeyPassphraseFragment extends Fragment {
|
|||||||
// initial values
|
// initial values
|
||||||
// TODO: using String here is unsafe...
|
// TODO: using String here is unsafe...
|
||||||
if (mCreateKeyActivity.mPassphrase != null) {
|
if (mCreateKeyActivity.mPassphrase != null) {
|
||||||
mPassphraseEdit.setText(new String(mCreateKeyActivity.mPassphrase.getCharArray()));
|
mPassphraseEdit.setText(mCreateKeyActivity.mPassphrase.toStringUnsafe());
|
||||||
mPassphraseEditAgain.setText(new String(mCreateKeyActivity.mPassphrase.getCharArray()));
|
mPassphraseEditAgain.setText(mCreateKeyActivity.mPassphrase.toStringUnsafe());
|
||||||
}
|
}
|
||||||
|
|
||||||
mPassphraseEdit.requestFocus();
|
mPassphraseEdit.requestFocus();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
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.util.Passphrase;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
@@ -63,30 +64,38 @@ public class CreateYubiKeyPinFragment extends Fragment {
|
|||||||
mNextButton = view.findViewById(R.id.create_key_next_button);
|
mNextButton = view.findViewById(R.id.create_key_next_button);
|
||||||
|
|
||||||
if (mCreateKeyActivity.mYubiKeyPin == null) {
|
if (mCreateKeyActivity.mYubiKeyPin == null) {
|
||||||
new AsyncTask<Void, Void, Pair<String, String>>() {
|
new AsyncTask<Void, Void, Pair<Passphrase, Passphrase>>() {
|
||||||
@Override
|
@Override
|
||||||
protected Pair<String, String> doInBackground(Void... unused) {
|
protected Pair<Passphrase, Passphrase> doInBackground(Void... unused) {
|
||||||
SecureRandom secureRandom = new SecureRandom();
|
SecureRandom secureRandom = new SecureRandom();
|
||||||
// min = 6, we choose 6
|
// min = 6, we choose 6
|
||||||
String pin = "" + secureRandom.nextInt(999999);
|
String pin = "" + secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9);
|
||||||
// min = 8, we choose 10, but 6 are equals the PIN
|
// min = 8, we choose 10, but 6 are equals the PIN
|
||||||
String adminPin = pin + secureRandom.nextInt(9999);
|
String adminPin = pin + secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9)
|
||||||
|
+ secureRandom.nextInt(9);
|
||||||
|
|
||||||
return new Pair<>(pin, adminPin);
|
return new Pair<>(new Passphrase(pin), new Passphrase(adminPin));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Pair<String, String> pair) {
|
protected void onPostExecute(Pair<Passphrase, Passphrase> pair) {
|
||||||
mCreateKeyActivity.mYubiKeyPin = pair.first;
|
mCreateKeyActivity.mYubiKeyPin = pair.first;
|
||||||
mCreateKeyActivity.mYubiKeyAdminPin = pair.second;
|
mCreateKeyActivity.mYubiKeyAdminPin = pair.second;
|
||||||
|
|
||||||
mPin.setText(mCreateKeyActivity.mYubiKeyPin);
|
mPin.setText(mCreateKeyActivity.mYubiKeyPin.toStringUnsafe());
|
||||||
mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin);
|
mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe());
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
} else {
|
} else {
|
||||||
mPin.setText(mCreateKeyActivity.mYubiKeyPin);
|
mPin.setText(mCreateKeyActivity.mYubiKeyPin.toStringUnsafe());
|
||||||
mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin);
|
mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe());
|
||||||
}
|
}
|
||||||
|
|
||||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@@ -114,9 +123,6 @@ public class CreateYubiKeyPinFragment extends Fragment {
|
|||||||
|
|
||||||
|
|
||||||
private void nextClicked() {
|
private void nextClicked() {
|
||||||
// save state
|
|
||||||
// mCreateKeyActivity.mPassphrase = new Passphrase(mPassphraseEdit);
|
|
||||||
|
|
||||||
CreateYubiKeyPinRepeatFragment frag = CreateYubiKeyPinRepeatFragment.newInstance();
|
CreateYubiKeyPinRepeatFragment frag = CreateYubiKeyPinRepeatFragment.newInstance();
|
||||||
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
|
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,9 +124,9 @@ public class CreateYubiKeyPinRepeatFragment extends Fragment {
|
|||||||
|
|
||||||
private void nextClicked() {
|
private void nextClicked() {
|
||||||
if (isEditTextNotEmpty(getActivity(), mPin)
|
if (isEditTextNotEmpty(getActivity(), mPin)
|
||||||
&& checkPin(getActivity(), mPin, mCreateKeyActivity.mYubiKeyPin)
|
&& checkPin(getActivity(), mPin, mCreateKeyActivity.mYubiKeyPin.toStringUnsafe())
|
||||||
&& isEditTextNotEmpty(getActivity(), mAdminPin)
|
&& isEditTextNotEmpty(getActivity(), mAdminPin)
|
||||||
&& checkPin(getActivity(), mAdminPin, mCreateKeyActivity.mYubiKeyAdminPin)) {
|
&& checkPin(getActivity(), mAdminPin, mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe())) {
|
||||||
|
|
||||||
CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance();
|
CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance();
|
||||||
hideKeyboard();
|
hideKeyboard();
|
||||||
|
|||||||
@@ -80,16 +80,16 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
|||||||
|
|
||||||
switch (mRequiredInput.mType) {
|
switch (mRequiredInput.mType) {
|
||||||
case NFC_DECRYPT: {
|
case NFC_DECRYPT: {
|
||||||
for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) {
|
for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
|
||||||
byte[] hash = mRequiredInput.mInputHashes[i];
|
byte[] encryptedSessionKey = mRequiredInput.mInputData[i];
|
||||||
byte[] decryptedSessionKey = nfcDecryptSessionKey(hash);
|
byte[] decryptedSessionKey = nfcDecryptSessionKey(encryptedSessionKey);
|
||||||
inputParcel.addCryptoData(hash, decryptedSessionKey);
|
inputParcel.addCryptoData(encryptedSessionKey, decryptedSessionKey);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NFC_SIGN: {
|
case NFC_SIGN: {
|
||||||
for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) {
|
for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
|
||||||
byte[] hash = mRequiredInput.mInputHashes[i];
|
byte[] hash = mRequiredInput.mInputData[i];
|
||||||
int algo = mRequiredInput.mSignAlgos[i];
|
int algo = mRequiredInput.mSignAlgos[i];
|
||||||
byte[] signedHash = nfcCalculateSignature(hash, algo);
|
byte[] signedHash = nfcCalculateSignature(hash, algo);
|
||||||
inputParcel.addCryptoData(hash, signedHash);
|
inputParcel.addCryptoData(hash, signedHash);
|
||||||
@@ -97,6 +97,10 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NFC_MOVE_KEY_TO_CARD: {
|
case NFC_MOVE_KEY_TO_CARD: {
|
||||||
|
// TODO: assume PIN and Admin PIN to be default for this operation
|
||||||
|
mPin = new Passphrase("123456");
|
||||||
|
mAdminPin = new Passphrase("12345678");
|
||||||
|
|
||||||
ProviderHelper providerHelper = new ProviderHelper(this);
|
ProviderHelper providerHelper = new ProviderHelper(this);
|
||||||
CanonicalizedSecretKeyRing secretKeyRing;
|
CanonicalizedSecretKeyRing secretKeyRing;
|
||||||
try {
|
try {
|
||||||
@@ -107,8 +111,11 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
|||||||
throw new IOException("Couldn't find subkey for key to card operation.");
|
throw new IOException("Couldn't find subkey for key to card operation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) {
|
byte[] newPin = mRequiredInput.mInputData[0];
|
||||||
byte[] subkeyBytes = mRequiredInput.mInputHashes[i];
|
byte[] newAdminPin = mRequiredInput.mInputData[1];
|
||||||
|
|
||||||
|
for (int i = 2; i < mRequiredInput.mInputData.length; i++) {
|
||||||
|
byte[] subkeyBytes = mRequiredInput.mInputData[i];
|
||||||
ByteBuffer buf = ByteBuffer.wrap(subkeyBytes);
|
ByteBuffer buf = ByteBuffer.wrap(subkeyBytes);
|
||||||
long subkeyId = buf.getLong();
|
long subkeyId = buf.getLong();
|
||||||
|
|
||||||
@@ -155,8 +162,18 @@ public class NfcOperationActivity extends BaseNfcActivity {
|
|||||||
throw new IOException("Inappropriate key flags for smart card key.");
|
throw new IOException("Inappropriate key flags for smart card key.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Is this really needed?
|
||||||
inputParcel.addCryptoData(subkeyBytes, cardSerialNumber);
|
inputParcel.addCryptoData(subkeyBytes, cardSerialNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change PINs afterwards
|
||||||
|
nfcModifyPIN(0x81, newPin);
|
||||||
|
nfcModifyPIN(0x83, newAdminPin);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new AssertionError("Unhandled mRequiredInput.mType");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -179,8 +179,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
Notify.create(this, getString(R.string.error_nfc_unknown), Style.WARN).show();
|
Notify.create(this, getString(R.string.error_nfc_unknown), Style.WARN).show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
Notify.create(this, getString(R.string.error_nfc, e.getMessage()), Style.WARN).show();
|
Notify.create(this, getString(R.string.error_nfc, e.getMessage()), Style.WARN).show();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -311,9 +313,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
mPw1ValidatedForDecrypt = false;
|
mPw1ValidatedForDecrypt = false;
|
||||||
mPw3Validated = false;
|
mPw3Validated = false;
|
||||||
|
|
||||||
// TODO: Handle non-default Admin PIN
|
|
||||||
mAdminPin = new Passphrase("12345678");
|
|
||||||
|
|
||||||
onNfcPerform();
|
onNfcPerform();
|
||||||
|
|
||||||
mIsoDep.close();
|
mIsoDep.close();
|
||||||
@@ -569,12 +568,12 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
*/
|
*/
|
||||||
public void nfcVerifyPIN(int mode) throws IOException {
|
public void nfcVerifyPIN(int mode) throws IOException {
|
||||||
if (mPin != null || mode == 0x83) {
|
if (mPin != null || mode == 0x83) {
|
||||||
byte[] pin;
|
|
||||||
|
|
||||||
|
byte[] pin;
|
||||||
if (mode == 0x83) {
|
if (mode == 0x83) {
|
||||||
pin = new String(mAdminPin.getCharArray()).getBytes();
|
pin = mAdminPin.toStringUnsafe().getBytes();
|
||||||
} else {
|
} else {
|
||||||
pin = new String(mPin.getCharArray()).getBytes();
|
pin = mPin.toStringUnsafe().getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// SW1/2 0x9000 is the generic "ok" response, which we expect most of the time.
|
// SW1/2 0x9000 is the generic "ok" response, which we expect most of the time.
|
||||||
@@ -611,12 +610,11 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
* @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83.
|
* @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83.
|
||||||
* @param newPinString The new PW1 or PW3.
|
* @param newPinString The new PW1 or PW3.
|
||||||
*/
|
*/
|
||||||
public void nfcModifyPIN(int pw, String newPinString) throws IOException {
|
public void nfcModifyPIN(int pw, byte[] newPin) throws IOException {
|
||||||
final int MAX_PW1_LENGTH_INDEX = 1;
|
final int MAX_PW1_LENGTH_INDEX = 1;
|
||||||
final int MAX_PW3_LENGTH_INDEX = 3;
|
final int MAX_PW3_LENGTH_INDEX = 3;
|
||||||
|
|
||||||
byte[] pwStatusBytes = nfcGetPwStatusBytes();
|
byte[] pwStatusBytes = nfcGetPwStatusBytes();
|
||||||
byte[] newPin = newPinString.getBytes();
|
|
||||||
|
|
||||||
if (pw == 0x81) {
|
if (pw == 0x81) {
|
||||||
if (newPin.length < 6 || newPin.length > pwStatusBytes[MAX_PW1_LENGTH_INDEX]) {
|
if (newPin.length < 6 || newPin.length > pwStatusBytes[MAX_PW1_LENGTH_INDEX]) {
|
||||||
@@ -631,11 +629,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
byte[] pin;
|
byte[] pin;
|
||||||
|
|
||||||
if (pw == 0x83) {
|
if (pw == 0x83) {
|
||||||
pin = new String(mAdminPin.getCharArray()).getBytes();
|
pin = mAdminPin.toStringUnsafe().getBytes();
|
||||||
} else {
|
} else {
|
||||||
pin = new String(mPin.getCharArray()).getBytes();
|
pin = mPin.toStringUnsafe().getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command APDU for CHANGE REFERENCE DATA command (page 32)
|
// Command APDU for CHANGE REFERENCE DATA command (page 32)
|
||||||
@@ -700,7 +697,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
throw new IOException("Invalid key slot");
|
throw new IOException("Invalid key slot");
|
||||||
}
|
}
|
||||||
|
|
||||||
RSAPrivateCrtKey crtSecretKey = null;
|
RSAPrivateCrtKey crtSecretKey;
|
||||||
try {
|
try {
|
||||||
secretKey.unlock(passphrase);
|
secretKey.unlock(passphrase);
|
||||||
crtSecretKey = secretKey.getCrtSecretKey();
|
crtSecretKey = secretKey.getCrtSecretKey();
|
||||||
@@ -719,7 +716,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mPw3Validated) {
|
if (!mPw3Validated) {
|
||||||
nfcVerifyPIN(0x83); // (Verify PW1 with mode 83)
|
nfcVerifyPIN(0x83); // (Verify PW3 with mode 83)
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] header= Hex.decode(
|
byte[] header= Hex.decode(
|
||||||
|
|||||||
@@ -117,6 +117,13 @@ public class Passphrase implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new String from the char[]. This is considered unsafe!
|
||||||
|
*/
|
||||||
|
public String toStringUnsafe() {
|
||||||
|
return new String(mPassphrase);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@@ -127,11 +134,7 @@ public class Passphrase implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Passphrase that = (Passphrase) o;
|
Passphrase that = (Passphrase) o;
|
||||||
if (!Arrays.equals(mPassphrase, that.mPassphrase)) {
|
return Arrays.equals(mPassphrase, that.mPassphrase);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -342,6 +342,8 @@
|
|||||||
<string name="progress_modify_subkeystrip">"stripping subkeys…"</string>
|
<string name="progress_modify_subkeystrip">"stripping subkeys…"</string>
|
||||||
<string name="progress_modify_subkeyadd">"adding subkeys…"</string>
|
<string name="progress_modify_subkeyadd">"adding subkeys…"</string>
|
||||||
<string name="progress_modify_passphrase">"changing password…"</string>
|
<string name="progress_modify_passphrase">"changing password…"</string>
|
||||||
|
<string name="progress_modify_pin">"changing PIN…"</string>
|
||||||
|
<string name="progress_modify_admin_pin">"changing Admin PIN…"</string>
|
||||||
|
|
||||||
<plurals name="progress_exporting_key">
|
<plurals name="progress_exporting_key">
|
||||||
<item quantity="one">"exporting key…"</item>
|
<item quantity="one">"exporting key…"</item>
|
||||||
@@ -660,7 +662,7 @@
|
|||||||
<string name="create_key_add_email_text">"Additional email addresses are also associated to this key and can be used for secure communication."</string>
|
<string name="create_key_add_email_text">"Additional email addresses are also associated to this key and can be used for secure communication."</string>
|
||||||
<string name="create_key_email_already_exists_text">"Email address has already been added"</string>
|
<string name="create_key_email_already_exists_text">"Email address has already been added"</string>
|
||||||
<string name="create_key_email_invalid_email">"Email address format is invalid"</string>
|
<string name="create_key_email_invalid_email">"Email address format is invalid"</string>
|
||||||
<string name="create_key_yubi_key_pin_text">"Please remember these PINs. They are required to use your YubiKey later. If possible write down the Admin PIN and store it in a safe place."</string>
|
<string name="create_key_yubi_key_pin_text">"Please remember the PIN, it is required to use your YubiKey later. Please write down the Admin PIN and store it in a safe place."</string>
|
||||||
<string name="create_key_yubi_key_pin">"PIN"</string>
|
<string name="create_key_yubi_key_pin">"PIN"</string>
|
||||||
<string name="create_key_yubi_key_admin_pin">"Admin PIN"</string>
|
<string name="create_key_yubi_key_admin_pin">"Admin PIN"</string>
|
||||||
<string name="create_key_yubi_key_pin_repeat_text">"Please enter the PIN and Admin PIN to proceed."</string>
|
<string name="create_key_yubi_key_pin_repeat_text">"Please enter the PIN and Admin PIN to proceed."</string>
|
||||||
@@ -957,6 +959,8 @@
|
|||||||
<string name="msg_mf_notation_empty">"Adding empty notation packet"</string>
|
<string name="msg_mf_notation_empty">"Adding empty notation packet"</string>
|
||||||
<string name="msg_mf_notation_pin">"Adding PIN notation packet"</string>
|
<string name="msg_mf_notation_pin">"Adding PIN notation packet"</string>
|
||||||
<string name="msg_mf_passphrase">"Changing password for keyring"</string>
|
<string name="msg_mf_passphrase">"Changing password for keyring"</string>
|
||||||
|
<string name="msg_mf_pin">"Changing PIN on card"</string>
|
||||||
|
<string name="msg_mf_admin_pin">"Changing Admin PIN on card"</string>
|
||||||
<string name="msg_mf_passphrase_key">"Re-encrypting subkey %s with new password"</string>
|
<string name="msg_mf_passphrase_key">"Re-encrypting subkey %s with new password"</string>
|
||||||
<string name="msg_mf_passphrase_empty_retry">"Setting new password failed, trying again with empty old password"</string>
|
<string name="msg_mf_passphrase_empty_retry">"Setting new password failed, trying again with empty old password"</string>
|
||||||
<string name="msg_mf_passphrase_fail">"Password for subkey could not be changed! (Does it have a different one from the other keys?)"</string>
|
<string name="msg_mf_passphrase_fail">"Password for subkey could not be changed! (Does it have a different one from the other keys?)"</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user