support yubikeys in (some) edit key operations

This commit is contained in:
Vincent Breitmoser 2015-03-20 02:27:05 +01:00
parent 25d89b5550
commit 3b04636f5d
17 changed files with 295 additions and 247 deletions

View File

@ -83,7 +83,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
String passphrase = parcel.mCryptoInput.getPassphrase(); char[] 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);
@ -103,7 +103,7 @@ public class CertifyOperation extends BaseOperation {
int certifyOk = 0, certifyError = 0, uploadOk = 0, uploadError = 0; int certifyOk = 0, certifyError = 0, uploadOk = 0, uploadError = 0;
NfcSignOperationsBuilder allRequiredInput = new NfcSignOperationsBuilder(parcel.getSignatureTime()); NfcSignOperationsBuilder allRequiredInput = new NfcSignOperationsBuilder(parcel.mCryptoInput.getSignatureTime());
// Work through all requested certifications // Work through all requested certifications
for (CertifyAction action : parcel.mCertifyActions) { for (CertifyAction action : parcel.mCertifyActions) {
@ -127,7 +127,7 @@ public class CertifyOperation extends BaseOperation {
PgpCertifyOperation op = new PgpCertifyOperation(); PgpCertifyOperation op = new PgpCertifyOperation();
PgpCertifyResult result = op.certify(certificationKey, publicRing, PgpCertifyResult result = op.certify(certificationKey, publicRing,
log, 2, action, parcel.getSignatureData(), parcel.getSignatureTime()); log, 2, action, parcel.getSignatureData(), parcel.mCryptoInput.getSignatureTime());
if (!result.success()) { if (!result.success()) {
certifyError += 1; certifyError += 1;

View File

@ -21,6 +21,7 @@ import android.content.Context;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
@ -34,6 +35,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; 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.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.ProgressScaler;
@ -55,7 +57,7 @@ public class EditKeyOperation extends BaseOperation {
super(context, providerHelper, progressable, cancelled); super(context, providerHelper, progressable, cancelled);
} }
public EditKeyResult execute(SaveKeyringParcel saveParcel, String passphrase) { public OperationResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) {
OperationLog log = new OperationLog(); OperationLog log = new OperationLog();
log.add(LogType.MSG_ED, 0); log.add(LogType.MSG_ED, 0);
@ -69,7 +71,7 @@ public class EditKeyOperation extends BaseOperation {
PgpEditKeyResult modifyResult; PgpEditKeyResult modifyResult;
{ {
PgpKeyOperation keyOperations = PgpKeyOperation keyOperations =
new PgpKeyOperation(new ProgressScaler(mProgressable, 10, 60, 100), mCancelled); new PgpKeyOperation(new ProgressScaler(mProgressable, 10, 60, 100), mCancelled, cryptoInput);
// If a key id is specified, fetch and edit // If a key id is specified, fetch and edit
if (saveParcel.mMasterKeyId != null) { if (saveParcel.mMasterKeyId != null) {
@ -80,7 +82,10 @@ public class EditKeyOperation extends BaseOperation {
CanonicalizedSecretKeyRing secRing = CanonicalizedSecretKeyRing secRing =
mProviderHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId); mProviderHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase); modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel);
if (modifyResult.isPending()) {
return modifyResult;
}
} catch (NotFoundException e) { } catch (NotFoundException e) {
log.add(LogType.MSG_ED_ERROR_KEY_NOT_FOUND, 2); log.add(LogType.MSG_ED_ERROR_KEY_NOT_FOUND, 2);

View File

@ -11,66 +11,35 @@ public class InputPendingResult extends OperationResult {
// the fourth bit indicates a "data pending" result! (it's also a form of non-success) // the fourth bit indicates a "data pending" result! (it's also a form of non-success)
public static final int RESULT_PENDING = RESULT_ERROR + 8; public static final int RESULT_PENDING = RESULT_ERROR + 8;
public static final int RESULT_PENDING_PASSPHRASE = RESULT_PENDING + 16;
public static final int RESULT_PENDING_NFC = RESULT_PENDING + 32;
final RequiredInputParcel mRequiredInput; final RequiredInputParcel mRequiredInput;
final Long mKeyIdPassphraseNeeded;
public InputPendingResult(int result, OperationLog log) { public InputPendingResult(int result, OperationLog log) {
super(result, log); super(result, log);
mRequiredInput = null; mRequiredInput = null;
mKeyIdPassphraseNeeded = null;
} }
public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput) { public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput) {
super(RESULT_PENDING_NFC, log); super(RESULT_PENDING, log);
mRequiredInput = requiredInput; mRequiredInput = requiredInput;
mKeyIdPassphraseNeeded = null;
}
public InputPendingResult(OperationLog log, long keyIdPassphraseNeeded) {
super(RESULT_PENDING_PASSPHRASE, log);
mRequiredInput = null;
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
} }
public InputPendingResult(Parcel source) { public InputPendingResult(Parcel source) {
super(source); super(source);
mRequiredInput = source.readParcelable(getClass().getClassLoader()); mRequiredInput = source.readParcelable(getClass().getClassLoader());
mKeyIdPassphraseNeeded = source.readInt() != 0 ? source.readLong() : null;
} }
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
dest.writeParcelable(mRequiredInput, 0); dest.writeParcelable(mRequiredInput, 0);
if (mKeyIdPassphraseNeeded != null) {
dest.writeInt(1);
dest.writeLong(mKeyIdPassphraseNeeded);
} else {
dest.writeInt(0);
}
} }
public boolean isPending() { public boolean isPending() {
return (mResult & RESULT_PENDING) == RESULT_PENDING; return (mResult & RESULT_PENDING) == RESULT_PENDING;
} }
public boolean isNfcPending() {
return (mResult & RESULT_PENDING_NFC) == RESULT_PENDING_NFC;
}
public boolean isPassphrasePending() {
return (mResult & RESULT_PENDING_PASSPHRASE) == RESULT_PENDING_PASSPHRASE;
}
public RequiredInputParcel getRequiredInputParcel() { public RequiredInputParcel getRequiredInputParcel() {
return mRequiredInput; return mRequiredInput;
} }
public long getPassphraseKeyId() {
return mKeyIdPassphraseNeeded;
}
} }

View File

@ -512,6 +512,7 @@ public abstract class OperationResult implements Parcelable {
// secret key modify // secret key modify
MSG_MF (LogLevel.START, R.string.msg_mr), MSG_MF (LogLevel.START, R.string.msg_mr),
MSG_MF_DIVERT (LogLevel.DEBUG, R.string.msg_mf_divert),
MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial), MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial),
MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode), MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode),
MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint), MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint),
@ -529,6 +530,7 @@ public abstract class OperationResult implements Parcelable {
MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary), MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig), MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig),
MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing), MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing),
MSG_MF_INPUT_REQUIRED (LogLevel.OK, R.string.msg_mf_input_required),
MSG_MF_MASTER (LogLevel.DEBUG, R.string.msg_mf_master), MSG_MF_MASTER (LogLevel.DEBUG, R.string.msg_mf_master),
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),
@ -596,7 +598,6 @@ public abstract class OperationResult implements Parcelable {
MSG_PR_SUCCESS (LogLevel.OK, R.string.msg_pr_success), MSG_PR_SUCCESS (LogLevel.OK, R.string.msg_pr_success),
// messages used in UI code // messages used in UI code
MSG_EK_ERROR_DIVERT (LogLevel.ERROR, R.string.msg_ek_error_divert),
MSG_EK_ERROR_DUMMY (LogLevel.ERROR, R.string.msg_ek_error_dummy), MSG_EK_ERROR_DUMMY (LogLevel.ERROR, R.string.msg_ek_error_dummy),
MSG_EK_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_ek_error_not_found), MSG_EK_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_ek_error_not_found),

