diff options
author | Alex Fong <alexfongg@gmail.com> | 2016-03-15 10:24:28 +0800 |
---|---|---|
committer | Alex Fong <alexfongg@gmail.com> | 2016-05-04 22:36:23 +0800 |
commit | 525788359c6821a958ee7306ef3aa34d7b211a6f (patch) | |
tree | df76551c2d2b187db62bba313eda1886fa1e7bf1 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp | |
parent | 6b7a0597af7aa42b375ca34d8a47515fa8adcc9f (diff) | |
download | open-keychain-525788359c6821a958ee7306ef3aa34d7b211a6f.tar.gz open-keychain-525788359c6821a958ee7306ef3aa34d7b211a6f.tar.bz2 open-keychain-525788359c6821a958ee7306ef3aa34d7b211a6f.zip |
(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.
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp')
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 72 |
1 files changed, 66 insertions, 6 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index ce9c30894..abfdf0966 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -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; |