1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
package org.sufficientlysecure.keychain.operations;
import android.content.Context;
import android.support.annotation.NonNull;
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.PgpEditKeyResult;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.PassphraseChangeParcel;
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;
import java.util.Iterator;
/**
* Created by alex on 3/14/16.
*/
public class PassphraseChangeOperation extends BaseOperation<PassphraseChangeParcel> {
public PassphraseChangeOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
super(context, providerHelper, progressable);
}
/**
* Finds the first unstripped key & uses that for passphrase verification.
* Might bring in complications
*
* @param passphraseParcel primary input to the operation
* @param cryptoInput input that changes if user interaction is required
* @return the result of the operation
*/
@NonNull
public OperationResult execute(PassphraseChangeParcel passphraseParcel, CryptoInputParcel cryptoInput) {
OperationResult.OperationLog log = new OperationResult.OperationLog();
log.add(OperationResult.LogType.MSG_ED, 0);
if (passphraseParcel == null || passphraseParcel.mMasterKeyId == null) {
log.add(OperationResult.LogType.MSG_ED_ERROR_NO_PARCEL, 1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// Perform actual modification
PgpEditKeyResult modifyResult;
{
PgpKeyOperation keyOperations =
new PgpKeyOperation(new ProgressScaler(mProgressable, 0, 70, 100), mCancelled);
try {
log.add(OperationResult.LogType.MSG_ED_FETCHING, 1,
KeyFormattingUtils.convertKeyIdToHex(passphraseParcel.mMasterKeyId));
CanonicalizedSecretKeyRing secRing =
mProviderHelper.getCanonicalizedSecretKeyRing(passphraseParcel.mMasterKeyId);
CachedPublicKeyRing cachedRing =
mProviderHelper.getCachedPublicKeyRing(passphraseParcel.mMasterKeyId);
passphraseParcel.mValidSubkeyId = getFirstValidKeyId(secRing, cachedRing);
if(passphraseParcel.mValidSubkeyId == null) {
log.add(OperationResult.LogType.MSG_MF_ERROR_ALL_KEYS_STRIPPED, 0);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
modifyResult = keyOperations.modifyKeyRingPassword(secRing, cryptoInput, passphraseParcel);
if (modifyResult.isPending()) {
log.add(modifyResult, 1);
return new EditKeyResult(log, modifyResult);
}
} catch (ProviderHelper.NotFoundException e) {
log.add(OperationResult.LogType.MSG_ED_ERROR_KEY_NOT_FOUND, 2);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
log.add(modifyResult, 1);
// Check if the action was cancelled
if (checkCancelled()) {
log.add(OperationResult.LogType.MSG_OPERATION_CANCELLED, 0);
return new EditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
}
if (!modifyResult.success()) {
// error is already logged by modification
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// Cannot cancel from here on out!
mProgressable.setPreventCancel();
// It's a success, so this must be non-null now
UncachedKeyRing ring = modifyResult.getRing();
SaveKeyringResult saveResult = mProviderHelper
.saveSecretKeyRing(ring, new ProgressScaler(mProgressable, 70, 95, 100));
log.add(saveResult, 1);
// If the save operation didn't succeed, exit here
if (!saveResult.success()) {
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
updateProgress(R.string.progress_done, 100, 100);
log.add(OperationResult.LogType.MSG_ED_SUCCESS, 0);
return new EditKeyResult(EditKeyResult.RESULT_OK, log, ring.getMasterKeyId());
}
private static Long getFirstValidKeyId (CanonicalizedSecretKeyRing secRing, CachedPublicKeyRing cachedRing) {
Iterator<CanonicalizedSecretKey> secretKeyIterator = secRing.secretKeyIterator().iterator();
while(secretKeyIterator.hasNext()) {
try {
long keyId = secretKeyIterator.next().getKeyId();
CanonicalizedSecretKey.SecretKeyType keyType = cachedRing.getSecretKeyType(keyId);
if( keyType == CanonicalizedSecretKey.SecretKeyType.PASSPHRASE
|| keyType == CanonicalizedSecretKey.SecretKeyType.PASSPHRASE_EMPTY) {
return keyId;
}
} catch (ProviderHelper.NotFoundException e) {
;
}
}
return null;
}
}
|