View File

@ -22,8 +22,10 @@ import android.os.Parcel;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
public class PgpEditKeyResult extends OperationResult {
public class PgpEditKeyResult extends InputPendingResult {
private transient UncachedKeyRing mRing; private transient UncachedKeyRing mRing;
public final long mRingMasterKeyId; public final long mRingMasterKeyId;
@ -35,6 +37,11 @@ public class PgpEditKeyResult extends OperationResult {
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none; mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
} }
public PgpEditKeyResult(OperationLog log, RequiredInputParcel requiredInput) {
super(log, requiredInput);
mRingMasterKeyId = Constants.key.none;
}
public UncachedKeyRing getRing() { public UncachedKeyRing getRing() {
return mRing; return mRing;
} }

View File

@ -149,10 +149,14 @@ 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(String passphrase) throws PgpGeneralException { public boolean unlock(char[] 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
@ -164,7 +168,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.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED; mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED;
} catch (PGPException e) { } catch (PGPException e) {

View File

@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.S2K;
import org.spongycastle.bcpg.sig.Features; import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec; import org.spongycastle.jce.spec.ElGamalParameterSpec;
@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.PGPDataDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculator; import org.spongycastle.openpgp.operator.PGPDigestCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
@ -43,6 +44,8 @@ import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBu
import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
@ -54,6 +57,9 @@ 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.service.SaveKeyringParcel.Curve; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
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.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@ -85,9 +91,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
* This indicator may be null. * This indicator may be null.
*/ */
public class PgpKeyOperation { public class PgpKeyOperation {
private Stack<Progressable> mProgress; private Stack<Progressable> mProgress;
private AtomicBoolean mCancelled; private AtomicBoolean mCancelled;
NfcSignOperationsBuilder mNfcSignOps;
private CryptoInputParcel mCryptoInput;
public PgpKeyOperation(Progressable progress) { public PgpKeyOperation(Progressable progress) {
super(); super();
if (progress != null) { if (progress != null) {
@ -96,9 +106,11 @@ public class PgpKeyOperation {
} }
} }
public PgpKeyOperation(Progressable progress, AtomicBoolean cancelled) { public PgpKeyOperation(Progressable progress, AtomicBoolean cancelled, CryptoInputParcel cryptoInput) {
this(progress); this(progress);
mCancelled = cancelled; mCancelled = cancelled;
mNfcSignOps = new NfcSignOperationsBuilder(cryptoInput.getSignatureTime());
mCryptoInput = cryptoInput;
} }
private boolean checkCancelled() { private boolean checkCancelled() {
@ -316,7 +328,8 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator()); masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
subProgressPush(50, 100); subProgressPush(50, 100);
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log); CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date(), "");
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, log);
} catch (PGPException e) { } catch (PGPException e) {
log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent); log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
@ -347,8 +360,8 @@ public class PgpKeyOperation {
* namely stripping of subkeys and changing the protection mode of dummy keys. * namely stripping of subkeys and changing the protection mode of dummy keys.
* *
*/ */
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR,
String passphrase) { SaveKeyringParcel saveParcel) {
OperationLog log = new OperationLog(); OperationLog log = new OperationLog();
int indent = 0; int indent = 0;
@ -386,11 +399,16 @@ public class PgpKeyOperation {
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
} }
// If we have no passphrase, only allow restricted operation if (saveParcel.isRestrictedOnly()) {
if (passphrase == null) {
return internalRestricted(sKR, saveParcel, log); return internalRestricted(sKR, saveParcel, log);
} }
// Do we require a passphrase? If so, pass it along
if (!isDivertToCard(masterSecretKey) && !mCryptoInput.hasPassphrase()) {
return new PgpEditKeyResult(log, RequiredInputParcel.createRequiredPassphrase(
masterSecretKey.getKeyID(), mCryptoInput.getSignatureTime()));
}
// read masterKeyFlags, and use the same as before. // read masterKeyFlags, and use the same as before.
// since this is the master key, this contains at least CERTIFY_OTHER // since this is the master key, this contains at least CERTIFY_OTHER
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
@ -398,13 +416,13 @@ public class PgpKeyOperation {
Date expiryTime = wsKR.getPublicKey().getExpiryTime(); Date expiryTime = wsKR.getPublicKey().getExpiryTime();
long masterKeyExpiry = expiryTime != null ? expiryTime.getTime() / 1000 : 0L; long masterKeyExpiry = expiryTime != null ? expiryTime.getTime() / 1000 : 0L;
return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log); return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, log);
} }
private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey, private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
int masterKeyFlags, long masterKeyExpiry, int masterKeyFlags, long masterKeyExpiry,
SaveKeyringParcel saveParcel, String passphrase, SaveKeyringParcel saveParcel,
OperationLog log) { OperationLog log) {
int indent = 1; int indent = 1;
@ -413,18 +431,25 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
// 1. Unlock private key
progress(R.string.progress_modify_unlock, 10);
log.add(LogType.MSG_MF_UNLOCK, indent);
PGPPrivateKey masterPrivateKey; PGPPrivateKey masterPrivateKey;
{
try { if (isDivertToCard(masterSecretKey)) {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( masterPrivateKey = null;
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); log.add(LogType.MSG_MF_DIVERT, indent);
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); } else {
} catch (PGPException e) {
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1); // 1. Unlock private key
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); progress(R.string.progress_modify_unlock, 10);
log.add(LogType.MSG_MF_UNLOCK, indent);
{
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mCryptoInput.getPassphrase());
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
}
} }
} }
@ -479,9 +504,16 @@ public class PgpKeyOperation {
boolean isPrimary = saveParcel.mChangePrimaryUserId != null boolean isPrimary = saveParcel.mChangePrimaryUserId != null
&& userId.equals(saveParcel.mChangePrimaryUserId); && userId.equals(saveParcel.mChangePrimaryUserId);
// generate and add new certificate // generate and add new certificate
PGPSignature cert = generateUserIdSignature(masterPrivateKey, try {
masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry); PGPSignature cert = generateUserIdSignature(
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert); getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, userId,
isPrimary, masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
} }
subProgressPop(); subProgressPop();
@ -508,9 +540,15 @@ public class PgpKeyOperation {
PGPUserAttributeSubpacketVector vector = attribute.getVector(); PGPUserAttributeSubpacketVector vector = attribute.getVector();
// generate and add new certificate // generate and add new certificate
PGPSignature cert = generateUserAttributeSignature(masterPrivateKey, try {
masterPublicKey, vector); PGPSignature cert = generateUserAttributeSignature(
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert); getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, vector);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
} }
subProgressPop(); subProgressPop();
@ -538,9 +576,15 @@ public class PgpKeyOperation {
// a duplicate revocation will be removed during canonicalization, so no need to // a duplicate revocation will be removed during canonicalization, so no need to
// take care of that here. // take care of that here.
PGPSignature cert = generateRevocationSignature(masterPrivateKey, try {
masterPublicKey, userId); PGPSignature cert = generateRevocationSignature(
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert); getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, userId);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
} }
subProgressPop(); subProgressPop();
@ -610,11 +654,18 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent); log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
modifiedPublicKey = PGPPublicKey.removeCertification( modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert); modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature( try {
masterPrivateKey, masterPublicKey, userId, false, PGPSignature newCert = generateUserIdSignature(
masterKeyFlags, masterKeyExpiry); getSignatureGenerator(masterSecretKey, mCryptoInput),
modifiedPublicKey = PGPPublicKey.addCertification( mCryptoInput.getSignatureTime(),
modifiedPublicKey, userId, newCert); masterPrivateKey, masterPublicKey, userId, false,
masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
continue; continue;
} }
@ -626,11 +677,17 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_PRIMARY_NEW, indent); log.add(LogType.MSG_MF_PRIMARY_NEW, indent);
modifiedPublicKey = PGPPublicKey.removeCertification( modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert); modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature( try {
masterPrivateKey, masterPublicKey, userId, true, PGPSignature newCert = generateUserIdSignature(
masterKeyFlags, masterKeyExpiry); getSignatureGenerator(masterSecretKey, mCryptoInput),
modifiedPublicKey = PGPPublicKey.addCertification( mCryptoInput.getSignatureTime(),
modifiedPublicKey, userId, newCert); masterPrivateKey, masterPublicKey, userId, true,
masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
ok = true; ok = true;
} }
@ -717,7 +774,8 @@ public class PgpKeyOperation {
} }
PGPPublicKey pKey = PGPPublicKey pKey =
updateMasterCertificates(masterPrivateKey, masterPublicKey, updateMasterCertificates(
masterSecretKey, masterPrivateKey, masterPublicKey,
flags, expiry, indent, log); flags, expiry, indent, log);
if (pKey == null) { if (pKey == null) {
// error log entry has already been added by updateMasterCertificates itself // error log entry has already been added by updateMasterCertificates itself
@ -755,9 +813,16 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.removeCertification(pKey, sig); pKey = PGPPublicKey.removeCertification(pKey, sig);
} }
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
mCryptoInput.getPassphrase());
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
PGPSignature sig = generateSubkeyBindingSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry);
// generate and add new signature // generate and add new signature
PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
sKey, pKey, flags, expiry, passphrase);
pKey = PGPPublicKey.addCertification(pKey, sig); pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey)); sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
} }
@ -781,10 +846,17 @@ public class PgpKeyOperation {
PGPPublicKey pKey = sKey.getPublicKey(); PGPPublicKey pKey = sKey.getPublicKey();
// generate and add new signature // generate and add new signature
PGPSignature sig = generateRevocationSignature(masterPublicKey, masterPrivateKey, pKey); try {
PGPSignature sig = generateRevocationSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPublicKey, masterPrivateKey, pKey);
pKey = PGPPublicKey.addCertification(pKey, sig); pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey)); sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
} }
subProgressPop(); subProgressPop();
@ -827,19 +899,29 @@ public class PgpKeyOperation {
// add subkey binding signature (making this a sub rather than master key) // add subkey binding signature (making this a sub rather than master key)
PGPPublicKey pKey = keyPair.getPublicKey(); PGPPublicKey pKey = keyPair.getPublicKey();
PGPSignature cert = generateSubkeyBindingSignature( try {
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey, PGPSignature cert = generateSubkeyBindingSignature(
add.mFlags, add.mExpiry); getSignatureGenerator(masterSecretKey, mCryptoInput),
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert); mCryptoInput.getSignatureTime(),
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
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.toCharArray()); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
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);
@ -867,7 +949,7 @@ public class PgpKeyOperation {
indent += 1; indent += 1;
sKR = applyNewUnlock(sKR, masterPublicKey, masterPrivateKey, sKR = applyNewUnlock(sKR, masterPublicKey, masterPrivateKey,
passphrase, saveParcel.mNewUnlock, log, indent); mCryptoInput.getPassphrase(), saveParcel.mNewUnlock, log, indent);
if (sKR == null) { if (sKR == null) {
// The error has been logged above, just return a bad state // The error has been logged above, just return a bad state
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
@ -891,6 +973,12 @@ public class PgpKeyOperation {
} }
progress(R.string.progress_done, 100); progress(R.string.progress_done, 100);
if (!mNfcSignOps.isEmpty()) {
log.add(LogType.MSG_MF_INPUT_REQUIRED, indent);
return new PgpEditKeyResult(log, mNfcSignOps.build());
}
log.add(LogType.MSG_MF_SUCCESS, indent); log.add(LogType.MSG_MF_SUCCESS, indent);
return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR)); return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));
@ -967,7 +1055,7 @@ public class PgpKeyOperation {
PGPSecretKeyRing sKR, PGPSecretKeyRing sKR,
PGPPublicKey masterPublicKey, PGPPublicKey masterPublicKey,
PGPPrivateKey masterPrivateKey, PGPPrivateKey masterPrivateKey,
String passphrase, char[] passphrase,
ChangeUnlockParcel newUnlock, ChangeUnlockParcel newUnlock,
OperationLog log, int indent) throws PGPException { OperationLog log, int indent) throws PGPException {
@ -1051,14 +1139,14 @@ public class PgpKeyOperation {
private static PGPSecretKeyRing applyNewPassphrase( private static PGPSecretKeyRing applyNewPassphrase(
PGPSecretKeyRing sKR, PGPSecretKeyRing sKR,
PGPPublicKey masterPublicKey, PGPPublicKey masterPublicKey,
String passphrase, char[] passphrase,
String newPassphrase, String 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.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
// 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,
@ -1115,8 +1203,9 @@ public class PgpKeyOperation {
} }
/** Update all (non-revoked) uid signatures with new flags and expiry time. */ /** Update all (non-revoked) uid signatures with new flags and expiry time. */
private static PGPPublicKey updateMasterCertificates( private PGPPublicKey updateMasterCertificates(
PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey, PGPSecretKey masterSecretKey, PGPPrivateKey masterPrivateKey,
PGPPublicKey masterPublicKey,
int flags, long expiry, int indent, OperationLog log) int flags, long expiry, int indent, OperationLog log)
throws PGPException, IOException, SignatureException { throws PGPException, IOException, SignatureException {
@ -1172,10 +1261,16 @@ public class PgpKeyOperation {
currentCert.getHashedSubPackets().isPrimaryUserID(); currentCert.getHashedSubPackets().isPrimaryUserID();
modifiedPublicKey = PGPPublicKey.removeCertification( modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert); modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature( try {
masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry); PGPSignature newCert = generateUserIdSignature(
modifiedPublicKey = PGPPublicKey.addCertification( getSignatureGenerator(masterSecretKey, mCryptoInput),
modifiedPublicKey, userId, newCert); mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
ok = true; ok = true;
} }
@ -1190,15 +1285,37 @@ public class PgpKeyOperation {
} }
private static PGPSignature generateUserIdSignature( private static PGPSignatureGenerator getSignatureGenerator(
PGPSecretKey secretKey, CryptoInputParcel cryptoInput) {
PGPContentSignerBuilder builder;
S2K s2k = secretKey.getS2K();
if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
&& s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
// use synchronous "NFC based" SignerBuilder
builder = new NfcSyncPGPContentSignerBuilder(
secretKey.getPublicKey().getAlgorithm(),
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
secretKey.getKeyID(), cryptoInput.getCryptoData())
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
} else {
// content signer based on signing key algorithm and chosen hash algorithm
builder = new JcaPGPContentSignerBuilder(
secretKey.getPublicKey().getAlgorithm(),
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
}
return new PGPSignatureGenerator(builder);
}
private PGPSignature generateUserIdSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary,
int flags, long expiry) int flags, long expiry)
throws IOException, PGPException, SignatureException { throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{ {
@ -1222,7 +1339,7 @@ public class PgpKeyOperation {
hashedPacketsGen.setPrimaryUserID(false, primary); hashedPacketsGen.setPrimaryUserID(false, primary);
/* critical subpackets: we consider those important for a modern pgp implementation */ /* critical subpackets: we consider those important for a modern pgp implementation */
hashedPacketsGen.setSignatureCreationTime(true, new Date()); hashedPacketsGen.setSignatureCreationTime(true, creationTime);
// Request that senders add the MDC to the message (authenticate unsigned messages) // Request that senders add the MDC to the message (authenticate unsigned messages)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
hashedPacketsGen.setKeyFlags(true, flags); hashedPacketsGen.setKeyFlags(true, flags);
@ -1238,19 +1355,15 @@ public class PgpKeyOperation {
} }
private static PGPSignature generateUserAttributeSignature( private static PGPSignature generateUserAttributeSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey,
PGPUserAttributeSubpacketVector vector) PGPUserAttributeSubpacketVector vector)
throws IOException, PGPException, SignatureException { throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
{ {
/* critical subpackets: we consider those important for a modern pgp implementation */ /* critical subpackets: we consider those important for a modern pgp implementation */
hashedPacketsGen.setSignatureCreationTime(true, new Date()); hashedPacketsGen.setSignatureCreationTime(true, creationTime);
} }
sGen.setHashedSubpackets(hashedPacketsGen.generate()); sGen.setHashedSubpackets(hashedPacketsGen.generate());
@ -1259,29 +1372,24 @@ public class PgpKeyOperation {
} }
private static PGPSignature generateRevocationSignature( private static PGPSignature generateRevocationSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId) PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
throws IOException, PGPException, SignatureException { throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(true, new Date()); subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate()); sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey); sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey); return sGen.generateCertification(userId, pKey);
} }
private static PGPSignature generateRevocationSignature( private static PGPSignature generateRevocationSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey) PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException { throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(true, new Date()); subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate()); sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness // Generate key revocation or subkey revocation, depending on master/subkey-ness
if (masterPublicKey.getKeyID() == pKey.getKeyID()) { if (masterPublicKey.getKeyID() == pKey.getKeyID()) {
@ -1293,26 +1401,12 @@ public class PgpKeyOperation {
} }
} }
private static PGPSignature generateSubkeyBindingSignature(
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, String passphrase)
throws IOException, PGPException, SignatureException {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
passphrase.toCharArray());
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey,
pKey, flags, expiry);
}
static PGPSignature generateSubkeyBindingSignature( static PGPSignature generateSubkeyBindingSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry) PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
throws IOException, PGPException, SignatureException { throws IOException, PGPException, SignatureException {
// date for signing
Date creationTime = new Date();
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
// If this key can sign, we need a primary key binding signature // If this key can sign, we need a primary key binding signature
@ -1323,10 +1417,10 @@ public class PgpKeyOperation {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO) pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey); subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
sGen.setHashedSubpackets(subHashedPacketsGen.generate()); subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey); PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
unhashedPacketsGen.setEmbeddedSignature(true, certification); unhashedPacketsGen.setEmbeddedSignature(true, certification);
} }
@ -1341,10 +1435,6 @@ public class PgpKeyOperation {
} }
} }
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey); sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
sGen.setHashedSubpackets(hashedPacketsGen.generate()); sGen.setHashedSubpackets(hashedPacketsGen.generate());
sGen.setUnhashedSubpackets(unhashedPacketsGen.generate()); sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
@ -1371,4 +1461,10 @@ public class PgpKeyOperation {
return flags; return flags;
} }
private static boolean isDivertToCard(PGPSecretKey secretKey) {
S2K s2k = secretKey.getS2K();
return s2k.getType() == S2K.GNU_DUMMY_S2K
&& s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD;
}
} }

