(WIP) Change password when key is stripped #1692
Approach: Find the first unstripped secret key and use it for passphrase verification All unstripped keys will have their passphrase changed to new passphrase, if possible. Current Progress: Changing the passphrase of keys works fine. Refactoring to combine "modifySecretKeyring" and newly added method, "modifyKeyRingPassword" may be possible if given the go-ahead.
This commit is contained in:
@@ -72,6 +72,8 @@ 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;
|
||||
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseChangeParcel;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
|
||||
@@ -345,6 +347,64 @@ public class PgpKeyOperation {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public PgpEditKeyResult modifyKeyRingPassword(CanonicalizedSecretKeyRing wsKR,
|
||||
CryptoInputParcel cryptoInput,
|
||||
PassphraseChangeParcel passphraseParcel) {
|
||||
|
||||
OperationLog log = new OperationLog();
|
||||
int indent = 0;
|
||||
|
||||
if (passphraseParcel.mMasterKeyId == null || passphraseParcel.mMasterKeyId != wsKR.getMasterKeyId()) {
|
||||
log.add(LogType.MSG_MF_ERROR_KEYID, indent);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
|
||||
log.add(LogType.MSG_MF, indent,
|
||||
KeyFormattingUtils.convertKeyIdToHex(wsKR.getMasterKeyId()));
|
||||
indent += 1;
|
||||
progress(R.string.progress_building_key, 0);
|
||||
|
||||
// We work on bouncycastle object level here
|
||||
PGPSecretKeyRing sKR = wsKR.getRing();
|
||||
PGPSecretKey masterSecretKey = sKR.getSecretKey();
|
||||
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
|
||||
// Make sure the fingerprint matches
|
||||
if (passphraseParcel.mFingerprint == null || !Arrays.equals(passphraseParcel.mFingerprint,
|
||||
masterSecretKey.getPublicKey().getFingerprint())) {
|
||||
log.add(LogType.MSG_MF_ERROR_FINGERPRINT, indent);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
|
||||
if (!cryptoInput.hasPassphrase()) {
|
||||
log.add(LogType.MSG_MF_REQUIRE_PASSPHRASE, indent);
|
||||
|
||||
return new PgpEditKeyResult(log, RequiredInputParcel.createRequiredSignPassphrase(
|
||||
masterSecretKey.getKeyID(), passphraseParcel.mValidSubkeyId,
|
||||
cryptoInput.getSignatureTime()), cryptoInput);
|
||||
} else {
|
||||
progress(R.string.progress_modify_passphrase, 70);
|
||||
log.add(LogType.MSG_MF_PASSPHRASE, indent);
|
||||
indent += 1;
|
||||
|
||||
try {
|
||||
sKR = applyNewPassphrase(sKR, masterPublicKey, cryptoInput.getPassphrase(),
|
||||
passphraseParcel.mNewUnlock.mNewPassphrase, log, indent);
|
||||
if (sKR == null) {
|
||||
// The error has been logged above, just return a bad state
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
} catch (PGPException e) {
|
||||
throw new UnsupportedOperationException("Failed to build encryptor/decryptor!");
|
||||
}
|
||||
|
||||
indent -= 1;
|
||||
progress(R.string.progress_done, 100);
|
||||
log.add(LogType.MSG_MF_SUCCESS, indent);
|
||||
return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));
|
||||
}
|
||||
}
|
||||
|
||||
/** This method introduces a list of modifications specified by a SaveKeyringParcel to a
|
||||
* WrappedSecretKeyRing.
|
||||
*
|
||||
@@ -1223,6 +1283,7 @@ public class PgpKeyOperation {
|
||||
PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
||||
PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(newPassphrase.getCharArray());
|
||||
int keysModified = 0;
|
||||
|
||||
for (PGPSecretKey sKey : new IterableIterator<>(sKR.getSecretKeys())) {
|
||||
log.add(LogType.MSG_MF_PASSPHRASE_KEY, indent,
|
||||
@@ -1236,12 +1297,6 @@ public class PgpKeyOperation {
|
||||
ok = true;
|
||||
} catch (PGPException e) {
|
||||
|
||||
// if this is the master key, error!
|
||||
if (sKey.getKeyID() == masterPublicKey.getKeyID()) {
|
||||
log.add(LogType.MSG_MF_ERROR_PASSPHRASE_MASTER, indent+1);
|
||||
return null;
|
||||
}
|
||||
|
||||
// being in here means decrypt failed, likely due to a bad passphrase try
|
||||
// again with an empty passphrase, maybe we can salvage this
|
||||
try {
|
||||
@@ -1264,7 +1319,12 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
|
||||
keysModified++;
|
||||
}
|
||||
|
||||
if(keysModified == 0) {
|
||||
log.add(LogType.MSG_MF_ERROR_PASSPHRASES_UNCHANGED, indent+1);
|
||||
return null;
|
||||
}
|
||||
|
||||
return sKR;
|
||||
|
||||
Reference in New Issue
Block a user