Merge pull request #2226 from open-keychain/multi-passphrase
Handle decryption with multiple candidate keys
This commit is contained in:
@@ -40,10 +40,16 @@ public abstract class CryptoInputParcel implements Parcelable {
|
||||
public abstract Date getSignatureTime();
|
||||
@Nullable
|
||||
public abstract Passphrase getPassphrase();
|
||||
@Nullable
|
||||
public abstract Long getPassphraseSubkey();
|
||||
public abstract boolean isCachePassphrase();
|
||||
|
||||
public boolean hasPassphrase() {
|
||||
return getPassphrase() != null;
|
||||
public boolean hasPassphraseForSubkey(long subKeyId) {
|
||||
return getPassphrase() != null && (getPassphraseSubkey() == null || getPassphraseSubkey() == subKeyId);
|
||||
}
|
||||
|
||||
public boolean hasPassphraseForSymmetric() {
|
||||
return getPassphrase() != null && getPassphraseSubkey() == null;
|
||||
}
|
||||
|
||||
// used to supply an explicit proxy to operations that require it
|
||||
@@ -59,43 +65,43 @@ public abstract class CryptoInputParcel implements Parcelable {
|
||||
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel() {
|
||||
return new AutoValue_CryptoInputParcel(null, null, true, null, Collections.<ByteBuffer,byte[]>emptyMap());
|
||||
return new AutoValue_CryptoInputParcel(null, null, null, true, null, Collections.<ByteBuffer,byte[]>emptyMap());
|
||||
}
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel(Date signatureTime, Passphrase passphrase) {
|
||||
if (signatureTime == null) {
|
||||
signatureTime = new Date();
|
||||
}
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, passphrase, true, null,
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, passphrase, null, true, null,
|
||||
Collections.<ByteBuffer,byte[]>emptyMap());
|
||||
}
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel(Passphrase passphrase) {
|
||||
return new AutoValue_CryptoInputParcel(null, passphrase, true, null, Collections.<ByteBuffer,byte[]>emptyMap());
|
||||
return new AutoValue_CryptoInputParcel(null, passphrase, null, true, null, Collections.<ByteBuffer,byte[]>emptyMap());
|
||||
}
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel(Date signatureTime) {
|
||||
if (signatureTime == null) {
|
||||
signatureTime = new Date();
|
||||
}
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, null, true, null,
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, null, null, true, null,
|
||||
Collections.<ByteBuffer,byte[]>emptyMap());
|
||||
}
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel(ParcelableProxy parcelableProxy) {
|
||||
return new AutoValue_CryptoInputParcel(null, null, true, parcelableProxy, new HashMap<ByteBuffer,byte[]>());
|
||||
return new AutoValue_CryptoInputParcel(null, null, null, true, parcelableProxy, new HashMap<ByteBuffer,byte[]>());
|
||||
}
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel(Date signatureTime, boolean cachePassphrase) {
|
||||
if (signatureTime == null) {
|
||||
signatureTime = new Date();
|
||||
}
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, null, cachePassphrase, null,
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, null, null, cachePassphrase, null,
|
||||
new HashMap<ByteBuffer,byte[]>());
|
||||
}
|
||||
|
||||
public static CryptoInputParcel createCryptoInputParcel(boolean cachePassphrase) {
|
||||
return new AutoValue_CryptoInputParcel(null, null, cachePassphrase, null, new HashMap<ByteBuffer,byte[]>());
|
||||
return new AutoValue_CryptoInputParcel(null, null, null, cachePassphrase, null, new HashMap<ByteBuffer,byte[]>());
|
||||
}
|
||||
|
||||
// TODO get rid of this!
|
||||
@@ -105,8 +111,8 @@ public abstract class CryptoInputParcel implements Parcelable {
|
||||
newCryptoData.put(ByteBuffer.wrap(hash), signedHash);
|
||||
newCryptoData = Collections.unmodifiableMap(newCryptoData);
|
||||
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), isCachePassphrase(),
|
||||
getParcelableProxy(), newCryptoData);
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), getPassphraseSubkey(),
|
||||
isCachePassphrase(), getParcelableProxy(), newCryptoData);
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
@@ -115,32 +121,32 @@ public abstract class CryptoInputParcel implements Parcelable {
|
||||
newCryptoData.putAll(cachedSessionKeys);
|
||||
newCryptoData = Collections.unmodifiableMap(newCryptoData);
|
||||
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), isCachePassphrase(),
|
||||
getParcelableProxy(), newCryptoData);
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), getPassphraseSubkey(),
|
||||
isCachePassphrase(), getParcelableProxy(), newCryptoData);
|
||||
}
|
||||
|
||||
|
||||
@CheckResult
|
||||
public CryptoInputParcel withPassphrase(Passphrase passphrase) {
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), passphrase, isCachePassphrase(),
|
||||
public CryptoInputParcel withPassphrase(Passphrase passphrase, Long subKeyId) {
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), passphrase, subKeyId, isCachePassphrase(),
|
||||
getParcelableProxy(), getCryptoData());
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
public CryptoInputParcel withNoCachePassphrase() {
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), false, getParcelableProxy(),
|
||||
getCryptoData());
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), getPassphraseSubkey(),
|
||||
false, getParcelableProxy(), getCryptoData());
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
public CryptoInputParcel withSignatureTime(Date signatureTime) {
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, getPassphrase(), isCachePassphrase(),
|
||||
getParcelableProxy(), getCryptoData());
|
||||
return new AutoValue_CryptoInputParcel(signatureTime, getPassphrase(), getPassphraseSubkey(),
|
||||
isCachePassphrase(), getParcelableProxy(), getCryptoData());
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
public CryptoInputParcel withParcelableProxy(ParcelableProxy parcelableProxy) {
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), isCachePassphrase(),
|
||||
parcelableProxy, getCryptoData());
|
||||
return new AutoValue_CryptoInputParcel(getSignatureTime(), getPassphrase(), getPassphraseSubkey(),
|
||||
isCachePassphrase(), parcelableProxy, getCryptoData());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,19 +46,25 @@ public class RequiredInputParcel implements Parcelable {
|
||||
public final byte[][] mInputData;
|
||||
public final int[] mSignAlgos;
|
||||
|
||||
private Long mMasterKeyId;
|
||||
private Long mSubKeyId;
|
||||
private long[] mMasterKeyIds;
|
||||
private long[] mSubKeyIds;
|
||||
|
||||
public boolean mSkipCaching = false;
|
||||
|
||||
private RequiredInputParcel(RequiredInputType type, byte[][] inputData,
|
||||
int[] signAlgos, Date signatureTime, Long masterKeyId, Long subKeyId) {
|
||||
int[] signAlgos, Date signatureTime, long[] masterKeyIds, long[] subKeyIds) {
|
||||
mType = type;
|
||||
mInputData = inputData;
|
||||
mSignAlgos = signAlgos;
|
||||
mSignatureTime = signatureTime;
|
||||
mMasterKeyId = masterKeyId;
|
||||
mSubKeyId = subKeyId;
|
||||
mMasterKeyIds = masterKeyIds;
|
||||
mSubKeyIds = subKeyIds;
|
||||
}
|
||||
|
||||
private RequiredInputParcel(RequiredInputType type, byte[][] inputData,
|
||||
int[] signAlgos, Date signatureTime, Long masterKeyId, Long subKeyId) {
|
||||
this(type, inputData, signAlgos, signatureTime, masterKeyId != null ? new long[] { masterKeyId } : null,
|
||||
subKeyId != null ? new long[] { subKeyId } : null);
|
||||
}
|
||||
|
||||
public RequiredInputParcel(Parcel source) {
|
||||
@@ -87,18 +93,26 @@ public class RequiredInputParcel implements Parcelable {
|
||||
}
|
||||
|
||||
mSignatureTime = source.readInt() != 0 ? new Date(source.readLong()) : null;
|
||||
mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
|
||||
mSubKeyId = source.readInt() != 0 ? source.readLong() : null;
|
||||
mMasterKeyIds = source.readInt() != 0 ? source.createLongArray() : null;
|
||||
mSubKeyIds = source.readInt() != 0 ? source.createLongArray() : null;
|
||||
mSkipCaching = source.readInt() != 0;
|
||||
|
||||
}
|
||||
|
||||
public Long getMasterKeyId() {
|
||||
return mMasterKeyId;
|
||||
return mMasterKeyIds == null ? null : mMasterKeyIds[0];
|
||||
}
|
||||
|
||||
public Long getSubKeyId() {
|
||||
return mSubKeyId;
|
||||
return mSubKeyIds == null ? null : mSubKeyIds[0];
|
||||
}
|
||||
|
||||
public long[] getMasterKeyIds() {
|
||||
return mMasterKeyIds;
|
||||
}
|
||||
|
||||
public long[] getSubKeyIds() {
|
||||
return mSubKeyIds;
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createRetryUploadOperation() {
|
||||
@@ -134,7 +148,7 @@ public class RequiredInputParcel implements Parcelable {
|
||||
|
||||
public static RequiredInputParcel createSecurityTokenReset() {
|
||||
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_RESET_CARD,
|
||||
null, null, null, null, null);
|
||||
null, null, null, (long[]) null, null);
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createRequiredAuthenticationPassphrase(
|
||||
@@ -157,18 +171,18 @@ public class RequiredInputParcel implements Parcelable {
|
||||
|
||||
public static RequiredInputParcel createRequiredSymmetricPassphrase() {
|
||||
return new RequiredInputParcel(RequiredInputType.PASSPHRASE_SYMMETRIC,
|
||||
null, null, null, null, null);
|
||||
null, null, null, (long[]) null, null);
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createRequiredBackupCode() {
|
||||
return new RequiredInputParcel(RequiredInputType.BACKUP_CODE,
|
||||
null, null, null, null, null);
|
||||
null, null, null, (long[]) null, null);
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createRequiredPassphrase(
|
||||
RequiredInputParcel req) {
|
||||
return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
|
||||
null, null, req.mSignatureTime, req.mMasterKeyId, req.mSubKeyId);
|
||||
null, null, req.mSignatureTime, req.mMasterKeyIds, req.mSubKeyIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,15 +211,15 @@ public class RequiredInputParcel implements Parcelable {
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (mMasterKeyId != null) {
|
||||
if (mMasterKeyIds != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeLong(mMasterKeyId);
|
||||
dest.writeLongArray(mMasterKeyIds);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (mSubKeyId != null) {
|
||||
if (mSubKeyIds != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeLong(mSubKeyId);
|
||||
dest.writeLongArray(mSubKeyIds);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
@@ -319,7 +333,7 @@ public class RequiredInputParcel implements Parcelable {
|
||||
}
|
||||
|
||||
public void addAll(RequiredInputParcel input) {
|
||||
if (!mMasterKeyId.equals(input.mMasterKeyId)) {
|
||||
if (!mMasterKeyId.equals(input.mMasterKeyIds)) {
|
||||
throw new AssertionError("Master keys must match, this is a programming error!");
|
||||
}
|
||||
if (input.mType != RequiredInputType.SECURITY_TOKEN_MOVE_KEY_TO_CARD) {
|
||||
@@ -335,4 +349,30 @@ public class RequiredInputParcel implements Parcelable {
|
||||
|
||||
}
|
||||
|
||||
public static class RequireAnyDecryptPassphraseBuilder {
|
||||
private final ArrayList<Long> masterKeyIds = new ArrayList<>();
|
||||
private final ArrayList<Long> subKeyIds = new ArrayList<>();
|
||||
|
||||
public RequiredInputParcel build() {
|
||||
int numIds = masterKeyIds.size();
|
||||
long[] masterKeyIdsArr = new long[numIds];
|
||||
long[] subKeyIdsArr = new long[numIds];
|
||||
for (int i = 0; i < numIds; i++) {
|
||||
masterKeyIdsArr[i] = masterKeyIds.get(i);
|
||||
subKeyIdsArr[i] = subKeyIds.get(i);
|
||||
}
|
||||
|
||||
return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
|
||||
null, null, null, masterKeyIdsArr, subKeyIdsArr);
|
||||
}
|
||||
|
||||
public void add(long masterKeyId, long subKeyId) {
|
||||
masterKeyIds.add(masterKeyId);
|
||||
subKeyIds.add(subKeyId);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return masterKeyIds.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user