View File

@ -76,10 +76,6 @@ public class CertifyActionsParcel implements Parcelable {
return mCryptoInput.getCryptoData(); return mCryptoInput.getCryptoData();
} }
public Date getSignatureTime() {
return mCryptoInput.getSignatureTime();
}
public static final Creator<CertifyActionsParcel> CREATOR = new Creator<CertifyActionsParcel>() { public static final Creator<CertifyActionsParcel> CREATOR = new Creator<CertifyActionsParcel>() {
public CertifyActionsParcel createFromParcel(final Parcel source) { public CertifyActionsParcel createFromParcel(final Parcel source) {
return new CertifyActionsParcel(source); return new CertifyActionsParcel(source);

View File

@ -61,6 +61,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.FileHelper; 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;
@ -160,6 +161,7 @@ public class KeychainIntentService extends IntentService implements Progressable
// save keyring // save keyring
public static final String EDIT_KEYRING_PARCEL = "save_parcel"; public static final String EDIT_KEYRING_PARCEL = "save_parcel";
public static final String EDIT_KEYRING_PASSPHRASE = "passphrase"; public static final String EDIT_KEYRING_PASSPHRASE = "passphrase";
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
// delete keyring(s) // delete keyring(s)
public static final String DELETE_KEY_LIST = "delete_list"; public static final String DELETE_KEY_LIST = "delete_list";
@ -469,11 +471,11 @@ public class KeychainIntentService extends IntentService implements Progressable
// Input // Input
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation // Operation
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);
EditKeyResult result = op.execute(saveParcel, passphrase); OperationResult result = op.execute(saveParcel, cryptoInput);
// Result // Result
sendMessageToHandler(MessageStatus.OKAY, result); sendMessageToHandler(MessageStatus.OKAY, result);

View File

@ -81,8 +81,8 @@ public class CryptoInputParcel implements Parcelable {
return mPassphrase != null; return mPassphrase != null;
} }
public String getPassphrase() { public char[] getPassphrase() {
return mPassphrase; return mPassphrase == null ? null : mPassphrase.toCharArray();
} }
public static final Creator<CryptoInputParcel> CREATOR = new Creator<CryptoInputParcel>() { public static final Creator<CryptoInputParcel> CREATOR = new Creator<CryptoInputParcel>() {
@ -95,4 +95,19 @@ public class CryptoInputParcel implements Parcelable {
} }
}; };
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("CryptoInput: { ");
b.append(mSignatureTime).append(" ");
if (mPassphrase != null) {
b.append("passphrase");
}
if (mCryptoData != null) {
b.append(mCryptoData.size());
b.append(" hashes ");
}
b.append("}");
return b.toString();
}
} }

