diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-10-15 22:50:34 +0200 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-10-15 22:50:34 +0200 |
commit | cac7c3234a6ee1d25f46a9179645e01c1c0512c2 (patch) | |
tree | f6e8cdb715249084322740605e5758c312502f00 /OpenKeychain/src/main/java | |
parent | c03dee6fe2f60717f448178dcf49d370dce0bab0 (diff) | |
download | open-keychain-cac7c3234a6ee1d25f46a9179645e01c1c0512c2.tar.gz open-keychain-cac7c3234a6ee1d25f46a9179645e01c1c0512c2.tar.bz2 open-keychain-cac7c3234a6ee1d25f46a9179645e01c1c0512c2.zip |
Support backupVersion ASCII Armor header
Diffstat (limited to 'OpenKeychain/src/main/java')
7 files changed, 94 insertions, 25 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 17db500ce..1398e2d29 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -82,7 +82,6 @@ public final class Constants { public static final class Path { public static final File APP_DIR = new File(Environment.getExternalStorageDirectory(), "OpenKeychain"); - public static final File APP_DIR_FILE = new File(APP_DIR, "export.asc"); } public static final class Notification { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java index 5886f000c..1ec43b625 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java @@ -142,6 +142,7 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> { PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel(); inputParcel.setSymmetricPassphrase(exportInput.mSymmetricPassphrase); inputParcel.setEnableAsciiArmorOutput(true); + inputParcel.setAddBackupHeader(true); InputStream inStream = mContext.getContentResolver().openInputStream(exportOutputUri); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 24d1215d4..382d6c46d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -639,6 +639,7 @@ public abstract class OperationResult implements Parcelable { MSG_DC_ASKIP_NOT_ALLOWED (LogLevel.DEBUG, R.string.msg_dc_askip_not_allowed), MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym), MSG_DC_CHARSET (LogLevel.DEBUG, R.string.msg_dc_charset), + MSG_DC_BACKUP_VERSION (LogLevel.DEBUG, R.string.msg_dc_backup_version), MSG_DC_CLEAR_DATA (LogLevel.DEBUG, R.string.msg_dc_clear_data), MSG_DC_CLEAR_DECOMPRESS (LogLevel.DEBUG, R.string.msg_dc_clear_decompress), MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java index 4a08ab9c1..7fe89b6f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java @@ -31,6 +31,7 @@ import java.util.Iterator; import android.content.Context; import android.support.annotation.NonNull; +import android.text.TextUtils; import android.webkit.MimeTypeMap; import org.openintents.openpgp.OpenPgpDecryptionResult; @@ -201,6 +202,57 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } + private static class ArmorHeaders { + String charset = null; + Integer backupVersion = null; + } + + private ArmorHeaders parseArmorHeaders(InputStream in, OperationLog log, int indent) { + ArmorHeaders armorHeaders = new ArmorHeaders(); + + // If the input stream is armored, and there is a charset specified, take a note for later + // https://tools.ietf.org/html/rfc4880#page56 + if (in instanceof ArmoredInputStream) { + ArmoredInputStream aIn = (ArmoredInputStream) in; + if (aIn.getArmorHeaders() != null) { + for (String header : aIn.getArmorHeaders()) { + String[] pieces = header.split(":", 2); + if (pieces.length != 2 + || TextUtils.isEmpty(pieces[0]) + || TextUtils.isEmpty(pieces[1])) { + continue; + } + + switch (pieces[0].toLowerCase()) { + case "charset": { + armorHeaders.charset = pieces[1].trim(); + break; + } + case "backupversion": { + try { + armorHeaders.backupVersion = Integer.valueOf(pieces[1].trim()); + } catch (NumberFormatException e) { + continue; + } + break; + } + default: { + // continue; + } + } + } + if (armorHeaders.charset != null) { + log.add(LogType.MSG_DC_CHARSET, indent, armorHeaders.charset); + } + if (armorHeaders.backupVersion != null) { + log.add(LogType.MSG_DC_BACKUP_VERSION, indent, armorHeaders.backupVersion); + } + } + } + + return armorHeaders; + } + /** Decrypt and/or verify binary or ascii armored pgp data. */ @NonNull private DecryptVerifyResult decryptVerify( @@ -215,23 +267,12 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp int currentProgress = 0; updateProgress(R.string.progress_reading_data, currentProgress, 100); - // If the input stream is armored, and there is a charset specified, take a note for later - // https://tools.ietf.org/html/rfc4880#page56 - String charset = null; - if (in instanceof ArmoredInputStream) { - ArmoredInputStream aIn = (ArmoredInputStream) in; - if (aIn.getArmorHeaders() != null) { - for (String header : aIn.getArmorHeaders()) { - String[] pieces = header.split(":", 2); - if (pieces.length == 2 && "charset".equalsIgnoreCase(pieces[0])) { - charset = pieces[1].trim(); - break; - } - } - if (charset != null) { - log.add(LogType.MSG_DC_CHARSET, indent, charset); - } - } + // parse ASCII Armor headers + ArmorHeaders armorHeaders = parseArmorHeaders(in, log, indent); + String charset = armorHeaders.charset; + boolean useBackupCode = false; + if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 1) { + useBackupCode = true; } OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder(); @@ -245,7 +286,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp if (obj instanceof PGPEncryptedDataList) { esResult = handleEncryptedPacket( - input, cryptoInput, (PGPEncryptedDataList) obj, log, indent, currentProgress); + input, cryptoInput, (PGPEncryptedDataList) obj, log, indent, + currentProgress, useBackupCode); // if there is an error, nothing left to do here if (esResult.errorResult != null) { @@ -477,7 +519,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput, - PGPEncryptedDataList enc, OperationLog log, int indent, int currentProgress) throws PGPException { + PGPEncryptedDataList enc, OperationLog log, int indent, int currentProgress, boolean useBackupCode) throws PGPException { EncryptStreamResult result = new EncryptStreamResult(); @@ -609,8 +651,11 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp if (passphrase == null) { log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); + RequiredInputParcel requiredInputParcel = useBackupCode ? + RequiredInputParcel.createRequiredBackupCode() : + RequiredInputParcel.createRequiredSymmetricPassphrase(); return result.with(new DecryptVerifyResult(log, - RequiredInputParcel.createRequiredSymmetricPassphrase(), + requiredInputParcel, cryptoInput)); } @@ -653,8 +698,10 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp result.cleartextStream = encryptedDataSymmetric.getDataStream(decryptorFactory); } catch (PGPDataValidationException e) { log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent + 1); - return result.with(new DecryptVerifyResult(log, - RequiredInputParcel.createRequiredSymmetricPassphrase(), cryptoInput)); + RequiredInputParcel requiredInputParcel = useBackupCode ? + RequiredInputParcel.createRequiredBackupCode() : + RequiredInputParcel.createRequiredSymmetricPassphrase(); + return result.with(new DecryptVerifyResult(log, requiredInputParcel, cryptoInput)); } result.encryptedData = encryptedDataSymmetric; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index 36d1a07cb..c2c6234eb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -44,6 +44,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { protected boolean mDetachedSignature = false; protected boolean mHiddenRecipients = false; protected boolean mIntegrityProtected = true; + protected boolean mAddBackupHeader = false; public PgpSignEncryptInputParcel() { @@ -70,6 +71,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { mDetachedSignature = source.readInt() == 1; mHiddenRecipients = source.readInt() == 1; mIntegrityProtected = source.readInt() == 1; + mAddBackupHeader = source.readInt() == 1; } @Override @@ -100,6 +102,7 @@ public class PgpSignEncryptInputParcel implements Parcelable { dest.writeInt(mDetachedSignature ? 1 : 0); dest.writeInt(mHiddenRecipients ? 1 : 0); dest.writeInt(mIntegrityProtected ? 1 : 0); + dest.writeInt(mAddBackupHeader ? 1 : 0); } public String getCharset() { @@ -244,6 +247,15 @@ public class PgpSignEncryptInputParcel implements Parcelable { return this; } + public PgpSignEncryptInputParcel setAddBackupHeader(boolean addBackupHeader) { + this.mAddBackupHeader = addBackupHeader; + return this; + } + + public boolean isAddBackupHeader() { + return mAddBackupHeader; + } + public boolean isHiddenRecipients() { return mHiddenRecipients; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index ecc190d97..25445a6c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -149,6 +149,10 @@ public class PgpSignEncryptOperation extends BaseOperation { if (input.getCharset() != null) { armorOut.setHeader("Charset", input.getCharset()); } + // add proprietary header to indicate that this is a key backup + if (input.isAddBackupHeader()) { + armorOut.setHeader("BackupVersion", "1"); + } out = armorOut; } else { out = outputStream; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java index e4dac3227..2c430bc29 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java @@ -14,8 +14,8 @@ import java.util.Date; public class RequiredInputParcel implements Parcelable { public enum RequiredInputType { - PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT, - UPLOAD_FAIL_RETRY + PASSPHRASE, PASSPHRASE_SYMMETRIC, BACKUP_CODE, NFC_SIGN, NFC_DECRYPT, + NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT, UPLOAD_FAIL_RETRY } public Date mSignatureTime; @@ -117,6 +117,11 @@ public class RequiredInputParcel implements Parcelable { null, null, null, null, null); } + public static RequiredInputParcel createRequiredBackupCode() { + return new RequiredInputParcel(RequiredInputType.BACKUP_CODE, + null, null, null, null, null); + } + public static RequiredInputParcel createRequiredPassphrase( RequiredInputParcel req) { return new RequiredInputParcel(RequiredInputType.PASSPHRASE, |