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

View file

@ -21,6 +21,7 @@ import android.content.Context;
import org.sufficientlysecure.keychain.R;
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.OperationLog;
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.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@ -55,7 +57,7 @@ public class EditKeyOperation extends BaseOperation {
super(context, providerHelper, progressable, cancelled);
}
public EditKeyResult execute(SaveKeyringParcel saveParcel, String passphrase) {
public OperationResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) {
OperationLog log = new OperationLog();
log.add(LogType.MSG_ED, 0);
@ -69,7 +71,7 @@ public class EditKeyOperation extends BaseOperation {
PgpEditKeyResult modifyResult;
{
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 (saveParcel.mMasterKeyId != null) {
@ -80,7 +82,10 @@ public class EditKeyOperation extends BaseOperation {
CanonicalizedSecretKeyRing secRing =
mProviderHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel);
if (modifyResult.isPending()) {
return modifyResult;
}
} catch (NotFoundException e) {
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)
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 Long mKeyIdPassphraseNeeded;
public InputPendingResult(int result, OperationLog log) {
super(result, log);
mRequiredInput = null;
mKeyIdPassphraseNeeded = null;
}
public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput) {
super(RESULT_PENDING_NFC, log);
super(RESULT_PENDING, log);
mRequiredInput = requiredInput;
mKeyIdPassphraseNeeded = null;
}
public InputPendingResult(OperationLog log, long keyIdPassphraseNeeded) {
super(RESULT_PENDING_PASSPHRASE, log);
mRequiredInput = null;
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
}
public InputPendingResult(Parcel source) {
super(source);
mRequiredInput = source.readParcelable(getClass().getClassLoader());
mKeyIdPassphraseNeeded = source.readInt() != 0 ? source.readLong() : null;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(mRequiredInput, 0);
if (mKeyIdPassphraseNeeded != null) {
dest.writeInt(1);
dest.writeLong(mKeyIdPassphraseNeeded);
} else {
dest.writeInt(0);
}
}
public boolean isPending() {
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() {
return mRequiredInput;
}
public long getPassphraseKeyId() {
return mKeyIdPassphraseNeeded;
}
}

View file

@ -512,6 +512,7 @@ public abstract class OperationResult implements Parcelable {
// secret key modify
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_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode),
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_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_INPUT_REQUIRED (LogLevel.OK, R.string.msg_mf_input_required),
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_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),
// 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_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.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
public class PgpEditKeyResult extends OperationResult {
public class PgpEditKeyResult extends InputPendingResult {
private transient UncachedKeyRing mRing;
public final long mRingMasterKeyId;
@ -35,6 +37,11 @@ public class PgpEditKeyResult extends OperationResult {
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
}
public PgpEditKeyResult(OperationLog log, RequiredInputParcel requiredInput) {
super(log, requiredInput);
mRingMasterKeyId = Constants.key.none;
}
public UncachedKeyRing getRing() {
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
*/
public boolean unlock(String passphrase) throws PgpGeneralException {
public boolean unlock(char[] passphrase) throws PgpGeneralException {
// handle keys on OpenPGP cards like they were unlocked
if (mSecretKey.getS2K() != null
&& mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K
@ -164,7 +168,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
// try to extract keys using the passphrase
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED;
} catch (PGPException e) {

View file

@ -18,7 +18,7 @@
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.KeyFlags;
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.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.PGPDataDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
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.JcePBESecretKeyDecryptorBuilder;
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.R;
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.Curve;
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.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@ -85,9 +91,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
* This indicator may be null.
*/
public class PgpKeyOperation {
private Stack<Progressable> mProgress;
private AtomicBoolean mCancelled;
NfcSignOperationsBuilder mNfcSignOps;
private CryptoInputParcel mCryptoInput;
public PgpKeyOperation(Progressable progress) {
super();
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);
mCancelled = cancelled;
mNfcSignOps = new NfcSignOperationsBuilder(cryptoInput.getSignatureTime());
mCryptoInput = cryptoInput;
}
private boolean checkCancelled() {
@ -316,7 +328,8 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
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) {
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.
*
*/
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
String passphrase) {
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR,
SaveKeyringParcel saveParcel) {
OperationLog log = new OperationLog();
int indent = 0;
@ -386,11 +399,16 @@ public class PgpKeyOperation {
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
}
// If we have no passphrase, only allow restricted operation
if (passphrase == null) {
if (saveParcel.isRestrictedOnly()) {
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.
// since this is the master key, this contains at least CERTIFY_OTHER
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
@ -398,13 +416,13 @@ public class PgpKeyOperation {
Date expiryTime = wsKR.getPublicKey().getExpiryTime();
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,
int masterKeyFlags, long masterKeyExpiry,
SaveKeyringParcel saveParcel, String passphrase,
SaveKeyringParcel saveParcel,
OperationLog log) {
int indent = 1;
@ -413,18 +431,25 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
// 1. Unlock private key
progress(R.string.progress_modify_unlock, 10);
log.add(LogType.MSG_MF_UNLOCK, indent);
PGPPrivateKey masterPrivateKey;
{
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
if (isDivertToCard(masterSecretKey)) {
masterPrivateKey = null;
log.add(LogType.MSG_MF_DIVERT, indent);
} else {
// 1. Unlock private key
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
&& userId.equals(saveParcel.mChangePrimaryUserId);
// generate and add new certificate
PGPSignature cert = generateUserIdSignature(masterPrivateKey,
masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
try {
PGPSignature cert = generateUserIdSignature(
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();
@ -508,9 +540,15 @@ public class PgpKeyOperation {
PGPUserAttributeSubpacketVector vector = attribute.getVector();
// generate and add new certificate
PGPSignature cert = generateUserAttributeSignature(masterPrivateKey,
masterPublicKey, vector);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
try {
PGPSignature cert = generateUserAttributeSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, vector);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
}
subProgressPop();
@ -538,9 +576,15 @@ public class PgpKeyOperation {
// a duplicate revocation will be removed during canonicalization, so no need to
// take care of that here.
PGPSignature cert = generateRevocationSignature(masterPrivateKey,
masterPublicKey, userId);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
try {
PGPSignature cert = generateRevocationSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, userId);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
}
subProgressPop();
@ -610,11 +654,18 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature(
masterPrivateKey, masterPublicKey, userId, false,
masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
try {
PGPSignature newCert = generateUserIdSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, userId, false,
masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
continue;
}
@ -626,11 +677,17 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_PRIMARY_NEW, indent);
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature(
masterPrivateKey, masterPublicKey, userId, true,
masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
try {
PGPSignature newCert = generateUserIdSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
mCryptoInput.getSignatureTime(),
masterPrivateKey, masterPublicKey, userId, true,
masterKeyFlags, masterKeyExpiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
ok = true;
}
@ -717,7 +774,8 @@ public class PgpKeyOperation {
}
PGPPublicKey pKey =
updateMasterCertificates(masterPrivateKey, masterPublicKey,
updateMasterCertificates(
masterSecretKey, masterPrivateKey, masterPublicKey,
flags, expiry, indent, log);
if (pKey == null) {
// error log entry has already been added by updateMasterCertificates itself
@ -755,9 +813,16 @@ public class PgpKeyOperation {
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
PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
sKey, pKey, flags, expiry, passphrase);
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
@ -781,10 +846,17 @@ public class PgpKeyOperation {
PGPPublicKey pKey = sKey.getPublicKey();
// 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);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
} catch (NfcInteractionNeeded e) {
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
}
}
subProgressPop();
@ -827,19 +899,29 @@ public class PgpKeyOperation {
// add subkey binding signature (making this a sub rather than master key)
PGPPublicKey pKey = keyPair.getPublicKey();
PGPSignature cert = generateSubkeyBindingSignature(
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
try {
PGPSignature cert = generateSubkeyBindingSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
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; {
char[] passphrase = mCryptoInput.getPassphrase();
if (passphrase == null) {
passphrase = new char[] { };
}
// Build key encrypter and decrypter based on passphrase
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
.build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
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()
.build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
@ -867,7 +949,7 @@ public class PgpKeyOperation {
indent += 1;
sKR = applyNewUnlock(sKR, masterPublicKey, masterPrivateKey,
passphrase, saveParcel.mNewUnlock, log, indent);
mCryptoInput.getPassphrase(), saveParcel.mNewUnlock, log, indent);
if (sKR == null) {
// The error has been logged above, just return a bad state
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
@ -891,6 +973,12 @@ public class PgpKeyOperation {
}
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);
return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));
@ -967,7 +1055,7 @@ public class PgpKeyOperation {
PGPSecretKeyRing sKR,
PGPPublicKey masterPublicKey,
PGPPrivateKey masterPrivateKey,
String passphrase,
char[] passphrase,
ChangeUnlockParcel newUnlock,
OperationLog log, int indent) throws PGPException {
@ -1051,14 +1139,14 @@ public class PgpKeyOperation {
private static PGPSecretKeyRing applyNewPassphrase(
PGPSecretKeyRing sKR,
PGPPublicKey masterPublicKey,
String passphrase,
char[] passphrase,
String newPassphrase,
OperationLog log, int indent) throws PGPException {
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
.get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
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
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
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. */
private static PGPPublicKey updateMasterCertificates(
PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey,
private PGPPublicKey updateMasterCertificates(
PGPSecretKey masterSecretKey, PGPPrivateKey masterPrivateKey,
PGPPublicKey masterPublicKey,
int flags, long expiry, int indent, OperationLog log)
throws PGPException, IOException, SignatureException {
@ -1172,10 +1261,16 @@ public class PgpKeyOperation {
currentCert.getHashedSubPackets().isPrimaryUserID();
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature(
masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
try {
PGPSignature newCert = generateUserIdSignature(
getSignatureGenerator(masterSecretKey, mCryptoInput),
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;
}
@ -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,
int flags, long expiry)
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();
{
@ -1222,7 +1339,7 @@ public class PgpKeyOperation {
hashedPacketsGen.setPrimaryUserID(false, primary);
/* 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)
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
hashedPacketsGen.setKeyFlags(true, flags);
@ -1238,19 +1355,15 @@ public class PgpKeyOperation {
}
private static PGPSignature generateUserAttributeSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey,
PGPUserAttributeSubpacketVector vector)
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();
{
/* critical subpackets: we consider those important for a modern pgp implementation */
hashedPacketsGen.setSignatureCreationTime(true, new Date());
hashedPacketsGen.setSignatureCreationTime(true, creationTime);
}
sGen.setHashedSubpackets(hashedPacketsGen.generate());
@ -1259,29 +1372,24 @@ public class PgpKeyOperation {
}
private static PGPSignature generateRevocationSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
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();
subHashedPacketsGen.setSignatureCreationTime(true, new Date());
subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
}
private static PGPSignature generateRevocationSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
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();
subHashedPacketsGen.setSignatureCreationTime(true, new Date());
subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness
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(
PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
throws IOException, PGPException, SignatureException {
// date for signing
Date creationTime = new Date();
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
// If this key can sign, we need a primary key binding signature
@ -1323,10 +1417,10 @@ public class PgpKeyOperation {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey);
PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
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.setHashedSubpackets(hashedPacketsGen.generate());
sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
@ -1371,4 +1461,10 @@ public class PgpKeyOperation {
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();
}
public Date getSignatureTime() {
return mCryptoInput.getSignatureTime();
}
public static final Creator<CertifyActionsParcel> CREATOR = new Creator<CertifyActionsParcel>() {
public CertifyActionsParcel createFromParcel(final Parcel 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.provider.ProviderHelper;
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.InputData;
import org.sufficientlysecure.keychain.util.Log;
@ -160,6 +161,7 @@ public class KeychainIntentService extends IntentService implements Progressable
// save keyring
public static final String EDIT_KEYRING_PARCEL = "save_parcel";
public static final String EDIT_KEYRING_PASSPHRASE = "passphrase";
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
// delete keyring(s)
public static final String DELETE_KEY_LIST = "delete_list";
@ -469,11 +471,11 @@ public class KeychainIntentService extends IntentService implements Progressable
// Input
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE);
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);
EditKeyResult result = op.execute(saveParcel, passphrase);
OperationResult result = op.execute(saveParcel, cryptoInput);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);

View file

@ -81,8 +81,8 @@ public class CryptoInputParcel implements Parcelable {
return mPassphrase != null;
}
public String getPassphrase() {
return mPassphrase;
public char[] getPassphrase() {
return mPassphrase == null ? null : mPassphrase.toCharArray();
}
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 final RequiredInputType mType;
public String mNfcPin = "123456";
public final byte[][] mInputHashes;
public final int[] mSignAlgos;
private Long mSubKeyId;
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.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@ -25,7 +26,6 @@ public abstract class CryptoOperationFragment extends Fragment {
case NFC_DECRYPT:
case NFC_SIGN: {
Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456");
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
startActivityForResult(intent, REQUEST_CODE_NFC);
return;
@ -76,10 +76,14 @@ public abstract class CryptoOperationFragment extends Fragment {
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
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()) {
RequiredInputParcel requiredInput = result.getRequiredInputParcel();
InputPendingResult pendingResult = (InputPendingResult) result;
if (pendingResult.isPending()) {
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
initiateInputActivity(requiredInput);
return true;
}

View file

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

View file

@ -62,10 +62,9 @@ public abstract class EncryptActivity extends BaseActivity {
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.putExtra(NfcOperationActivity.EXTRA_PIN, pin);
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps);
// TODO respect keyid(?)
@ -148,8 +147,7 @@ public abstract class EncryptActivity extends BaseActivity {
pgpResult.getNfcHash(),
pgpResult.getNfcAlgo(),
input.getSignatureTime());
startNfcSign(pgpResult.getNfcKeyId(),
pgpResult.getNfcPassphrase(), parcel);
startNfcSign(pgpResult.getNfcKeyId(), parcel);
} else {
throw new RuntimeException("Unhandled pending result!");

View file

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

View file

@ -49,7 +49,6 @@ import org.sufficientlysecure.keychain.util.Log;
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger";
private static final String ARG_TITLE = "title";
private static final String ARG_OLD_PASSPHRASE = "old_passphrase";
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
* @return
*/
public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, int title) {
public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) {
SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment();
Bundle args = new Bundle();
args.putInt(ARG_TITLE, title);
args.putParcelable(ARG_MESSENGER, messenger);
args.putString(ARG_OLD_PASSPHRASE, oldPassphrase);
frag.setArguments(args);
@ -88,7 +86,6 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
int title = getArguments().getInt(ARG_TITLE);
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
String oldPassphrase = getArguments().getString(ARG_OLD_PASSPHRASE);
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);
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() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

View file

@ -897,6 +897,7 @@
<!-- modifySecretKeyRing -->
<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_encode">"Encoding exception!"</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_pgp">"Internal OpenPGP error!"</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_notation_empty">"Adding empty 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>
<!-- 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_not_found">"Key not found!"</string>