View File

@ -15,9 +15,13 @@ public class RequiredInputParcel implements Parcelable {
} }
public Date mSignatureTime; public Date mSignatureTime;
public final RequiredInputType mType; public final RequiredInputType mType;
public String mNfcPin = "123456";
public final byte[][] mInputHashes; public final byte[][] mInputHashes;
public final int[] mSignAlgos; public final int[] mSignAlgos;
private Long mSubKeyId; private Long mSubKeyId;
private RequiredInputParcel(RequiredInputType type, byte[][] inputHashes, private RequiredInputParcel(RequiredInputType type, byte[][] inputHashes,

View File

@ -9,6 +9,7 @@ import android.support.v4.app.Fragment;
import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
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;
@ -25,7 +26,6 @@ public abstract class CryptoOperationFragment extends Fragment {
case NFC_DECRYPT: case NFC_DECRYPT:
case NFC_SIGN: { case NFC_SIGN: {
Intent intent = new Intent(getActivity(), NfcOperationActivity.class); Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456");
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
startActivityForResult(intent, REQUEST_CODE_NFC); startActivityForResult(intent, REQUEST_CODE_NFC);
return; return;
@ -76,10 +76,14 @@ public abstract class CryptoOperationFragment extends Fragment {
if (message.arg1 == MessageStatus.OKAY.ordinal()) { if (message.arg1 == MessageStatus.OKAY.ordinal()) {
Bundle data = message.getData(); Bundle data = message.getData();
InputPendingResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); OperationResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
if (result == null || ! (result instanceof InputPendingResult)) {
return false;
}
if (result != null && result.isPending()) { InputPendingResult pendingResult = (InputPendingResult) result;
RequiredInputParcel requiredInput = result.getRequiredInputParcel(); if (pendingResult.isPending()) {
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
initiateInputActivity(requiredInput); initiateInputActivity(requiredInput);
return true; return true;
} }

View File

@ -17,6 +17,8 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.Date;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
@ -51,10 +53,10 @@ 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.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
@ -68,14 +70,12 @@ 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;
public class EditKeyFragment extends LoaderFragment implements public class EditKeyFragment extends CryptoOperationFragment implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri"; public static final String ARG_DATA_URI = "uri";
public static final String ARG_SAVE_KEYRING_PARCEL = "save_keyring_parcel"; public static final String ARG_SAVE_KEYRING_PARCEL = "save_keyring_parcel";
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
private ListView mUserIdsList; private ListView mUserIdsList;
private ListView mSubkeysList; private ListView mSubkeysList;
private ListView mUserIdsAddedList; private ListView mUserIdsAddedList;
@ -100,7 +100,6 @@ public class EditKeyFragment extends LoaderFragment implements
private SaveKeyringParcel mSaveKeyringParcel; private SaveKeyringParcel mSaveKeyringParcel;
private String mPrimaryUserId; private String mPrimaryUserId;
private String mCurrentPassphrase;
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
@ -129,8 +128,7 @@ public class EditKeyFragment extends LoaderFragment implements
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
View root = super.onCreateView(inflater, superContainer, savedInstanceState); View view = inflater.inflate(R.layout.edit_key_fragment, null);
View view = inflater.inflate(R.layout.edit_key_fragment, getContainer());
mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids); mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids);
mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys); mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys);
@ -140,7 +138,7 @@ public class EditKeyFragment extends LoaderFragment implements
mAddUserId = view.findViewById(R.id.edit_key_action_add_user_id); mAddUserId = view.findViewById(R.id.edit_key_action_add_user_id);
mAddSubkey = view.findViewById(R.id.edit_key_action_add_key); mAddSubkey = view.findViewById(R.id.edit_key_action_add_key);
return root; return view;
} }
@Override @Override
@ -155,7 +153,7 @@ public class EditKeyFragment extends LoaderFragment implements
if (mDataUri == null) { if (mDataUri == null) {
returnKeyringParcel(); returnKeyringParcel();
} else { } else {
saveInDatabase(mCurrentPassphrase); cryptoOperation(new CryptoInputParcel(new Date()));
} }
} }
}, new OnClickListener() { }, new OnClickListener() {
@ -185,18 +183,12 @@ public class EditKeyFragment extends LoaderFragment implements
private void loadSaveKeyringParcel(SaveKeyringParcel saveKeyringParcel) { private void loadSaveKeyringParcel(SaveKeyringParcel saveKeyringParcel) {
mSaveKeyringParcel = saveKeyringParcel; mSaveKeyringParcel = saveKeyringParcel;
mPrimaryUserId = saveKeyringParcel.mChangePrimaryUserId; mPrimaryUserId = saveKeyringParcel.mChangePrimaryUserId;
if (saveKeyringParcel.mNewUnlock != null) {
mCurrentPassphrase = saveKeyringParcel.mNewUnlock.mNewPassphrase;
}
mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mSaveKeyringParcel.mAddUserIds, true); mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mSaveKeyringParcel.mAddUserIds, true);
mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter);
mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.mAddSubKeys, true); mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.mAddSubKeys, true);
mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter); mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter);
// show directly
setContentShown(true);
} }
private void loadData(Uri dataUri) { private void loadData(Uri dataUri) {
@ -216,9 +208,6 @@ public class EditKeyFragment extends LoaderFragment implements
case GNU_DUMMY: case GNU_DUMMY:
finishWithError(LogType.MSG_EK_ERROR_DUMMY); finishWithError(LogType.MSG_EK_ERROR_DUMMY);
return; return;
case DIVERT_TO_CARD:
finishWithError(LogType.MSG_EK_ERROR_DIVERT);
break;
} }
mSaveKeyringParcel = new SaveKeyringParcel(masterKeyId, keyRing.getFingerprint()); mSaveKeyringParcel = new SaveKeyringParcel(masterKeyId, keyRing.getFingerprint());
@ -229,24 +218,10 @@ public class EditKeyFragment extends LoaderFragment implements
return; return;
} }
try { // Prepare the loaders. Either re-connect with an existing ones,
mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), // or start new ones.
mSaveKeyringParcel.mMasterKeyId, mSaveKeyringParcel.mMasterKeyId); getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this);
} catch (PassphraseCacheService.KeyNotFoundException e) { getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, EditKeyFragment.this);
finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND);
return;
}
if (mCurrentPassphrase == null) {
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mSaveKeyringParcel.mMasterKeyId);
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
} else {
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this);
getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, EditKeyFragment.this);
}
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, mSaveKeyringParcel); mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, mSaveKeyringParcel);
mUserIdsList.setAdapter(mUserIdsAdapter); mUserIdsList.setAdapter(mUserIdsAdapter);
@ -262,28 +237,6 @@ public class EditKeyFragment extends LoaderFragment implements
mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter); mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter);
} }
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) {
mCurrentPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this);
getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, EditKeyFragment.this);
} else {
getActivity().finish();
}
return;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
private void initView() { private void initView() {
mChangePassphrase.setOnClickListener(new View.OnClickListener() { mChangePassphrase.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -322,7 +275,6 @@ public class EditKeyFragment extends LoaderFragment implements
} }
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
setContentShown(false);
switch (id) { switch (id) {
case LOADER_ID_USER_IDS: { case LOADER_ID_USER_IDS: {
@ -355,7 +307,6 @@ public class EditKeyFragment extends LoaderFragment implements
break; break;
} }
setContentShown(true);
} }
/** /**
@ -397,7 +348,7 @@ public class EditKeyFragment extends LoaderFragment implements
Messenger messenger = new Messenger(returnHandler); Messenger messenger = new Messenger(returnHandler);
SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
messenger, mCurrentPassphrase, R.string.title_change_passphrase); messenger, R.string.title_change_passphrase);
setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog"); setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog");
} }
@ -593,8 +544,11 @@ public class EditKeyFragment extends LoaderFragment implements
getActivity().finish(); getActivity().finish();
} }
private void saveInDatabase(String passphrase) { @Override
Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString()); protected void cryptoOperation(CryptoInputParcel cryptoInput) {
Log.d(Constants.TAG, "cryptoInput:\n" + cryptoInput);
Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel);
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(), getActivity(),
@ -605,6 +559,10 @@ public class EditKeyFragment extends LoaderFragment implements
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message); super.handleMessage(message);
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) { if (message.arg1 == MessageStatus.OKAY.ordinal()) {
// get returned data bundle // get returned data bundle
@ -640,7 +598,7 @@ public class EditKeyFragment extends LoaderFragment implements
// fill values for this action // fill values for this action
Bundle data = new Bundle(); Bundle data = new Bundle();
data.putString(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase); data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel); data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);

View File

@ -62,10 +62,9 @@ public abstract class EncryptActivity extends BaseActivity {
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
} }
protected void startNfcSign(long keyId, String pin, RequiredInputParcel nfcOps) { protected void startNfcSign(long keyId, RequiredInputParcel nfcOps) {
Intent intent = new Intent(this, NfcOperationActivity.class); Intent intent = new Intent(this, NfcOperationActivity.class);
intent.putExtra(NfcOperationActivity.EXTRA_PIN, pin);
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps); intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps);
// TODO respect keyid(?) // TODO respect keyid(?)
@ -148,8 +147,7 @@ public abstract class EncryptActivity extends BaseActivity {
pgpResult.getNfcHash(), pgpResult.getNfcHash(),
pgpResult.getNfcAlgo(), pgpResult.getNfcAlgo(),
input.getSignatureTime()); input.getSignatureTime());
startNfcSign(pgpResult.getNfcKeyId(), startNfcSign(pgpResult.getNfcKeyId(), parcel);
pgpResult.getNfcPassphrase(), parcel);
} else { } else {
throw new RuntimeException("Unhandled pending result!"); throw new RuntimeException("Unhandled pending result!");

View File

@ -40,7 +40,6 @@ import java.nio.ByteBuffer;
@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
public class NfcOperationActivity extends BaseActivity { public class NfcOperationActivity extends BaseActivity {
public static final String EXTRA_PIN = "pin";
public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String EXTRA_REQUIRED_INPUT = "required_input";
public static final String RESULT_DATA = "result_data"; public static final String RESULT_DATA = "result_data";
@ -50,8 +49,6 @@ public class NfcOperationActivity extends BaseActivity {
private NfcAdapter mNfcAdapter; private NfcAdapter mNfcAdapter;
private IsoDep mIsoDep; private IsoDep mIsoDep;
private String mPin;
RequiredInputParcel mNfcOperations; RequiredInputParcel mNfcOperations;
@Override @Override
@ -70,7 +67,6 @@ public class NfcOperationActivity extends BaseActivity {
Bundle data = intent.getExtras(); Bundle data = intent.getExtras();
mNfcOperations = data.getParcelable(EXTRA_REQUIRED_INPUT); mNfcOperations = data.getParcelable(EXTRA_REQUIRED_INPUT);
mPin = data.getString(EXTRA_PIN);
} }
@ -161,14 +157,16 @@ public class NfcOperationActivity extends BaseActivity {
return; return;
} }
String pin = mNfcOperations.mNfcPin;
// Command APDU for VERIFY command (page 32) // Command APDU for VERIFY command (page 32)
String login = String login =
"00" // CLA "00" // CLA
+ "20" // INS + "20" // INS
+ "00" // P1 + "00" // P1
+ "82" // P2 (PW1) + "82" // P2 (PW1)
+ String.format("%02x", mPin.length()) // Lc + String.format("%02x", pin.length()) // Lc
+ Hex.toHexString(mPin.getBytes()); + Hex.toHexString(pin.getBytes());
if ( ! card(login).equals(accepted)) { // login if ( ! card(login).equals(accepted)) { // login
toast("Wrong PIN!"); toast("Wrong PIN!");
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);

View File

@ -49,7 +49,6 @@ import org.sufficientlysecure.keychain.util.Log;
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";
private static final String ARG_TITLE = "title"; private static final String ARG_TITLE = "title";
private static final String ARG_OLD_PASSPHRASE = "old_passphrase";
public static final int MESSAGE_OKAY = 1; public static final int MESSAGE_OKAY = 1;
@ -67,12 +66,11 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
* @param messenger to communicate back after setting the passphrase * @param messenger to communicate back after setting the passphrase
* @return * @return
*/ */
public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, int title) { public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) {
SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment(); SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(ARG_TITLE, title); args.putInt(ARG_TITLE, title);
args.putParcelable(ARG_MESSENGER, messenger); args.putParcelable(ARG_MESSENGER, messenger);
args.putString(ARG_OLD_PASSPHRASE, oldPassphrase);
frag.setArguments(args); frag.setArguments(args);
@ -88,7 +86,6 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
int title = getArguments().getInt(ARG_TITLE); int title = getArguments().getInt(ARG_TITLE);
mMessenger = getArguments().getParcelable(ARG_MESSENGER); mMessenger = getArguments().getParcelable(ARG_MESSENGER);
String oldPassphrase = getArguments().getString(ARG_OLD_PASSPHRASE);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
@ -102,13 +99,6 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again); mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase); mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase);
if (TextUtils.isEmpty(oldPassphrase)) {
mNoPassphraseCheckBox.setChecked(true);
mPassphraseEditText.setEnabled(false);
mPassphraseAgainEditText.setEnabled(false);
}
mNoPassphraseCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { mNoPassphraseCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

View File

@ -897,6 +897,7 @@
<!-- modifySecretKeyRing --> <!-- modifySecretKeyRing -->
<string name="msg_mr">"Modifying keyring %s"</string> <string name="msg_mr">"Modifying keyring %s"</string>
<string name="msg_mf_divert">"Will divert to card/nfc for crypto operations"</string>
<string name="msg_mf_error_divert_serial">"The serial number of a divert-to-card key must be 16 bytes! This is a programming error, please file a bug report!"</string> <string name="msg_mf_error_divert_serial">"The serial number of a divert-to-card key must be 16 bytes! This is a programming error, please file a bug report!"</string>
<string name="msg_mf_error_encode">"Encoding exception!"</string> <string name="msg_mf_error_encode">"Encoding exception!"</string>
<string name="msg_mf_error_fingerprint">"Actual key fingerprint does not match the expected one!"</string> <string name="msg_mf_error_fingerprint">"Actual key fingerprint does not match the expected one!"</string>
@ -911,6 +912,7 @@
<string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string> <string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string>
<string name="msg_mf_error_pgp">"Internal OpenPGP error!"</string> <string name="msg_mf_error_pgp">"Internal OpenPGP error!"</string>
<string name="msg_mf_error_sig">"Signature exception!"</string> <string name="msg_mf_error_sig">"Signature exception!"</string>
<string name="msg_mf_input_required">"Diverting to card/nfc for crypto operations"</string>
<string name="msg_mf_master">"Modifying master certifications"</string> <string name="msg_mf_master">"Modifying master certifications"</string>
<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>
@ -987,7 +989,6 @@
<string name="msg_pr_success">"Key successfully promoted"</string> <string name="msg_pr_success">"Key successfully promoted"</string>
<!-- Other messages used in OperationLogs --> <!-- Other messages used in OperationLogs -->
<string name="msg_ek_error_divert">"Editing of NFC keys is not (yet) supported!"</string>
<string name="msg_ek_error_dummy">"Cannot edit keyring with stripped master key!"</string> <string name="msg_ek_error_dummy">"Cannot edit keyring with stripped master key!"</string>
<string name="msg_ek_error_not_found">"Key not found!"</string> <string name="msg_ek_error_not_found">"Key not found!"</string>