Merge pull request #2644 from k9mail/autocrypt-update-on-display
Autocrypt parse on display
This commit is contained in:
commit
99786e0884
20 changed files with 953 additions and 97 deletions
|
@ -4,7 +4,9 @@ package com.fsck.k9.mail.internet;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -15,7 +17,6 @@ import com.fsck.k9.mail.Message;
|
||||||
import com.fsck.k9.mail.MessagingException;
|
import com.fsck.k9.mail.MessagingException;
|
||||||
import com.fsck.k9.mail.Multipart;
|
import com.fsck.k9.mail.Multipart;
|
||||||
import com.fsck.k9.mail.Part;
|
import com.fsck.k9.mail.Part;
|
||||||
|
|
||||||
import org.apache.james.mime4j.codec.Base64InputStream;
|
import org.apache.james.mime4j.codec.Base64InputStream;
|
||||||
import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
|
import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
|
||||||
import org.apache.james.mime4j.util.MimeUtil;
|
import org.apache.james.mime4j.util.MimeUtil;
|
||||||
|
@ -953,6 +954,23 @@ public class MimeUtility {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String,String> getAllHeaderParameters(String headerValue) {
|
||||||
|
Map<String,String> result = new HashMap<>();
|
||||||
|
|
||||||
|
headerValue = headerValue.replaceAll("\r|\n", "");
|
||||||
|
String[] parts = headerValue.split(";");
|
||||||
|
for (String part : parts) {
|
||||||
|
String[] partParts = part.split("=", 2);
|
||||||
|
if (partParts.length == 2) {
|
||||||
|
String parameterName = partParts[0].trim().toLowerCase(Locale.US);
|
||||||
|
String parameterValue = partParts[1].trim();
|
||||||
|
result.put(parameterName, parameterValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Part findFirstPartByMimeType(Part part, String mimeType) {
|
public static Part findFirstPartByMimeType(Part part, String mimeType) {
|
||||||
if (part.getBody() instanceof Multipart) {
|
if (part.getBody() instanceof Multipart) {
|
||||||
Multipart multipart = (Multipart)part.getBody();
|
Multipart multipart = (Multipart)part.getBody();
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
|
import com.fsck.k9.autocrypt.AutocryptOperations;
|
||||||
import com.fsck.k9.ui.crypto.OpenPgpApiFactory;
|
import com.fsck.k9.ui.crypto.OpenPgpApiFactory;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
@ -270,7 +271,8 @@ public class MessageLoaderHelper {
|
||||||
messageCryptoHelper = retainCryptoHelperFragment.getData();
|
messageCryptoHelper = retainCryptoHelperFragment.getData();
|
||||||
}
|
}
|
||||||
if (messageCryptoHelper == null || messageCryptoHelper.isConfiguredForOutdatedCryptoProvider()) {
|
if (messageCryptoHelper == null || messageCryptoHelper.isConfiguredForOutdatedCryptoProvider()) {
|
||||||
messageCryptoHelper = new MessageCryptoHelper(context, new OpenPgpApiFactory());
|
messageCryptoHelper = new MessageCryptoHelper(
|
||||||
|
context, new OpenPgpApiFactory(), AutocryptOperations.getInstance());
|
||||||
retainCryptoHelperFragment.setData(messageCryptoHelper);
|
retainCryptoHelperFragment.setData(messageCryptoHelper);
|
||||||
}
|
}
|
||||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(
|
messageCryptoHelper.asyncStartOrResumeProcessingMessage(
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.fsck.k9.autocrypt;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
class AutocryptHeader {
|
||||||
|
static final String AUTOCRYPT_HEADER = "Autocrypt";
|
||||||
|
|
||||||
|
static final String AUTOCRYPT_PARAM_TO = "addr";
|
||||||
|
static final String AUTOCRYPT_PARAM_KEY_DATA = "keydata";
|
||||||
|
|
||||||
|
static final String AUTOCRYPT_PARAM_TYPE = "type";
|
||||||
|
static final String AUTOCRYPT_TYPE_1 = "1";
|
||||||
|
|
||||||
|
static final String AUTOCRYPT_PARAM_PREFER_ENCRYPT = "prefer-encrypt";
|
||||||
|
static final String AUTOCRYPT_PREFER_ENCRYPT_MUTUAL = "mutual";
|
||||||
|
|
||||||
|
|
||||||
|
final byte[] keyData;
|
||||||
|
final String addr;
|
||||||
|
final Map<String,String> parameters;
|
||||||
|
final boolean isPreferEncryptMutual;
|
||||||
|
|
||||||
|
AutocryptHeader(Map<String, String> parameters, String addr, byte[] keyData, boolean isPreferEncryptMutual) {
|
||||||
|
this.parameters = parameters;
|
||||||
|
this.addr = addr;
|
||||||
|
this.keyData = keyData;
|
||||||
|
this.isPreferEncryptMutual = isPreferEncryptMutual;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package com.fsck.k9.autocrypt;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.fsck.k9.mail.Message;
|
||||||
|
import com.fsck.k9.mail.internet.MimeUtility;
|
||||||
|
import okio.ByteString;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
|
class AutocryptHeaderParser {
|
||||||
|
private static final AutocryptHeaderParser INSTANCE = new AutocryptHeaderParser();
|
||||||
|
|
||||||
|
|
||||||
|
public static AutocryptHeaderParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AutocryptHeaderParser() { }
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
AutocryptHeader getValidAutocryptHeader(Message currentMessage) {
|
||||||
|
String[] headers = currentMessage.getHeader(AutocryptHeader.AUTOCRYPT_HEADER);
|
||||||
|
ArrayList<AutocryptHeader> autocryptHeaders = parseAllAutocryptHeaders(headers);
|
||||||
|
|
||||||
|
boolean isSingleValidHeader = autocryptHeaders.size() == 1;
|
||||||
|
return isSingleValidHeader ? autocryptHeaders.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private AutocryptHeader parseAutocryptHeader(String headerValue) {
|
||||||
|
Map<String,String> parameters = MimeUtility.getAllHeaderParameters(headerValue);
|
||||||
|
|
||||||
|
String type = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_TYPE);
|
||||||
|
if (type != null && !type.equals(AutocryptHeader.AUTOCRYPT_TYPE_1)) {
|
||||||
|
Timber.e("autocrypt: unsupported type parameter %s", type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String base64KeyData = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA);
|
||||||
|
if (base64KeyData == null) {
|
||||||
|
Timber.e("autocrypt: missing key parameter");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteString byteString = ByteString.decodeBase64(base64KeyData);
|
||||||
|
if (byteString == null) {
|
||||||
|
Timber.e("autocrypt: error parsing base64 data");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String to = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_TO);
|
||||||
|
if (to == null) {
|
||||||
|
Timber.e("autocrypt: no to header!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPreferEncryptMutual = false;
|
||||||
|
String preferEncrypt = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_PREFER_ENCRYPT);
|
||||||
|
if (AutocryptHeader.AUTOCRYPT_PREFER_ENCRYPT_MUTUAL.equalsIgnoreCase(preferEncrypt)) {
|
||||||
|
isPreferEncryptMutual = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCriticalParameters(parameters)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AutocryptHeader(parameters, to, byteString.toByteArray(), isPreferEncryptMutual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCriticalParameters(Map<String, String> parameters) {
|
||||||
|
for (String parameterName : parameters.keySet()) {
|
||||||
|
if (parameterName != null && !parameterName.startsWith("_")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private ArrayList<AutocryptHeader> parseAllAutocryptHeaders(String[] headers) {
|
||||||
|
ArrayList<AutocryptHeader> autocryptHeaders = new ArrayList<>();
|
||||||
|
for (String header : headers) {
|
||||||
|
AutocryptHeader autocryptHeader = parseAutocryptHeader(header);
|
||||||
|
if (autocryptHeader != null) {
|
||||||
|
autocryptHeaders.add(autocryptHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return autocryptHeaders;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.fsck.k9.autocrypt;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.fsck.k9.mail.Message;
|
||||||
|
import org.openintents.openpgp.AutocryptPeerUpdate;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
|
||||||
|
|
||||||
|
public class AutocryptOperations {
|
||||||
|
private final AutocryptHeaderParser autocryptHeaderParser;
|
||||||
|
|
||||||
|
|
||||||
|
public static AutocryptOperations getInstance() {
|
||||||
|
AutocryptHeaderParser autocryptHeaderParser = AutocryptHeaderParser.getInstance();
|
||||||
|
return new AutocryptOperations(autocryptHeaderParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private AutocryptOperations(AutocryptHeaderParser autocryptHeaderParser) {
|
||||||
|
this.autocryptHeaderParser = autocryptHeaderParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addAutocryptPeerUpdateToIntentIfPresent(Message currentMessage, Intent intent) {
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(currentMessage);
|
||||||
|
if (autocryptHeader == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String messageFromAddress = currentMessage.getFrom()[0].getAddress();
|
||||||
|
if (!autocryptHeader.addr.equalsIgnoreCase(messageFromAddress)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date messageDate = currentMessage.getSentDate();
|
||||||
|
Date internalDate = currentMessage.getInternalDate();
|
||||||
|
Date effectiveDate = messageDate.before(internalDate) ? messageDate : internalDate;
|
||||||
|
|
||||||
|
AutocryptPeerUpdate data = AutocryptPeerUpdate.create(
|
||||||
|
autocryptHeader.keyData, effectiveDate, autocryptHeader.isPreferEncryptMutual);
|
||||||
|
intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, messageFromAddress);
|
||||||
|
intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_UPDATE, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAutocryptHeader(Message currentMessage) {
|
||||||
|
return currentMessage.getHeader(AutocryptHeader.AUTOCRYPT_HEADER).length > 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,8 @@ import android.content.Intent;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import com.fsck.k9.Globals;
|
import com.fsck.k9.Globals;
|
||||||
import com.fsck.k9.K9;
|
|
||||||
import com.fsck.k9.activity.compose.ComposeCryptoStatus;
|
import com.fsck.k9.activity.compose.ComposeCryptoStatus;
|
||||||
import com.fsck.k9.mail.Body;
|
import com.fsck.k9.mail.Body;
|
||||||
import com.fsck.k9.mail.BodyPart;
|
import com.fsck.k9.mail.BodyPart;
|
||||||
|
@ -36,6 +34,7 @@ import org.apache.james.mime4j.util.MimeUtil;
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
public class PgpMessageBuilder extends MessageBuilder {
|
public class PgpMessageBuilder extends MessageBuilder {
|
||||||
|
@ -154,7 +153,7 @@ public class PgpMessageBuilder extends MessageBuilder {
|
||||||
throw new MessagingException("encryption is enabled, but no recipient specified!");
|
throw new MessagingException("encryption is enabled, but no recipient specified!");
|
||||||
}
|
}
|
||||||
pgpApiIntent.putExtra(OpenPgpApi.EXTRA_USER_IDS, encryptRecipientAddresses);
|
pgpApiIntent.putExtra(OpenPgpApi.EXTRA_USER_IDS, encryptRecipientAddresses);
|
||||||
pgpApiIntent.putExtra(OpenPgpApi.EXTRA_ENCRYPT_OPPORTUNISTIC, cryptoStatus.isEncryptionOpportunistic());
|
pgpApiIntent.putExtra(OpenPgpApi.EXTRA_OPPORTUNISTIC_ENCRYPTION, cryptoStatus.isEncryptionOpportunistic());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pgpApiIntent = new Intent(isPgpInlineMode ? OpenPgpApi.ACTION_SIGN : OpenPgpApi.ACTION_DETACHED_SIGN);
|
pgpApiIntent = new Intent(isPgpInlineMode ? OpenPgpApi.ACTION_SIGN : OpenPgpApi.ACTION_DETACHED_SIGN);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.WorkerThread;
|
import android.support.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.fsck.k9.K9;
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.autocrypt.AutocryptOperations;
|
||||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
||||||
import com.fsck.k9.mail.Address;
|
import com.fsck.k9.mail.Address;
|
||||||
import com.fsck.k9.mail.Body;
|
import com.fsck.k9.mail.Body;
|
||||||
|
@ -45,6 +46,7 @@ import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.CancelableBackgroundOperation;
|
import org.openintents.openpgp.util.OpenPgpApi.CancelableBackgroundOperation;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpSinkResultCallback;
|
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpSinkResultCallback;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSink;
|
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSink;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
||||||
|
@ -62,8 +64,9 @@ public class MessageCryptoHelper {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final String openPgpProviderPackage;
|
private final String openPgpProviderPackage;
|
||||||
|
private final AutocryptOperations autocryptOperations;
|
||||||
private final Object callbackLock = new Object();
|
private final Object callbackLock = new Object();
|
||||||
private final Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<>();
|
private final Deque<CryptoPart> partsToProcess = new ArrayDeque<>();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MessageCryptoCallback callback;
|
private MessageCryptoCallback callback;
|
||||||
|
@ -78,7 +81,7 @@ public class MessageCryptoHelper {
|
||||||
private CryptoPart currentCryptoPart;
|
private CryptoPart currentCryptoPart;
|
||||||
private Intent currentCryptoResult;
|
private Intent currentCryptoResult;
|
||||||
private Intent userInteractionResultIntent;
|
private Intent userInteractionResultIntent;
|
||||||
private boolean secondPassStarted;
|
private State state;
|
||||||
private CancelableBackgroundOperation cancelableBackgroundOperation;
|
private CancelableBackgroundOperation cancelableBackgroundOperation;
|
||||||
private boolean isCancelled;
|
private boolean isCancelled;
|
||||||
|
|
||||||
|
@ -87,13 +90,15 @@ public class MessageCryptoHelper {
|
||||||
private OpenPgpApiFactory openPgpApiFactory;
|
private OpenPgpApiFactory openPgpApiFactory;
|
||||||
|
|
||||||
|
|
||||||
public MessageCryptoHelper(Context context, OpenPgpApiFactory openPgpApiFactory) {
|
public MessageCryptoHelper(Context context, OpenPgpApiFactory openPgpApiFactory,
|
||||||
|
AutocryptOperations autocryptOperations) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
|
|
||||||
if (!K9.isOpenPgpProviderConfigured()) {
|
if (!K9.isOpenPgpProviderConfigured()) {
|
||||||
throw new IllegalStateException("MessageCryptoHelper must only be called with a openpgp provider!");
|
throw new IllegalStateException("MessageCryptoHelper must only be called with a OpenPGP provider!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.autocryptOperations = autocryptOperations;
|
||||||
this.openPgpApiFactory = openPgpApiFactory;
|
this.openPgpApiFactory = openPgpApiFactory;
|
||||||
openPgpProviderPackage = K9.getOpenPgpProvider();
|
openPgpProviderPackage = K9.getOpenPgpProvider();
|
||||||
}
|
}
|
||||||
|
@ -110,28 +115,37 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageAnnotations = new MessageCryptoAnnotations();
|
this.messageAnnotations = new MessageCryptoAnnotations();
|
||||||
|
this.state = State.START;
|
||||||
this.currentMessage = message;
|
this.currentMessage = message;
|
||||||
this.cachedDecryptionResult = cachedDecryptionResult;
|
this.cachedDecryptionResult = cachedDecryptionResult;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
runFirstPass();
|
nextStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runFirstPass() {
|
private void findPartsForEncryptionPass() {
|
||||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(currentMessage);
|
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(currentMessage);
|
||||||
processFoundEncryptedParts(encryptedParts);
|
processFoundEncryptedParts(encryptedParts);
|
||||||
|
|
||||||
decryptOrVerifyNextPart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runSecondPass() {
|
private void findPartsForSignaturePass() {
|
||||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(currentMessage, messageAnnotations);
|
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(currentMessage, messageAnnotations);
|
||||||
processFoundSignedParts(signedParts);
|
processFoundSignedParts(signedParts);
|
||||||
|
|
||||||
List<Part> inlineParts = MessageDecryptVerifier.findPgpInlineParts(currentMessage);
|
List<Part> inlineParts = MessageDecryptVerifier.findPgpInlineParts(currentMessage);
|
||||||
addFoundInlinePgpParts(inlineParts);
|
processFoundInlinePgpParts(inlineParts);
|
||||||
|
}
|
||||||
|
|
||||||
decryptOrVerifyNextPart();
|
private void findPartsForAutocryptPass() {
|
||||||
|
boolean otherCryptoPerformed = !messageAnnotations.isEmpty();
|
||||||
|
if (otherCryptoPerformed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autocryptOperations.hasAutocryptHeader(currentMessage)) {
|
||||||
|
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PLAIN_AUTOCRYPT, currentMessage);
|
||||||
|
partsToProcess.add(cryptoPart);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processFoundEncryptedParts(List<Part> foundParts) {
|
private void processFoundEncryptedParts(List<Part> foundParts) {
|
||||||
|
@ -142,7 +156,7 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
if (MessageDecryptVerifier.isPgpMimeEncryptedOrSignedPart(part)) {
|
if (MessageDecryptVerifier.isPgpMimeEncryptedOrSignedPart(part)) {
|
||||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_ENCRYPTED, part);
|
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_ENCRYPTED, part);
|
||||||
partsToDecryptOrVerify.add(cryptoPart);
|
partsToProcess.add(cryptoPart);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addErrorAnnotation(part, CryptoError.ENCRYPTED_BUT_UNSUPPORTED, MessageHelper.createEmptyPart());
|
addErrorAnnotation(part, CryptoError.ENCRYPTED_BUT_UNSUPPORTED, MessageHelper.createEmptyPart());
|
||||||
|
@ -158,7 +172,7 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
if (MessageDecryptVerifier.isPgpMimeEncryptedOrSignedPart(part)) {
|
if (MessageDecryptVerifier.isPgpMimeEncryptedOrSignedPart(part)) {
|
||||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_SIGNED, part);
|
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_SIGNED, part);
|
||||||
partsToDecryptOrVerify.add(cryptoPart);
|
partsToProcess.add(cryptoPart);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MimeBodyPart replacementPart = getMultipartSignedContentPartIfAvailable(part);
|
MimeBodyPart replacementPart = getMultipartSignedContentPartIfAvailable(part);
|
||||||
|
@ -171,7 +185,7 @@ public class MessageCryptoHelper {
|
||||||
messageAnnotations.put(part, annotation);
|
messageAnnotations.put(part, annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFoundInlinePgpParts(List<Part> foundParts) {
|
private void processFoundInlinePgpParts(List<Part> foundParts) {
|
||||||
for (Part part : foundParts) {
|
for (Part part : foundParts) {
|
||||||
if (!currentMessage.getFlags().contains(Flag.X_DOWNLOADED_FULL)) {
|
if (!currentMessage.getFlags().contains(Flag.X_DOWNLOADED_FULL)) {
|
||||||
if (MessageDecryptVerifier.isPartPgpInlineEncrypted(part)) {
|
if (MessageDecryptVerifier.isPartPgpInlineEncrypted(part)) {
|
||||||
|
@ -184,29 +198,34 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_INLINE, part);
|
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_INLINE, part);
|
||||||
partsToDecryptOrVerify.add(cryptoPart);
|
partsToProcess.add(cryptoPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decryptOrVerifyNextPart() {
|
private void nextStep() {
|
||||||
if (isCancelled) {
|
if (isCancelled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partsToDecryptOrVerify.isEmpty()) {
|
while (state != State.FINISHED && partsToProcess.isEmpty()) {
|
||||||
runSecondPassOrReturnResultToFragment();
|
findPartsForNextPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == State.FINISHED) {
|
||||||
|
callbackReturnResult();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPart cryptoPart = partsToDecryptOrVerify.peekFirst();
|
|
||||||
startDecryptingOrVerifyingPart(cryptoPart);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startDecryptingOrVerifyingPart(CryptoPart cryptoPart) {
|
|
||||||
if (!isBoundToCryptoProviderService()) {
|
if (!isBoundToCryptoProviderService()) {
|
||||||
connectToCryptoProviderService();
|
connectToCryptoProviderService();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCryptoPart = partsToProcess.peekFirst();
|
||||||
|
if (currentCryptoPart.type == CryptoPartType.PLAIN_AUTOCRYPT) {
|
||||||
|
processAutocryptHeaderForCurrentPart();
|
||||||
} else {
|
} else {
|
||||||
decryptOrVerifyPart(cryptoPart);
|
decryptOrVerifyCurrentPart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +241,7 @@ public class MessageCryptoHelper {
|
||||||
public void onBound(IOpenPgpService2 service) {
|
public void onBound(IOpenPgpService2 service) {
|
||||||
openPgpApi = openPgpApiFactory.createOpenPgpApi(context, service);
|
openPgpApi = openPgpApiFactory.createOpenPgpApi(context, service);
|
||||||
|
|
||||||
decryptOrVerifyNextPart();
|
nextStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -234,24 +253,26 @@ public class MessageCryptoHelper {
|
||||||
openPgpServiceConnection.bindToService();
|
openPgpServiceConnection.bindToService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decryptOrVerifyPart(CryptoPart cryptoPart) {
|
private void decryptOrVerifyCurrentPart() {
|
||||||
currentCryptoPart = cryptoPart;
|
Intent apiIntent = userInteractionResultIntent;
|
||||||
Intent decryptIntent = userInteractionResultIntent;
|
|
||||||
userInteractionResultIntent = null;
|
userInteractionResultIntent = null;
|
||||||
if (decryptIntent == null) {
|
if (apiIntent == null) {
|
||||||
decryptIntent = getDecryptionIntent();
|
apiIntent = getDecryptVerifyIntent();
|
||||||
}
|
}
|
||||||
decryptVerify(decryptIntent);
|
decryptVerify(apiIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Intent getDecryptionIntent() {
|
private Intent getDecryptVerifyIntent() {
|
||||||
Intent decryptIntent = new Intent(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
Intent decryptIntent = new Intent(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||||
|
|
||||||
Address[] from = currentMessage.getFrom();
|
Address[] from = currentMessage.getFrom();
|
||||||
if (from.length > 0) {
|
if (from.length > 0) {
|
||||||
decryptIntent.putExtra(OpenPgpApi.EXTRA_SENDER_ADDRESS, from[0].getAddress());
|
decryptIntent.putExtra(OpenPgpApi.EXTRA_SENDER_ADDRESS, from[0].getAddress());
|
||||||
|
// we add this here independently of the autocrypt peer update, to allow picking up signing keys as gossip
|
||||||
|
decryptIntent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, from[0].getAddress());
|
||||||
}
|
}
|
||||||
|
autocryptOperations.addAutocryptPeerUpdateToIntentIfPresent(currentMessage, decryptIntent);
|
||||||
|
|
||||||
decryptIntent.putExtra(OpenPgpApi.EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING, true);
|
decryptIntent.putExtra(OpenPgpApi.EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING, true);
|
||||||
decryptIntent.putExtra(OpenPgpApi.EXTRA_DECRYPTION_RESULT, cachedDecryptionResult);
|
decryptIntent.putExtra(OpenPgpApi.EXTRA_DECRYPTION_RESULT, cachedDecryptionResult);
|
||||||
|
@ -259,22 +280,24 @@ public class MessageCryptoHelper {
|
||||||
return decryptIntent;
|
return decryptIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decryptVerify(Intent intent) {
|
private void decryptVerify(Intent apiIntent) {
|
||||||
try {
|
try {
|
||||||
CryptoPartType cryptoPartType = currentCryptoPart.type;
|
CryptoPartType cryptoPartType = currentCryptoPart.type;
|
||||||
switch (cryptoPartType) {
|
switch (cryptoPartType) {
|
||||||
case PGP_SIGNED: {
|
case PGP_SIGNED: {
|
||||||
callAsyncDetachedVerify(intent);
|
callAsyncDetachedVerify(apiIntent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case PGP_ENCRYPTED: {
|
case PGP_ENCRYPTED: {
|
||||||
callAsyncDecrypt(intent);
|
callAsyncDecrypt(apiIntent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case PGP_INLINE: {
|
case PGP_INLINE: {
|
||||||
callAsyncInlineOperation(intent);
|
callAsyncInlineOperation(apiIntent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case PLAIN_AUTOCRYPT:
|
||||||
|
throw new IllegalStateException("This part type must have been handled previously!");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalStateException("Unknown crypto part type: " + cryptoPartType);
|
throw new IllegalStateException("Unknown crypto part type: " + cryptoPartType);
|
||||||
|
@ -285,6 +308,23 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processAutocryptHeaderForCurrentPart() {
|
||||||
|
Intent intent = new Intent(OpenPgpApi.ACTION_UPDATE_AUTOCRYPT_PEER);
|
||||||
|
boolean hasInlineKeyData = autocryptOperations.addAutocryptPeerUpdateToIntentIfPresent(
|
||||||
|
(Message) currentCryptoPart.part, intent);
|
||||||
|
if (hasInlineKeyData) {
|
||||||
|
Timber.d("Passing autocrypt data from plain mail to OpenPGP API");
|
||||||
|
// We don't care about the result here, so we just call this fire-and-forget wait to minimize delay
|
||||||
|
openPgpApi.executeApiAsync(intent, null, null, new IOpenPgpCallback() {
|
||||||
|
@Override
|
||||||
|
public void onReturn(Intent result) {
|
||||||
|
Timber.d("Autocrypt update OK!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onCryptoFinished();
|
||||||
|
}
|
||||||
|
|
||||||
private void callAsyncInlineOperation(Intent intent) throws IOException {
|
private void callAsyncInlineOperation(Intent intent) throws IOException {
|
||||||
OpenPgpDataSource dataSource = getDataSourceForEncryptedOrInlineData();
|
OpenPgpDataSource dataSource = getDataSourceForEncryptedOrInlineData();
|
||||||
OpenPgpDataSink<MimeBodyPart> dataSink = getDataSinkForDecryptedInlineData();
|
OpenPgpDataSink<MimeBodyPart> dataSink = getDataSinkForDecryptedInlineData();
|
||||||
|
@ -534,7 +574,7 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
userInteractionResultIntent = data;
|
userInteractionResultIntent = data;
|
||||||
decryptOrVerifyNextPart();
|
nextStep();
|
||||||
} else {
|
} else {
|
||||||
onCryptoOperationCanceled();
|
onCryptoOperationCanceled();
|
||||||
}
|
}
|
||||||
|
@ -586,31 +626,55 @@ public class MessageCryptoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCryptoFinished() {
|
private void onCryptoFinished() {
|
||||||
boolean currentPartIsFirstInQueue = partsToDecryptOrVerify.peekFirst() == currentCryptoPart;
|
boolean currentPartIsFirstInQueue = partsToProcess.peekFirst() == currentCryptoPart;
|
||||||
if (!currentPartIsFirstInQueue) {
|
if (!currentPartIsFirstInQueue) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Trying to remove part from queue that is not the currently processed one!");
|
"Trying to remove part from queue that is not the currently processed one!");
|
||||||
}
|
}
|
||||||
if (currentCryptoPart != null) {
|
if (currentCryptoPart != null) {
|
||||||
partsToDecryptOrVerify.removeFirst();
|
partsToProcess.removeFirst();
|
||||||
currentCryptoPart = null;
|
currentCryptoPart = null;
|
||||||
} else {
|
} else {
|
||||||
Timber.e(new Throwable(), "Got to onCryptoFinished() with no part in processing!");
|
Timber.e(new Throwable(), "Got to onCryptoFinished() with no part in processing!");
|
||||||
}
|
}
|
||||||
decryptOrVerifyNextPart();
|
nextStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runSecondPassOrReturnResultToFragment() {
|
private void findPartsForNextPass() {
|
||||||
if (secondPassStarted) {
|
switch (state) {
|
||||||
callbackReturnResult();
|
case START: {
|
||||||
|
state = State.ENCRYPTION;
|
||||||
|
|
||||||
|
findPartsForEncryptionPass();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
secondPassStarted = true;
|
|
||||||
runSecondPass();
|
case ENCRYPTION: {
|
||||||
|
state = State.SIGNATURES;
|
||||||
|
|
||||||
|
findPartsForSignaturePass();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case SIGNATURES: {
|
||||||
|
state = State.AUTOCRYPT;
|
||||||
|
|
||||||
|
findPartsForAutocryptPass();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AUTOCRYPT: {
|
||||||
|
state = State.FINISHED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
throw new IllegalStateException("unhandled state");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupAfterProcessingFinished() {
|
private void cleanupAfterProcessingFinished() {
|
||||||
partsToDecryptOrVerify.clear();
|
partsToProcess.clear();
|
||||||
openPgpApi = null;
|
openPgpApi = null;
|
||||||
if (openPgpServiceConnection != null) {
|
if (openPgpServiceConnection != null) {
|
||||||
openPgpServiceConnection.unbindFromService();
|
openPgpServiceConnection.unbindFromService();
|
||||||
|
@ -699,7 +763,8 @@ public class MessageCryptoHelper {
|
||||||
private enum CryptoPartType {
|
private enum CryptoPartType {
|
||||||
PGP_INLINE,
|
PGP_INLINE,
|
||||||
PGP_ENCRYPTED,
|
PGP_ENCRYPTED,
|
||||||
PGP_SIGNED
|
PGP_SIGNED,
|
||||||
|
PLAIN_AUTOCRYPT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -729,4 +794,8 @@ public class MessageCryptoHelper {
|
||||||
return NO_REPLACEMENT_PART;
|
return NO_REPLACEMENT_PART;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum State {
|
||||||
|
START, ENCRYPTION, SIGNATURES, AUTOCRYPT, FINISHED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
package com.fsck.k9.autocrypt;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import com.fsck.k9.mail.MessagingException;
|
||||||
|
import com.fsck.k9.mail.internet.BinaryTempFileBody;
|
||||||
|
import com.fsck.k9.mail.internet.MimeMessage;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(manifest = Config.NONE, sdk = 21)
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class AutocryptHeaderParserTest {
|
||||||
|
AutocryptHeaderParser autocryptHeaderParser = AutocryptHeaderParser.getInstance();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
BinaryTempFileBody.setTempDirectory(RuntimeEnvironment.application.getCacheDir());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test cases taken from: https://github.com/mailencrypt/autocrypt/tree/master/src/tests/data
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withNoHeader__shouldReturnNull() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/no_autocrypt.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNull(autocryptHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withBrokenBase64__shouldReturnNull() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/rsa2048-broken-base64.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNull(autocryptHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withSimpleAutocrypt() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/rsa2048-simple.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNotNull(autocryptHeader);
|
||||||
|
assertEquals("alice@testsuite.autocrypt.org", autocryptHeader.addr);
|
||||||
|
assertEquals(0, autocryptHeader.parameters.size());
|
||||||
|
assertEquals(1225, autocryptHeader.keyData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withExplicitType() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/rsa2048-explicit-type.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNotNull(autocryptHeader);
|
||||||
|
assertEquals("alice@testsuite.autocrypt.org", autocryptHeader.addr);
|
||||||
|
assertEquals(0, autocryptHeader.parameters.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withUnknownType__shouldReturnNull() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/unknown-type.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNull(autocryptHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withUnknownCriticalHeader__shouldReturnNull() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/rsa2048-unknown-critical.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNull(autocryptHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValidAutocryptHeader__withUnknownNonCriticalHeader() throws Exception {
|
||||||
|
MimeMessage message = parseFromResource("autocrypt/rsa2048-unknown-non-critical.eml");
|
||||||
|
|
||||||
|
AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);
|
||||||
|
|
||||||
|
assertNotNull(autocryptHeader);
|
||||||
|
assertEquals("alice@testsuite.autocrypt.org", autocryptHeader.addr);
|
||||||
|
assertEquals(1, autocryptHeader.parameters.size());
|
||||||
|
assertEquals("ignore", autocryptHeader.parameters.get("_monkey"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MimeMessage parseFromResource(String resourceName) throws IOException, MessagingException {
|
||||||
|
InputStream inputStream = readFromResourceFile(resourceName);
|
||||||
|
return MimeMessage.parseMimeMessage(inputStream, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream readFromResourceFile(String name) throws FileNotFoundException {
|
||||||
|
return new FileInputStream(RuntimeEnvironment.application.getPackageResourcePath() + "/src/test/resources/" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -277,7 +277,7 @@ public class PgpMessageBuilderTest {
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, TEST_SIGN_KEY_ID);
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, TEST_SIGN_KEY_ID);
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, new long[] { TEST_SELF_ENCRYPT_KEY_ID });
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, new long[] { TEST_SELF_ENCRYPT_KEY_ID });
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_ENCRYPT_OPPORTUNISTIC, false);
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_OPPORTUNISTIC_ENCRYPTION, false);
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_USER_IDS, cryptoStatus.getRecipientAddresses());
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_USER_IDS, cryptoStatus.getRecipientAddresses());
|
||||||
assertIntentEqualsActionAndExtras(expectedApiIntent, capturedApiIntent.getValue());
|
assertIntentEqualsActionAndExtras(expectedApiIntent, capturedApiIntent.getValue());
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ public class PgpMessageBuilderTest {
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, TEST_SIGN_KEY_ID);
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, TEST_SIGN_KEY_ID);
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, new long[] { TEST_SELF_ENCRYPT_KEY_ID });
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, new long[] { TEST_SELF_ENCRYPT_KEY_ID });
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_ENCRYPT_OPPORTUNISTIC, false);
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_OPPORTUNISTIC_ENCRYPTION, false);
|
||||||
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_USER_IDS, cryptoStatus.getRecipientAddresses());
|
expectedApiIntent.putExtra(OpenPgpApi.EXTRA_USER_IDS, cryptoStatus.getRecipientAddresses());
|
||||||
assertIntentEqualsActionAndExtras(expectedApiIntent, capturedApiIntent.getValue());
|
assertIntentEqualsActionAndExtras(expectedApiIntent, capturedApiIntent.getValue());
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.fsck.k9.ui.crypto;
|
package com.fsck.k9.ui.crypto;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
@ -8,6 +9,7 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.fsck.k9.K9;
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.autocrypt.AutocryptOperations;
|
||||||
import com.fsck.k9.mail.Address;
|
import com.fsck.k9.mail.Address;
|
||||||
import com.fsck.k9.mail.Body;
|
import com.fsck.k9.mail.Body;
|
||||||
import com.fsck.k9.mail.BodyPart;
|
import com.fsck.k9.mail.BodyPart;
|
||||||
|
@ -27,6 +29,7 @@ import org.openintents.openpgp.IOpenPgpService2;
|
||||||
import org.openintents.openpgp.OpenPgpDecryptionResult;
|
import org.openintents.openpgp.OpenPgpDecryptionResult;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpSinkResultCallback;
|
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpSinkResultCallback;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSink;
|
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSink;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
||||||
|
@ -38,6 +41,8 @@ import static junit.framework.Assert.assertEquals;
|
||||||
import static junit.framework.Assert.assertSame;
|
import static junit.framework.Assert.assertSame;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Matchers.same;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
@ -54,17 +59,21 @@ public class MessageCryptoHelperTest {
|
||||||
private Intent capturedApiIntent;
|
private Intent capturedApiIntent;
|
||||||
private IOpenPgpSinkResultCallback capturedCallback;
|
private IOpenPgpSinkResultCallback capturedCallback;
|
||||||
private MessageCryptoCallback messageCryptoCallback;
|
private MessageCryptoCallback messageCryptoCallback;
|
||||||
|
private AutocryptOperations autocryptOperations;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
openPgpApi = mock(OpenPgpApi.class);
|
openPgpApi = mock(OpenPgpApi.class);
|
||||||
|
autocryptOperations = mock(AutocryptOperations.class);
|
||||||
|
|
||||||
K9.setOpenPgpProvider("org.example.dummy");
|
K9.setOpenPgpProvider("org.example.dummy");
|
||||||
|
|
||||||
OpenPgpApiFactory openPgpApiFactory = mock(OpenPgpApiFactory.class);
|
OpenPgpApiFactory openPgpApiFactory = mock(OpenPgpApiFactory.class);
|
||||||
when(openPgpApiFactory.createOpenPgpApi(any(Context.class), any(IOpenPgpService2.class))).thenReturn(openPgpApi);
|
when(openPgpApiFactory.createOpenPgpApi(any(Context.class), any(IOpenPgpService2.class))).thenReturn(openPgpApi);
|
||||||
messageCryptoHelper = new MessageCryptoHelper(RuntimeEnvironment.application, openPgpApiFactory);
|
|
||||||
|
messageCryptoHelper = new MessageCryptoHelper(RuntimeEnvironment.application, openPgpApiFactory,
|
||||||
|
autocryptOperations);
|
||||||
messageCryptoCallback = mock(MessageCryptoCallback.class);
|
messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +91,35 @@ public class MessageCryptoHelperTest {
|
||||||
MessageCryptoAnnotations annotations = captor.getValue();
|
MessageCryptoAnnotations annotations = captor.getValue();
|
||||||
assertTrue(annotations.isEmpty());
|
assertTrue(annotations.isEmpty());
|
||||||
verifyNoMoreInteractions(messageCryptoCallback);
|
verifyNoMoreInteractions(messageCryptoCallback);
|
||||||
|
|
||||||
|
verify(autocryptOperations).hasAutocryptHeader(message);
|
||||||
|
verifyNoMoreInteractions(autocryptOperations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void textPlain_withAutocrypt() throws Exception {
|
||||||
|
MimeMessage message = new MimeMessage();
|
||||||
|
message.setUid("msguid");
|
||||||
|
message.setHeader("Content-Type", "text/plain");
|
||||||
|
|
||||||
|
when(autocryptOperations.hasAutocryptHeader(message)).thenReturn(true);
|
||||||
|
when(autocryptOperations.addAutocryptPeerUpdateToIntentIfPresent(same(message), any(Intent.class))).thenReturn(true);
|
||||||
|
|
||||||
|
|
||||||
|
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||||
|
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||||
|
|
||||||
|
|
||||||
|
ArgumentCaptor<MessageCryptoAnnotations> captor = ArgumentCaptor.forClass(MessageCryptoAnnotations.class);
|
||||||
|
verify(messageCryptoCallback).onCryptoOperationsFinished(captor.capture());
|
||||||
|
MessageCryptoAnnotations annotations = captor.getValue();
|
||||||
|
assertTrue(annotations.isEmpty());
|
||||||
|
verifyNoMoreInteractions(messageCryptoCallback);
|
||||||
|
|
||||||
|
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
verify(autocryptOperations).addAutocryptPeerUpdateToIntentIfPresent(same(message), intentCaptor.capture());
|
||||||
|
verify(openPgpApi).executeApiAsync(same(intentCaptor.getValue()), same((InputStream) null),
|
||||||
|
same((OutputStream) null), any(IOpenPgpCallback.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -161,6 +199,9 @@ public class MessageCryptoHelperTest {
|
||||||
|
|
||||||
assertEquals(OpenPgpApi.ACTION_DECRYPT_VERIFY, capturedApiIntent.getAction());
|
assertEquals(OpenPgpApi.ACTION_DECRYPT_VERIFY, capturedApiIntent.getAction());
|
||||||
assertEquals("test@example.org", capturedApiIntent.getStringExtra(OpenPgpApi.EXTRA_SENDER_ADDRESS));
|
assertEquals("test@example.org", capturedApiIntent.getStringExtra(OpenPgpApi.EXTRA_SENDER_ADDRESS));
|
||||||
|
|
||||||
|
verify(autocryptOperations).addAutocryptPeerUpdateToIntentIfPresent(message, capturedApiIntent);
|
||||||
|
verifyNoMoreInteractions(autocryptOperations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -201,6 +242,8 @@ public class MessageCryptoHelperTest {
|
||||||
assertEquals("test@example.org", capturedApiIntent.getStringExtra(OpenPgpApi.EXTRA_SENDER_ADDRESS));
|
assertEquals("test@example.org", capturedApiIntent.getStringExtra(OpenPgpApi.EXTRA_SENDER_ADDRESS));
|
||||||
assertPartAnnotationHasState(message, messageCryptoCallback, CryptoError.OPENPGP_OK, decryptedPart,
|
assertPartAnnotationHasState(message, messageCryptoCallback, CryptoError.OPENPGP_OK, decryptedPart,
|
||||||
decryptionResult, signatureResult, pendingIntent);
|
decryptionResult, signatureResult, pendingIntent);
|
||||||
|
verify(autocryptOperations).addAutocryptPeerUpdateToIntentIfPresent(message, capturedApiIntent);
|
||||||
|
verifyNoMoreInteractions(autocryptOperations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processEncryptedMessageAndCaptureMocks(Message message, Body encryptedBody, OutputStream outputStream)
|
private void processEncryptedMessageAndCaptureMocks(Message message, Body encryptedBody, OutputStream outputStream)
|
||||||
|
|
11
k9mail/src/test/resources/autocrypt/no_autocrypt.eml
Normal file
11
k9mail/src/test/resources/autocrypt/no_autocrypt.eml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: INBOME with invalid type attribute
|
||||||
|
Date: Sat, 17 Dec 2016 10:51:48 +0100
|
||||||
|
Message-ID: <unknown-type@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This message contains no INBOME header
|
||||||
|
|
||||||
|
An agent capable of INBOME level 0 should not try to parse it as a header and crash.
|
|
@ -0,0 +1,35 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: an INBOME RSA test
|
||||||
|
Autocrypt: addr=alice@testsuite.autocrypt.org; keydata=
|
||||||
|
m!@#$%hVF+ABCADu17FBUgA3mCemeKbNaBTyWe3VGxjbu7fUyHgdLK7i3tnd7IRtxQy/AEN2t6Vq
|
||||||
|
0/xeZEAKYRInsHI/HjvmhqPeWFzipk71jRQ02WUY1pZytFjYNIrTdMk4eLYdC1N0go83PU33V4R8
|
||||||
|
fc2fWHD8N5JPsDH2xOB6WNWkMPxgMbtGIa0QTx7TINhDif4/1/VcrX3wz1gZ6xYI+sujbC54iBZo
|
||||||
|
qbEfu4SFVvp53d+a1plxBzuZ/X6nqJqcysiS7ORMieBvU6W/mVeiAxwN4qcAI5s+rGmRnP8ltONK
|
||||||
|
/P1ScH6lmELgqm8Z/M0wdiYgywme/bdEQOg3s0S/8nCIFmwUchN7ABEBAAG0HWFsaWNlQHRlc3Rz
|
||||||
|
dWl0ZS5hdXRvY3J5cHQub3JniQFOBBMBCAA4FiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+AC
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQuvxTPNmTvX/k4wf+JJZ0M0rZeAXbnxdR6HDU
|
||||||
|
ZYL734Z8x/HRpz3vzK4VQQJ4oIbUQPwydZmAlTlglQY48IWWOdJnYvn2pIhlTM/T8q9ZfmOyp6i1
|
||||||
|
jxFCPT+2ma4DjNOqYFhfnULE/MYc6xeVaBcwGj7yvAW7YY7156/wDo6+9TCd/a9mzOFCGS0yQoRa
|
||||||
|
K3uDajA+G/SmbC8t/3X8+5sapvi9Ru0HNkIzaj1jhH+kW6628E7nkf9aN9LodXHfs1UtfuLqM8VG
|
||||||
|
Ysk9474x9QxbsrJ4YvXeFwM9zAs+Pvj4lnpH/0WOU8jJc3uarluGH58kTHM5/5+p0TeMpOHX7OEw
|
||||||
|
JndsBOV9gFc6FMx4hLkBDQRYVRfiAQgA3ad+Aat4UY8xvQQutLYb8e417XZN1zVmKypyReB0l0Zf
|
||||||
|
HA6Qc7uxnJQ7dzIEZAxdnjvTYJaCFrOCBXAyPHpShVMpKqQP+kBBY/WiC3BSUALR3xqp7k5/sjLD
|
||||||
|
+K4dAacXEc7nyXP5o5+oqBXEH8Ls5X440c9A3EdsvVlncvSW5ILLItlFHmQd6f1ynnjK+FQwYJRJ
|
||||||
|
ypDuqJpYkA1vn7+XxeQShpX105rM3C8tJUxRAP3QFimenn4Zm2BDhQpCneuBt239rkXOAXsR0PnJ
|
||||||
|
fV8eNAEsE8IIqnPoSlBme5DZAri69+joYmTeSKGuj4aoxzDlx1AQigwpMISLciTXLnJypwARAQAB
|
||||||
|
iQE2BBgBCAAgFiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+ICGwwACgkQuvxTPNmTvX8dOwf9
|
||||||
|
H72BGoYJkuuFrbQ6F/mH7gG9z3ytQHRD2Z0ja+3O7YnJBpotHFFjF7yHGj0FtmQR0Q7KnhkJ/3mv
|
||||||
|
fkvuaH3Gcjli/E7VASastuFDFkGANLmGZVGQQ2iTYFG1aejjtGb01vcaPrgE9WDueMB+Pn6/QbDc
|
||||||
|
5SWCrVWrRFZKrwbAGw35GySoFYpxXyCNsk6q6Db56plllPZjrYj7axF0yN536D1ntEVFDOdKZq8x
|
||||||
|
Tb9P/4Tq9NKRLE4+aO6qCqEOz+V1OeOvYLw58BfnzXY8rXF93D/86YLyilv6p5WGaS/cRhIzr+Xq
|
||||||
|
+qBLD/vW+dh72e8MvcduX3tXV3Vkg0mkGekdOw==
|
||||||
|
Date: Sat, 17 Dec 2016 10:07:48 +0100
|
||||||
|
Message-ID: <rsa2048-simple@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This contains an INBOME header with invalid characters in the base64 key
|
||||||
|
data.
|
||||||
|
|
||||||
|
This header should be ignored by all user agents.
|
|
@ -0,0 +1,40 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: inbome rsa2048 with correct type
|
||||||
|
Autocrypt: addr=alice@testsuite.autocrypt.org; type=1; keydata=
|
||||||
|
mQENBFhVF+ABCADu17FBUgA3mCemeKbNaBTyWe3VGxjbu7fUyHgdLK7i3tnd7IRtxQy/AEN2t6Vq
|
||||||
|
0/xeZEAKYRInsHI/HjvmhqPeWFzipk71jRQ02WUY1pZytFjYNIrTdMk4eLYdC1N0go83PU33V4R8
|
||||||
|
fc2fWHD8N5JPsDH2xOB6WNWkMPxgMbtGIa0QTx7TINhDif4/1/VcrX3wz1gZ6xYI+sujbC54iBZo
|
||||||
|
qbEfu4SFVvp53d+a1plxBzuZ/X6nqJqcysiS7ORMieBvU6W/mVeiAxwN4qcAI5s+rGmRnP8ltONK
|
||||||
|
/P1ScH6lmELgqm8Z/M0wdiYgywme/bdEQOg3s0S/8nCIFmwUchN7ABEBAAG0HWFsaWNlQHRlc3Rz
|
||||||
|
dWl0ZS5hdXRvY3J5cHQub3JniQFOBBMBCAA4FiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+AC
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQuvxTPNmTvX/k4wf+JJZ0M0rZeAXbnxdR6HDU
|
||||||
|
ZYL734Z8x/HRpz3vzK4VQQJ4oIbUQPwydZmAlTlglQY48IWWOdJnYvn2pIhlTM/T8q9ZfmOyp6i1
|
||||||
|
jxFCPT+2ma4DjNOqYFhfnULE/MYc6xeVaBcwGj7yvAW7YY7156/wDo6+9TCd/a9mzOFCGS0yQoRa
|
||||||
|
K3uDajA+G/SmbC8t/3X8+5sapvi9Ru0HNkIzaj1jhH+kW6628E7nkf9aN9LodXHfs1UtfuLqM8VG
|
||||||
|
Ysk9474x9QxbsrJ4YvXeFwM9zAs+Pvj4lnpH/0WOU8jJc3uarluGH58kTHM5/5+p0TeMpOHX7OEw
|
||||||
|
JndsBOV9gFc6FMx4hLkBDQRYVRfiAQgA3ad+Aat4UY8xvQQutLYb8e417XZN1zVmKypyReB0l0Zf
|
||||||
|
HA6Qc7uxnJQ7dzIEZAxdnjvTYJaCFrOCBXAyPHpShVMpKqQP+kBBY/WiC3BSUALR3xqp7k5/sjLD
|
||||||
|
+K4dAacXEc7nyXP5o5+oqBXEH8Ls5X440c9A3EdsvVlncvSW5ILLItlFHmQd6f1ynnjK+FQwYJRJ
|
||||||
|
ypDuqJpYkA1vn7+XxeQShpX105rM3C8tJUxRAP3QFimenn4Zm2BDhQpCneuBt239rkXOAXsR0PnJ
|
||||||
|
fV8eNAEsE8IIqnPoSlBme5DZAri69+joYmTeSKGuj4aoxzDlx1AQigwpMISLciTXLnJypwARAQAB
|
||||||
|
iQE2BBgBCAAgFiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+ICGwwACgkQuvxTPNmTvX8dOwf9
|
||||||
|
H72BGoYJkuuFrbQ6F/mH7gG9z3ytQHRD2Z0ja+3O7YnJBpotHFFjF7yHGj0FtmQR0Q7KnhkJ/3mv
|
||||||
|
fkvuaH3Gcjli/E7VASastuFDFkGANLmGZVGQQ2iTYFG1aejjtGb01vcaPrgE9WDueMB+Pn6/QbDc
|
||||||
|
5SWCrVWrRFZKrwbAGw35GySoFYpxXyCNsk6q6Db56plllPZjrYj7axF0yN536D1ntEVFDOdKZq8x
|
||||||
|
Tb9P/4Tq9NKRLE4+aO6qCqEOz+V1OeOvYLw58BfnzXY8rXF93D/86YLyilv6p5WGaS/cRhIzr+Xq
|
||||||
|
+qBLD/vW+dh72e8MvcduX3tXV3Vkg0mkGekdOw==
|
||||||
|
Date: Sat, 17 Dec 2016 10:49:02 +0100
|
||||||
|
Message-ID: <rsa2048-explicit-type@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This message contains the standard INBOME header, but includes an
|
||||||
|
explicit "type=p" attribute. This is the default value of type, so it
|
||||||
|
should not be necessary to include this attribute.
|
||||||
|
|
||||||
|
"p" signifies that the key value is a specialized subset of OpenPGP.
|
||||||
|
|
||||||
|
This should be accepted by any agent capable of INBOME level 0.
|
||||||
|
|
||||||
|
--dkg
|
|
@ -0,0 +1,34 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Autocrypt-Bot <bot@autocrypt.org>
|
||||||
|
Subject: an INBOME RSA test
|
||||||
|
INBOME: to=alice@testsuite.autocrypt.org; keydata=
|
||||||
|
mQENBFhVF+ABCADu17FBUgA3mCemeKbNaBTyWe3VGxjbu7fUyHgdLK7i3tnd7IRtxQy/AEN2t6Vq
|
||||||
|
0/xeZEAKYRInsHI/HjvmhqPeWFzipk71jRQ02WUY1pZytFjYNIrTdMk4eLYdC1N0go83PU33V4R8
|
||||||
|
fc2fWHD8N5JPsDH2xOB6WNWkMPxgMbtGIa0QTx7TINhDif4/1/VcrX3wz1gZ6xYI+sujbC54iBZo
|
||||||
|
qbEfu4SFVvp53d+a1plxBzuZ/X6nqJqcysiS7ORMieBvU6W/mVeiAxwN4qcAI5s+rGmRnP8ltONK
|
||||||
|
/P1ScH6lmELgqm8Z/M0wdiYgywme/bdEQOg3s0S/8nCIFmwUchN7ABEBAAG0HWFsaWNlQHRlc3Rz
|
||||||
|
dWl0ZS5hdXRvY3J5cHQub3JniQFOBBMBCAA4FiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+AC
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQuvxTPNmTvX/k4wf+JJZ0M0rZeAXbnxdR6HDU
|
||||||
|
ZYL734Z8x/HRpz3vzK4VQQJ4oIbUQPwydZmAlTlglQY48IWWOdJnYvn2pIhlTM/T8q9ZfmOyp6i1
|
||||||
|
jxFCPT+2ma4DjNOqYFhfnULE/MYc6xeVaBcwGj7yvAW7YY7156/wDo6+9TCd/a9mzOFCGS0yQoRa
|
||||||
|
K3uDajA+G/SmbC8t/3X8+5sapvi9Ru0HNkIzaj1jhH+kW6628E7nkf9aN9LodXHfs1UtfuLqM8VG
|
||||||
|
Ysk9474x9QxbsrJ4YvXeFwM9zAs+Pvj4lnpH/0WOU8jJc3uarluGH58kTHM5/5+p0TeMpOHX7OEw
|
||||||
|
JndsBOV9gFc6FMx4hLkBDQRYVRfiAQgA3ad+Aat4UY8xvQQutLYb8e417XZN1zVmKypyReB0l0Zf
|
||||||
|
HA6Qc7uxnJQ7dzIEZAxdnjvTYJaCFrOCBXAyPHpShVMpKqQP+kBBY/WiC3BSUALR3xqp7k5/sjLD
|
||||||
|
+K4dAacXEc7nyXP5o5+oqBXEH8Ls5X440c9A3EdsvVlncvSW5ILLItlFHmQd6f1ynnjK+FQwYJRJ
|
||||||
|
ypDuqJpYkA1vn7+XxeQShpX105rM3C8tJUxRAP3QFimenn4Zm2BDhQpCneuBt239rkXOAXsR0PnJ
|
||||||
|
fV8eNAEsE8IIqnPoSlBme5DZAri69+joYmTeSKGuj4aoxzDlx1AQigwpMISLciTXLnJypwARAQAB
|
||||||
|
iQE2BBgBCAAgFiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+ICGwwACgkQuvxTPNmTvX8dOwf9
|
||||||
|
H72BGoYJkuuFrbQ6F/mH7gG9z3ytQHRD2Z0ja+3O7YnJBpotHFFjF7yHGj0FtmQR0Q7KnhkJ/3mv
|
||||||
|
fkvuaH3Gcjli/E7VASastuFDFkGANLmGZVGQQ2iTYFG1aejjtGb01vcaPrgE9WDueMB+Pn6/QbDc
|
||||||
|
5SWCrVWrRFZKrwbAGw35GySoFYpxXyCNsk6q6Db56plllPZjrYj7axF0yN536D1ntEVFDOdKZq8x
|
||||||
|
Tb9P/4Tq9NKRLE4+aO6qCqEOz+V1OeOvYLw58BfnzXY8rXF93D/86YLyilv6p5WGaS/cRhIzr+Xq
|
||||||
|
+qBLD/vW+dh72e8MvcduX3tXV3Vkg0mkGekdOw==
|
||||||
|
Date: Sat, 17 Dec 2016 10:07:48 +0100
|
||||||
|
Message-ID: <rsa2048-simple-to-bot@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This contains a default, minimal INBOME header using an RSA 2048 key.
|
||||||
|
|
||||||
|
This should be importable and valid by any agent supporting INBOME level 0.
|
34
k9mail/src/test/resources/autocrypt/rsa2048-simple.eml
Normal file
34
k9mail/src/test/resources/autocrypt/rsa2048-simple.eml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: an INBOME RSA test
|
||||||
|
Autocrypt: addr=alice@testsuite.autocrypt.org; keydata=
|
||||||
|
mQENBFhVF+ABCADu17FBUgA3mCemeKbNaBTyWe3VGxjbu7fUyHgdLK7i3tnd7IRtxQy/AEN2t6Vq
|
||||||
|
0/xeZEAKYRInsHI/HjvmhqPeWFzipk71jRQ02WUY1pZytFjYNIrTdMk4eLYdC1N0go83PU33V4R8
|
||||||
|
fc2fWHD8N5JPsDH2xOB6WNWkMPxgMbtGIa0QTx7TINhDif4/1/VcrX3wz1gZ6xYI+sujbC54iBZo
|
||||||
|
qbEfu4SFVvp53d+a1plxBzuZ/X6nqJqcysiS7ORMieBvU6W/mVeiAxwN4qcAI5s+rGmRnP8ltONK
|
||||||
|
/P1ScH6lmELgqm8Z/M0wdiYgywme/bdEQOg3s0S/8nCIFmwUchN7ABEBAAG0HWFsaWNlQHRlc3Rz
|
||||||
|
dWl0ZS5hdXRvY3J5cHQub3JniQFOBBMBCAA4FiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+AC
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQuvxTPNmTvX/k4wf+JJZ0M0rZeAXbnxdR6HDU
|
||||||
|
ZYL734Z8x/HRpz3vzK4VQQJ4oIbUQPwydZmAlTlglQY48IWWOdJnYvn2pIhlTM/T8q9ZfmOyp6i1
|
||||||
|
jxFCPT+2ma4DjNOqYFhfnULE/MYc6xeVaBcwGj7yvAW7YY7156/wDo6+9TCd/a9mzOFCGS0yQoRa
|
||||||
|
K3uDajA+G/SmbC8t/3X8+5sapvi9Ru0HNkIzaj1jhH+kW6628E7nkf9aN9LodXHfs1UtfuLqM8VG
|
||||||
|
Ysk9474x9QxbsrJ4YvXeFwM9zAs+Pvj4lnpH/0WOU8jJc3uarluGH58kTHM5/5+p0TeMpOHX7OEw
|
||||||
|
JndsBOV9gFc6FMx4hLkBDQRYVRfiAQgA3ad+Aat4UY8xvQQutLYb8e417XZN1zVmKypyReB0l0Zf
|
||||||
|
HA6Qc7uxnJQ7dzIEZAxdnjvTYJaCFrOCBXAyPHpShVMpKqQP+kBBY/WiC3BSUALR3xqp7k5/sjLD
|
||||||
|
+K4dAacXEc7nyXP5o5+oqBXEH8Ls5X440c9A3EdsvVlncvSW5ILLItlFHmQd6f1ynnjK+FQwYJRJ
|
||||||
|
ypDuqJpYkA1vn7+XxeQShpX105rM3C8tJUxRAP3QFimenn4Zm2BDhQpCneuBt239rkXOAXsR0PnJ
|
||||||
|
fV8eNAEsE8IIqnPoSlBme5DZAri69+joYmTeSKGuj4aoxzDlx1AQigwpMISLciTXLnJypwARAQAB
|
||||||
|
iQE2BBgBCAAgFiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+ICGwwACgkQuvxTPNmTvX8dOwf9
|
||||||
|
H72BGoYJkuuFrbQ6F/mH7gG9z3ytQHRD2Z0ja+3O7YnJBpotHFFjF7yHGj0FtmQR0Q7KnhkJ/3mv
|
||||||
|
fkvuaH3Gcjli/E7VASastuFDFkGANLmGZVGQQ2iTYFG1aejjtGb01vcaPrgE9WDueMB+Pn6/QbDc
|
||||||
|
5SWCrVWrRFZKrwbAGw35GySoFYpxXyCNsk6q6Db56plllPZjrYj7axF0yN536D1ntEVFDOdKZq8x
|
||||||
|
Tb9P/4Tq9NKRLE4+aO6qCqEOz+V1OeOvYLw58BfnzXY8rXF93D/86YLyilv6p5WGaS/cRhIzr+Xq
|
||||||
|
+qBLD/vW+dh72e8MvcduX3tXV3Vkg0mkGekdOw==
|
||||||
|
Date: Sat, 17 Dec 2016 10:07:48 +0100
|
||||||
|
Message-ID: <rsa2048-simple@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This contains a default, minimal INBOME header using an RSA 2048 key.
|
||||||
|
|
||||||
|
This should be importable and valid by any agent supporting INBOME level 0.
|
|
@ -0,0 +1,35 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: another inbome with rsa2048 but with an unknown critical attribute
|
||||||
|
Autocrypt: addr=alice@testsuite.autocrypt.org; danger=do-not-use; keydata=
|
||||||
|
mQENBFhVGA8BCADK+qTRkAfax0LtJ6RiyxzuAFyIohBTwvtcOM2sd/tRmWq1eyNif5AGDnc1+b6X
|
||||||
|
zJ6l3BXiYM/8qXU/F04UA5BP05SgIqXjqT5I13blrydjKtUbZFchK7lJU7cyDbar+TH70DZURSQm
|
||||||
|
MusCj0+fdx6hx8y4LSOM68rjwVeq7JXAPU78QQsYgMrbtkf5mZWUquDdb7tEoxU+PcNifvtvuHF2
|
||||||
|
ILv09a4Fi8thJG4i/3LxMFtmMLIiZWLfk5KpXAKrOy436e1LCm3vesALcihPNppb803dgBqpvvEE
|
||||||
|
9W7sg5NUy3P8+fTEuvI8HYYd+lEvYe2ojm4HVTts4YFHmzaGVzHLABEBAAG0HVRoaXMgc2hvdWxk
|
||||||
|
IG5ldmVyIGJlIGltcG9ydGVkiQFOBBMBCAA4FiEE0uuMX0KSMgVBfC/25MZusLe5gWMFAlhVGA8C
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQ5MZusLe5gWN9Hwf+PpLCCV7TiGc1nqIxLMTs
|
||||||
|
O84PVLSQZB642/QhLoMYXQ5iqty5H2FqGuK+uWLCnM+yIMDkcJC3ayWfa06fs3JOipVKlMh8hHnU
|
||||||
|
6/FHJB+3eZrc4lhh5B67Vi8Xg43pTP+I9ct/PlbHvD9kYw+DpcmCz0XILhaUP0R1oQ6M5KI49uLg
|
||||||
|
LAdNczcEtcw3A/hZ5ZTUe3o3gav0XDBXFCgGjkI+CaMjKb/HjgNM9YsrGxUxH1RFMYqTfrmCklHD
|
||||||
|
EboQc1Qtzi5rIwzVR3zSryve9KHH75TCfDApghwUBKSLNh374hjTFj5v5kPAxG3njX6EOqHS/UVX
|
||||||
|
Mn5aEVn0n6S1y+DJZLkBDQRYVRgRAQgAzQgD/CluB1wuBeI8qaqmIxG8epHCPstQ4kee6FuFWi3F
|
||||||
|
Lqtyk1R9tB4UL40gpEkpzB+qYms/zs9SeicuNcXoXA4bMcNGDFz3mZ1d9qG2izgC19e9p50oXiMY
|
||||||
|
cr8GM1Qcb77dmxlk829cBpr+X7NDKJy9VMGsqNYukgFDnNIzty0oMdCLSzpqi3UtXtCGYDqIiltU
|
||||||
|
aT8XdMAvddr6Scgpkz3wrqi/bVagc+q4IdKL0r8iL7o3EnTf/5Dc2XUaCFJLCa3Rk6oat5kTWjan
|
||||||
|
sp/K5k/VzSDcESji8n6xl0OzD2okhmX8iJZg1hhyI8hNmtW3boe51Hkkdlj+wC8Y2Fgh4QARAQAB
|
||||||
|
iQE2BBgBCAAgFiEE0uuMX0KSMgVBfC/25MZusLe5gWMFAlhVGBECGwwACgkQ5MZusLe5gWOn/Qf/
|
||||||
|
aeV7CqZW/YN4/LhXjJG7i+iDJYv/9Lr12dvgjO/sOlmDPHkEzXPMLKalm0biMPN7E1woQzcKt7Qy
|
||||||
|
eF/CRcVKK1TM6wdClOj2jErnWyx85/uZfnG9QRD41rhInk891A8LGebPZ6DJeJR/uwzMniEgNnKN
|
||||||
|
AMuGy95ckwlM3AfwzsKPTUUFnBAmSwWfMLRxjZPNefeo1Ic8mMRAT3d5sfDUx/4wm8tyiNLuOSkm
|
||||||
|
Ej6ONYpESD2sJGMo3ZY96pkzir7ZH++4mH6PwZg1ZT2nO+0PtaB9DHRGfBrzH85d4aLFZD9txx3p
|
||||||
|
ewabrNpYI/cJu9hUTaTM7wZaG5kmfStwihKYUg==
|
||||||
|
Date: Sat, 17 Dec 2016 10:32:49 +0100
|
||||||
|
Message-ID: <rsa2048-unknown-critical@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This message contains an INBOME header with RSA 2048, but with an
|
||||||
|
unknown critical attribute. Agents that are compatible with INBOME
|
||||||
|
level 0 should ignore this header because of the unknown critical
|
||||||
|
attribute.
|
|
@ -0,0 +1,36 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: inbome: rsa 2048 with unknown non-critical attribute
|
||||||
|
Autocrypt: addr=alice@testsuite.autocrypt.org; _monkey=ignore; keydata=
|
||||||
|
mQENBFhVF+ABCADu17FBUgA3mCemeKbNaBTyWe3VGxjbu7fUyHgdLK7i3tnd7IRtxQy/AEN2t6Vq
|
||||||
|
0/xeZEAKYRInsHI/HjvmhqPeWFzipk71jRQ02WUY1pZytFjYNIrTdMk4eLYdC1N0go83PU33V4R8
|
||||||
|
fc2fWHD8N5JPsDH2xOB6WNWkMPxgMbtGIa0QTx7TINhDif4/1/VcrX3wz1gZ6xYI+sujbC54iBZo
|
||||||
|
qbEfu4SFVvp53d+a1plxBzuZ/X6nqJqcysiS7ORMieBvU6W/mVeiAxwN4qcAI5s+rGmRnP8ltONK
|
||||||
|
/P1ScH6lmELgqm8Z/M0wdiYgywme/bdEQOg3s0S/8nCIFmwUchN7ABEBAAG0HWFsaWNlQHRlc3Rz
|
||||||
|
dWl0ZS5hdXRvY3J5cHQub3JniQFOBBMBCAA4FiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+AC
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQuvxTPNmTvX/k4wf+JJZ0M0rZeAXbnxdR6HDU
|
||||||
|
ZYL734Z8x/HRpz3vzK4VQQJ4oIbUQPwydZmAlTlglQY48IWWOdJnYvn2pIhlTM/T8q9ZfmOyp6i1
|
||||||
|
jxFCPT+2ma4DjNOqYFhfnULE/MYc6xeVaBcwGj7yvAW7YY7156/wDo6+9TCd/a9mzOFCGS0yQoRa
|
||||||
|
K3uDajA+G/SmbC8t/3X8+5sapvi9Ru0HNkIzaj1jhH+kW6628E7nkf9aN9LodXHfs1UtfuLqM8VG
|
||||||
|
Ysk9474x9QxbsrJ4YvXeFwM9zAs+Pvj4lnpH/0WOU8jJc3uarluGH58kTHM5/5+p0TeMpOHX7OEw
|
||||||
|
JndsBOV9gFc6FMx4hLkBDQRYVRfiAQgA3ad+Aat4UY8xvQQutLYb8e417XZN1zVmKypyReB0l0Zf
|
||||||
|
HA6Qc7uxnJQ7dzIEZAxdnjvTYJaCFrOCBXAyPHpShVMpKqQP+kBBY/WiC3BSUALR3xqp7k5/sjLD
|
||||||
|
+K4dAacXEc7nyXP5o5+oqBXEH8Ls5X440c9A3EdsvVlncvSW5ILLItlFHmQd6f1ynnjK+FQwYJRJ
|
||||||
|
ypDuqJpYkA1vn7+XxeQShpX105rM3C8tJUxRAP3QFimenn4Zm2BDhQpCneuBt239rkXOAXsR0PnJ
|
||||||
|
fV8eNAEsE8IIqnPoSlBme5DZAri69+joYmTeSKGuj4aoxzDlx1AQigwpMISLciTXLnJypwARAQAB
|
||||||
|
iQE2BBgBCAAgFiEEfi47NkGai9tG9hBruvxTPNmTvX8FAlhVF+ICGwwACgkQuvxTPNmTvX8dOwf9
|
||||||
|
H72BGoYJkuuFrbQ6F/mH7gG9z3ytQHRD2Z0ja+3O7YnJBpotHFFjF7yHGj0FtmQR0Q7KnhkJ/3mv
|
||||||
|
fkvuaH3Gcjli/E7VASastuFDFkGANLmGZVGQQ2iTYFG1aejjtGb01vcaPrgE9WDueMB+Pn6/QbDc
|
||||||
|
5SWCrVWrRFZKrwbAGw35GySoFYpxXyCNsk6q6Db56plllPZjrYj7axF0yN536D1ntEVFDOdKZq8x
|
||||||
|
Tb9P/4Tq9NKRLE4+aO6qCqEOz+V1OeOvYLw58BfnzXY8rXF93D/86YLyilv6p5WGaS/cRhIzr+Xq
|
||||||
|
+qBLD/vW+dh72e8MvcduX3tXV3Vkg0mkGekdOw==
|
||||||
|
Date: Sat, 17 Dec 2016 10:34:30 +0100
|
||||||
|
Message-ID: <rsa2048-unknown-non-critical@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This message contains an INBOME header with RSA 2048, but with an
|
||||||
|
unknown non-critical attribute. Agents that are compatible with
|
||||||
|
INBOME level 0 should accept this header while ignoring the unknown
|
||||||
|
attribute.
|
||||||
|
|
36
k9mail/src/test/resources/autocrypt/unknown-type.eml
Normal file
36
k9mail/src/test/resources/autocrypt/unknown-type.eml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
From: Alice <alice@testsuite.autocrypt.org>
|
||||||
|
To: Bob <bob@testsuite.autocrypt.org>
|
||||||
|
Subject: INBOME with invalid type attribute
|
||||||
|
Autocrypt: addr=alice@testsuite.autocrypt.org; type=x; keydata=
|
||||||
|
mQENBFhVGA8BCADK+qTRkAfax0LtJ6RiyxzuAFyIohBTwvtcOM2sd/tRmWq1eyNif5AGDnc1+b6X
|
||||||
|
zJ6l3BXiYM/8qXU/F04UA5BP05SgIqXjqT5I13blrydjKtUbZFchK7lJU7cyDbar+TH70DZURSQm
|
||||||
|
MusCj0+fdx6hx8y4LSOM68rjwVeq7JXAPU78QQsYgMrbtkf5mZWUquDdb7tEoxU+PcNifvtvuHF2
|
||||||
|
ILv09a4Fi8thJG4i/3LxMFtmMLIiZWLfk5KpXAKrOy436e1LCm3vesALcihPNppb803dgBqpvvEE
|
||||||
|
9W7sg5NUy3P8+fTEuvI8HYYd+lEvYe2ojm4HVTts4YFHmzaGVzHLABEBAAG0HVRoaXMgc2hvdWxk
|
||||||
|
IG5ldmVyIGJlIGltcG9ydGVkiQFOBBMBCAA4FiEE0uuMX0KSMgVBfC/25MZusLe5gWMFAlhVGA8C
|
||||||
|
GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQ5MZusLe5gWN9Hwf+PpLCCV7TiGc1nqIxLMTs
|
||||||
|
O84PVLSQZB642/QhLoMYXQ5iqty5H2FqGuK+uWLCnM+yIMDkcJC3ayWfa06fs3JOipVKlMh8hHnU
|
||||||
|
6/FHJB+3eZrc4lhh5B67Vi8Xg43pTP+I9ct/PlbHvD9kYw+DpcmCz0XILhaUP0R1oQ6M5KI49uLg
|
||||||
|
LAdNczcEtcw3A/hZ5ZTUe3o3gav0XDBXFCgGjkI+CaMjKb/HjgNM9YsrGxUxH1RFMYqTfrmCklHD
|
||||||
|
EboQc1Qtzi5rIwzVR3zSryve9KHH75TCfDApghwUBKSLNh374hjTFj5v5kPAxG3njX6EOqHS/UVX
|
||||||
|
Mn5aEVn0n6S1y+DJZLkBDQRYVRgRAQgAzQgD/CluB1wuBeI8qaqmIxG8epHCPstQ4kee6FuFWi3F
|
||||||
|
Lqtyk1R9tB4UL40gpEkpzB+qYms/zs9SeicuNcXoXA4bMcNGDFz3mZ1d9qG2izgC19e9p50oXiMY
|
||||||
|
cr8GM1Qcb77dmxlk829cBpr+X7NDKJy9VMGsqNYukgFDnNIzty0oMdCLSzpqi3UtXtCGYDqIiltU
|
||||||
|
aT8XdMAvddr6Scgpkz3wrqi/bVagc+q4IdKL0r8iL7o3EnTf/5Dc2XUaCFJLCa3Rk6oat5kTWjan
|
||||||
|
sp/K5k/VzSDcESji8n6xl0OzD2okhmX8iJZg1hhyI8hNmtW3boe51Hkkdlj+wC8Y2Fgh4QARAQAB
|
||||||
|
iQE2BBgBCAAgFiEE0uuMX0KSMgVBfC/25MZusLe5gWMFAlhVGBECGwwACgkQ5MZusLe5gWOn/Qf/
|
||||||
|
aeV7CqZW/YN4/LhXjJG7i+iDJYv/9Lr12dvgjO/sOlmDPHkEzXPMLKalm0biMPN7E1woQzcKt7Qy
|
||||||
|
eF/CRcVKK1TM6wdClOj2jErnWyx85/uZfnG9QRD41rhInk891A8LGebPZ6DJeJR/uwzMniEgNnKN
|
||||||
|
AMuGy95ckwlM3AfwzsKPTUUFnBAmSwWfMLRxjZPNefeo1Ic8mMRAT3d5sfDUx/4wm8tyiNLuOSkm
|
||||||
|
Ej6ONYpESD2sJGMo3ZY96pkzir7ZH++4mH6PwZg1ZT2nO+0PtaB9DHRGfBrzH85d4aLFZD9txx3p
|
||||||
|
ewabrNpYI/cJu9hUTaTM7wZaG5kmfStwihKYUg==
|
||||||
|
Date: Sat, 17 Dec 2016 10:51:48 +0100
|
||||||
|
Message-ID: <unknown-type@testsuite.autocrypt.org>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
This message contains an INBOME header that claims to be of type "x",
|
||||||
|
which is not a specified type.
|
||||||
|
|
||||||
|
An agent capable of INBOME level 0 should reject this inbome header
|
||||||
|
because of this type. (it should not try to parse it as a header).
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.openintents.openpgp;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class AutocryptPeerUpdate implements Parcelable {
|
||||||
|
/**
|
||||||
|
* Since there might be a case where new versions of the client using the library getting
|
||||||
|
* old versions of the protocol (and thus old versions of this class), we need a versioning
|
||||||
|
* system for the parcels sent between the clients and the providers.
|
||||||
|
*/
|
||||||
|
private static final int PARCELABLE_VERSION = 1;
|
||||||
|
|
||||||
|
|
||||||
|
private final byte[] keyData;
|
||||||
|
private final Date effectiveDate;
|
||||||
|
private final PreferEncrypt preferEncrypt;
|
||||||
|
|
||||||
|
|
||||||
|
private AutocryptPeerUpdate(byte[] keyData, Date effectiveDate, PreferEncrypt preferEncrypt) {
|
||||||
|
this.keyData = keyData;
|
||||||
|
this.effectiveDate = effectiveDate;
|
||||||
|
this.preferEncrypt = preferEncrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AutocryptPeerUpdate(Parcel source, int version) {
|
||||||
|
this.keyData = source.createByteArray();
|
||||||
|
this.effectiveDate = source.readInt() != 0 ? new Date(source.readLong()) : null;
|
||||||
|
this.preferEncrypt = PreferEncrypt.values()[source.readInt()];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static AutocryptPeerUpdate create(byte[] keyData, Date timestamp, boolean isMutual) {
|
||||||
|
return new AutocryptPeerUpdate(keyData, timestamp, isMutual ? PreferEncrypt.MUTUAL : PreferEncrypt.NOPREFERENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getKeyData() {
|
||||||
|
return keyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasKeyData() {
|
||||||
|
return keyData != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getEffectiveDate() {
|
||||||
|
return effectiveDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreferEncrypt getPreferEncrypt() {
|
||||||
|
return preferEncrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
/**
|
||||||
|
* NOTE: When adding fields in the process of updating this API, make sure to bump
|
||||||
|
* {@link #PARCELABLE_VERSION}.
|
||||||
|
*/
|
||||||
|
dest.writeInt(PARCELABLE_VERSION);
|
||||||
|
// Inject a placeholder that will store the parcel size from this point on
|
||||||
|
// (not including the size itself).
|
||||||
|
int sizePosition = dest.dataPosition();
|
||||||
|
dest.writeInt(0);
|
||||||
|
int startPosition = dest.dataPosition();
|
||||||
|
|
||||||
|
// version 1
|
||||||
|
dest.writeByteArray(keyData);
|
||||||
|
if (effectiveDate != null) {
|
||||||
|
dest.writeInt(1);
|
||||||
|
dest.writeLong(effectiveDate.getTime());
|
||||||
|
} else {
|
||||||
|
dest.writeInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.writeInt(preferEncrypt.ordinal());
|
||||||
|
|
||||||
|
// Go back and write the size
|
||||||
|
int parcelableSize = dest.dataPosition() - startPosition;
|
||||||
|
dest.setDataPosition(sizePosition);
|
||||||
|
dest.writeInt(parcelableSize);
|
||||||
|
dest.setDataPosition(startPosition + parcelableSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<AutocryptPeerUpdate> CREATOR = new Creator<AutocryptPeerUpdate>() {
|
||||||
|
public AutocryptPeerUpdate createFromParcel(final Parcel source) {
|
||||||
|
int version = source.readInt(); // parcelableVersion
|
||||||
|
int parcelableSize = source.readInt();
|
||||||
|
int startPosition = source.dataPosition();
|
||||||
|
|
||||||
|
AutocryptPeerUpdate vr = new AutocryptPeerUpdate(source, version);
|
||||||
|
|
||||||
|
// skip over all fields added in future versions of this parcel
|
||||||
|
source.setDataPosition(startPosition + parcelableSize);
|
||||||
|
|
||||||
|
return vr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutocryptPeerUpdate[] newArray(final int size) {
|
||||||
|
return new AutocryptPeerUpdate[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum PreferEncrypt {
|
||||||
|
NOPREFERENCE, MUTUAL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,6 @@ import org.openintents.openpgp.util.ParcelFileDescriptorUtil.DataSinkTransferThr
|
||||||
import org.openintents.openpgp.util.ParcelFileDescriptorUtil.DataSourceTransferThread;
|
import org.openintents.openpgp.util.ParcelFileDescriptorUtil.DataSourceTransferThread;
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class OpenPgpApi {
|
public class OpenPgpApi {
|
||||||
|
|
||||||
public static final String TAG = "OpenPgp API";
|
public static final String TAG = "OpenPgp API";
|
||||||
|
@ -48,7 +47,7 @@ public class OpenPgpApi {
|
||||||
/**
|
/**
|
||||||
* see CHANGELOG.md
|
* see CHANGELOG.md
|
||||||
*/
|
*/
|
||||||
public static final int API_VERSION = 10;
|
public static final int API_VERSION = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General extras
|
* General extras
|
||||||
|
@ -63,16 +62,16 @@ public class OpenPgpApi {
|
||||||
* PendingIntent RESULT_INTENT (if RESULT_CODE == RESULT_CODE_USER_INTERACTION_REQUIRED)
|
* PendingIntent RESULT_INTENT (if RESULT_CODE == RESULT_CODE_USER_INTERACTION_REQUIRED)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This action performs no operation, but can be used to check if the App has permission
|
||||||
|
* to access the API in general, returning a user interaction PendingIntent otherwise.
|
||||||
|
* This can be used to trigger the permission dialog explicitly.
|
||||||
|
*
|
||||||
|
* This action uses no extras.
|
||||||
|
*/
|
||||||
public static final String ACTION_CHECK_PERMISSION = "org.openintents.openpgp.action.CHECK_PERMISSION";
|
public static final String ACTION_CHECK_PERMISSION = "org.openintents.openpgp.action.CHECK_PERMISSION";
|
||||||
|
|
||||||
/**
|
@Deprecated
|
||||||
* DEPRECATED
|
|
||||||
* Same as ACTION_CLEARTEXT_SIGN
|
|
||||||
* <p/>
|
|
||||||
* optional extras:
|
|
||||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (DEPRECATED: this makes no sense here)
|
|
||||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
|
||||||
*/
|
|
||||||
public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN";
|
public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,10 +80,10 @@ public class OpenPgpApi {
|
||||||
* cleartext signatures per RFC 4880 before the text is actually signed:
|
* cleartext signatures per RFC 4880 before the text is actually signed:
|
||||||
* - end cleartext with newline
|
* - end cleartext with newline
|
||||||
* - remove whitespaces on line endings
|
* - remove whitespaces on line endings
|
||||||
* <p/>
|
*
|
||||||
* required extras:
|
* required extras:
|
||||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||||
*/
|
*/
|
||||||
|
@ -94,49 +93,50 @@ public class OpenPgpApi {
|
||||||
* Sign text or binary data resulting in a detached signature.
|
* Sign text or binary data resulting in a detached signature.
|
||||||
* No OutputStream necessary for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)!
|
* No OutputStream necessary for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)!
|
||||||
* The detached signature is returned separately in RESULT_DETACHED_SIGNATURE.
|
* The detached signature is returned separately in RESULT_DETACHED_SIGNATURE.
|
||||||
* <p/>
|
*
|
||||||
* required extras:
|
* required extras:
|
||||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature)
|
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature)
|
||||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||||
* <p/>
|
*
|
||||||
* returned extras:
|
* returned extras:
|
||||||
* byte[] RESULT_DETACHED_SIGNATURE
|
* byte[] RESULT_DETACHED_SIGNATURE
|
||||||
|
* String RESULT_SIGNATURE_MICALG (contains the name of the used signature algorithm as a string)
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_DETACHED_SIGN = "org.openintents.openpgp.action.DETACHED_SIGN";
|
public static final String ACTION_DETACHED_SIGN = "org.openintents.openpgp.action.DETACHED_SIGN";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt
|
* Encrypt
|
||||||
* <p/>
|
*
|
||||||
* required extras:
|
* required extras:
|
||||||
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
|
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
|
||||||
* or
|
* or
|
||||||
* long[] EXTRA_KEY_IDS
|
* long[] EXTRA_KEY_IDS
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
||||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||||
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
||||||
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default is true)
|
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default ist true)
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
|
public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign and encrypt
|
* Sign and encrypt
|
||||||
* <p/>
|
*
|
||||||
* required extras:
|
* required extras:
|
||||||
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
|
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
|
||||||
* or
|
* or
|
||||||
* long[] EXTRA_KEY_IDS
|
* long[] EXTRA_KEY_IDS
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
||||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||||
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
||||||
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default is true)
|
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default ist true)
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT";
|
public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT";
|
||||||
|
|
||||||
|
@ -144,15 +144,15 @@ public class OpenPgpApi {
|
||||||
* Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted,
|
* Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted,
|
||||||
* and also signed-only input.
|
* and also signed-only input.
|
||||||
* OutputStream is optional, e.g., for verifying detached signatures!
|
* OutputStream is optional, e.g., for verifying detached signatures!
|
||||||
* <p/>
|
*
|
||||||
* If OpenPgpSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_KEY_MISSING
|
* If OpenPgpSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_KEY_MISSING
|
||||||
* in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.
|
* in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.
|
||||||
* On all other status, in addition a PendingIntent is returned via RESULT_INTENT to open
|
* On all other status, in addition a PendingIntent is returned via RESULT_INTENT to open
|
||||||
* the key view in OpenKeychain.
|
* the key view in OpenKeychain.
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* byte[] EXTRA_DETACHED_SIGNATURE (detached signature)
|
* byte[] EXTRA_DETACHED_SIGNATURE (detached signature)
|
||||||
* <p/>
|
*
|
||||||
* returned extras:
|
* returned extras:
|
||||||
* OpenPgpSignatureResult RESULT_SIGNATURE
|
* OpenPgpSignatureResult RESULT_SIGNATURE
|
||||||
* OpenPgpDecryptionResult RESULT_DECRYPTION
|
* OpenPgpDecryptionResult RESULT_DECRYPTION
|
||||||
|
@ -163,9 +163,9 @@ public class OpenPgpApi {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts the header of an encrypted file to retrieve metadata such as original filename.
|
* Decrypts the header of an encrypted file to retrieve metadata such as original filename.
|
||||||
* <p/>
|
*
|
||||||
* This does not decrypt the actual content of the file.
|
* This does not decrypt the actual content of the file.
|
||||||
* <p/>
|
*
|
||||||
* returned extras:
|
* returned extras:
|
||||||
* OpenPgpDecryptMetadata RESULT_METADATA
|
* OpenPgpDecryptMetadata RESULT_METADATA
|
||||||
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
|
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
|
||||||
|
@ -174,10 +174,10 @@ public class OpenPgpApi {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select key id for signing
|
* Select key id for signing
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* String EXTRA_USER_ID
|
* String EXTRA_USER_ID
|
||||||
* <p/>
|
*
|
||||||
* returned extras:
|
* returned extras:
|
||||||
* long EXTRA_SIGN_KEY_ID
|
* long EXTRA_SIGN_KEY_ID
|
||||||
*/
|
*/
|
||||||
|
@ -185,10 +185,10 @@ public class OpenPgpApi {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get key ids based on given user ids (=emails)
|
* Get key ids based on given user ids (=emails)
|
||||||
* <p/>
|
*
|
||||||
* required extras:
|
* required extras:
|
||||||
* String[] EXTRA_USER_IDS
|
* String[] EXTRA_USER_IDS
|
||||||
* <p/>
|
*
|
||||||
* returned extras:
|
* returned extras:
|
||||||
* long[] RESULT_KEY_IDS
|
* long[] RESULT_KEY_IDS
|
||||||
*/
|
*/
|
||||||
|
@ -197,26 +197,43 @@ public class OpenPgpApi {
|
||||||
/**
|
/**
|
||||||
* This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key
|
* This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key
|
||||||
* corresponding to the given key id in its database.
|
* corresponding to the given key id in its database.
|
||||||
* <p/>
|
*
|
||||||
* It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key.
|
* It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key.
|
||||||
* The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver.
|
* The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver.
|
||||||
* <p/>
|
*
|
||||||
* If an Output stream has been defined the whole public key is returned.
|
* If an Output stream has been defined the whole public key is returned.
|
||||||
* required extras:
|
* required extras:
|
||||||
* long EXTRA_KEY_ID
|
* long EXTRA_KEY_ID
|
||||||
* <p/>
|
*
|
||||||
* optional extras:
|
* optional extras:
|
||||||
* String EXTRA_REQUEST_ASCII_ARMOR (request that the returned key is encoded in ASCII Armor)
|
* String EXTRA_REQUEST_ASCII_ARMOR (request that the returned key is encoded in ASCII Armor)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_GET_KEY = "org.openintents.openpgp.action.GET_KEY";
|
public static final String ACTION_GET_KEY = "org.openintents.openpgp.action.GET_KEY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backup all keys given by EXTRA_KEY_IDS and if requested their secret parts.
|
||||||
|
* The encrypted backup will be written to the OutputStream.
|
||||||
|
* The client app has no access to the backup code used to encrypt the backup!
|
||||||
|
* This operation always requires user interaction with RESULT_CODE_USER_INTERACTION_REQUIRED!
|
||||||
|
*
|
||||||
|
* required extras:
|
||||||
|
* long[] EXTRA_KEY_IDS (keys that should be included in the backup)
|
||||||
|
* boolean EXTRA_BACKUP_SECRET (also backup secret keys)
|
||||||
|
*/
|
||||||
|
public static final String ACTION_BACKUP = "org.openintents.openpgp.action.BACKUP";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the status of some Autocrypt peer, identified by their peer id.
|
||||||
|
*
|
||||||
|
* required extras:
|
||||||
|
* String EXTRA_AUTOCRYPT_PEER_ID (autocrypt peer id to update)
|
||||||
|
* AutocryptPeerUpdate EXTRA_AUTOCRYPT_PEER_UPDATE (actual peer update)
|
||||||
|
*/
|
||||||
|
public static final String ACTION_UPDATE_AUTOCRYPT_PEER = "org.openintents.openpgp.action.UPDATE_AUTOCRYPT_PEER";
|
||||||
|
|
||||||
/* Intent extras */
|
/* Intent extras */
|
||||||
public static final String EXTRA_API_VERSION = "api_version";
|
public static final String EXTRA_API_VERSION = "api_version";
|
||||||
|
|
||||||
// DEPRECATED!!!
|
|
||||||
public static final String EXTRA_ACCOUNT_NAME = "account_name";
|
|
||||||
|
|
||||||
// ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY
|
// ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY
|
||||||
// request ASCII Armor for output
|
// request ASCII Armor for output
|
||||||
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
|
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
|
||||||
|
@ -226,23 +243,37 @@ public class OpenPgpApi {
|
||||||
public static final String RESULT_DETACHED_SIGNATURE = "detached_signature";
|
public static final String RESULT_DETACHED_SIGNATURE = "detached_signature";
|
||||||
public static final String RESULT_SIGNATURE_MICALG = "signature_micalg";
|
public static final String RESULT_SIGNATURE_MICALG = "signature_micalg";
|
||||||
|
|
||||||
// ENCRYPT, SIGN_AND_ENCRYPT
|
// ENCRYPT, SIGN_AND_ENCRYPT, QUERY_AUTOCRYPT_STATUS
|
||||||
public static final String EXTRA_USER_IDS = "user_ids";
|
public static final String EXTRA_USER_IDS = "user_ids";
|
||||||
public static final String EXTRA_KEY_IDS = "key_ids";
|
public static final String EXTRA_KEY_IDS = "key_ids";
|
||||||
|
public static final String EXTRA_KEY_IDS_SELECTED = "key_ids_selected";
|
||||||
public static final String EXTRA_SIGN_KEY_ID = "sign_key_id";
|
public static final String EXTRA_SIGN_KEY_ID = "sign_key_id";
|
||||||
|
|
||||||
|
public static final String RESULT_KEYS_CONFIRMED = "keys_confirmed";
|
||||||
|
public static final String RESULT_AUTOCRYPT_STATUS = "autocrypt_status";
|
||||||
|
public static final int AUTOCRYPT_STATUS_UNAVAILABLE = 0;
|
||||||
|
public static final int AUTOCRYPT_STATUS_DISCOURAGE = 1;
|
||||||
|
public static final int AUTOCRYPT_STATUS_AVAILABLE = 2;
|
||||||
|
public static final int AUTOCRYPT_STATUS_MUTUAL = 3;
|
||||||
|
|
||||||
// optional extras:
|
// optional extras:
|
||||||
public static final String EXTRA_PASSPHRASE = "passphrase";
|
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||||
public static final String EXTRA_ORIGINAL_FILENAME = "original_filename";
|
public static final String EXTRA_ORIGINAL_FILENAME = "original_filename";
|
||||||
public static final String EXTRA_ENABLE_COMPRESSION = "enable_compression";
|
public static final String EXTRA_ENABLE_COMPRESSION = "enable_compression";
|
||||||
public static final String EXTRA_ENCRYPT_OPPORTUNISTIC = "opportunistic";
|
public static final String EXTRA_OPPORTUNISTIC_ENCRYPTION = "opportunistic";
|
||||||
|
|
||||||
// GET_SIGN_KEY_ID
|
// GET_SIGN_KEY_ID
|
||||||
public static final String EXTRA_USER_ID = "user_id";
|
public static final String EXTRA_USER_ID = "user_id";
|
||||||
|
|
||||||
// GET_KEY
|
// GET_KEY
|
||||||
public static final String EXTRA_KEY_ID = "key_id";
|
public static final String EXTRA_KEY_ID = "key_id";
|
||||||
|
public static final String EXTRA_MINIMIZE = "minimize";
|
||||||
|
public static final String EXTRA_MINIMIZE_USER_ID = "minimize_user_id";
|
||||||
public static final String RESULT_KEY_IDS = "key_ids";
|
public static final String RESULT_KEY_IDS = "key_ids";
|
||||||
|
|
||||||
|
// BACKUP
|
||||||
|
public static final String EXTRA_BACKUP_SECRET = "backup_secret";
|
||||||
|
|
||||||
/* Service Intent returns */
|
/* Service Intent returns */
|
||||||
public static final String RESULT_CODE = "result_code";
|
public static final String RESULT_CODE = "result_code";
|
||||||
|
|
||||||
|
@ -258,10 +289,10 @@ public class OpenPgpApi {
|
||||||
public static final String RESULT_INTENT = "intent";
|
public static final String RESULT_INTENT = "intent";
|
||||||
|
|
||||||
// DECRYPT_VERIFY
|
// DECRYPT_VERIFY
|
||||||
public static final String EXTRA_DECRYPTION_RESULT = "decryption_result";
|
|
||||||
public static final String EXTRA_DETACHED_SIGNATURE = "detached_signature";
|
public static final String EXTRA_DETACHED_SIGNATURE = "detached_signature";
|
||||||
public static final String EXTRA_PROGRESS_MESSENGER = "progress_messenger";
|
public static final String EXTRA_PROGRESS_MESSENGER = "progress_messenger";
|
||||||
public static final String EXTRA_DATA_LENGTH = "data_length";
|
public static final String EXTRA_DATA_LENGTH = "data_length";
|
||||||
|
public static final String EXTRA_DECRYPTION_RESULT = "decryption_result";
|
||||||
public static final String EXTRA_SENDER_ADDRESS = "sender_address";
|
public static final String EXTRA_SENDER_ADDRESS = "sender_address";
|
||||||
public static final String EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING = "support_override_crpto_warning";
|
public static final String EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING = "support_override_crpto_warning";
|
||||||
public static final String RESULT_SIGNATURE = "signature";
|
public static final String RESULT_SIGNATURE = "signature";
|
||||||
|
@ -272,7 +303,11 @@ public class OpenPgpApi {
|
||||||
// This will be the charset which was specified in the headers of ascii armored input, if any
|
// This will be the charset which was specified in the headers of ascii armored input, if any
|
||||||
public static final String RESULT_CHARSET = "charset";
|
public static final String RESULT_CHARSET = "charset";
|
||||||
|
|
||||||
// INTERNAL, should not be used
|
// UPDATE_AUTOCRYPT_PEER
|
||||||
|
public static final String EXTRA_AUTOCRYPT_PEER_ID = "autocrypt_peer_id";
|
||||||
|
public static final String EXTRA_AUTOCRYPT_PEER_UPDATE = "autocrypt_peer_update";
|
||||||
|
|
||||||
|
// INTERNAL, must not be used
|
||||||
public static final String EXTRA_CALL_UUID1 = "call_uuid1";
|
public static final String EXTRA_CALL_UUID1 = "call_uuid1";
|
||||||
public static final String EXTRA_CALL_UUID2 = "call_uuid2";
|
public static final String EXTRA_CALL_UUID2 = "call_uuid2";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue