diff options
Diffstat (limited to 'OpenKeychain/src/main')
43 files changed, 593 insertions, 673 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java index aaff0a07c..f3ceac681 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java @@ -151,7 +151,6 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(mContext, mProviderHelper, mProgressable); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes) - .setSignedLiteralData(true) .setRequiredSignerFingerprint(requiredFingerprint); DecryptVerifyResult decryptVerifyResult = op.execute(input, new CryptoInputParcel()); 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 fc72a9ac2..24d1215d4 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 @@ -514,7 +514,7 @@ public abstract class OperationResult implements Parcelable { MSG_CR_ERROR_NO_USER_ID (LogLevel.ERROR, R.string.msg_cr_error_no_user_id), MSG_CR_ERROR_NO_CERTIFY (LogLevel.ERROR, R.string.msg_cr_error_no_certify), MSG_CR_ERROR_NULL_EXPIRY(LogLevel.ERROR, R.string.msg_cr_error_null_expiry), - MSG_CR_ERROR_KEYSIZE_512 (LogLevel.ERROR, R.string.msg_cr_error_keysize_512), + MSG_CR_ERROR_KEYSIZE_2048(LogLevel.ERROR, R.string.msg_cr_error_keysize_2048), MSG_CR_ERROR_NO_KEYSIZE (LogLevel.ERROR, R.string.msg_cr_error_no_keysize), MSG_CR_ERROR_NO_CURVE (LogLevel.ERROR, R.string.msg_cr_error_no_curve), MSG_CR_ERROR_UNKNOWN_ALGO (LogLevel.ERROR, R.string.msg_cr_error_unknown_algo), @@ -661,6 +661,7 @@ public abstract class OperationResult implements Parcelable { MSG_DC_ERROR_INPUT (LogLevel.ERROR, R.string.msg_dc_error_input), MSG_DC_ERROR_NO_DATA (LogLevel.ERROR, R.string.msg_dc_error_no_data), MSG_DC_ERROR_NO_KEY (LogLevel.ERROR, R.string.msg_dc_error_no_key), + MSG_DC_ERROR_NO_SIGNATURE (LogLevel.ERROR, R.string.msg_dc_error_no_signature), MSG_DC_ERROR_PGP_EXCEPTION (LogLevel.ERROR, R.string.msg_dc_error_pgp_exception), MSG_DC_INTEGRITY_CHECK_OK (LogLevel.INFO, R.string.msg_dc_integrity_check_ok), MSG_DC_OK_META_ONLY (LogLevel.OK, R.string.msg_dc_ok_meta_only), @@ -687,6 +688,7 @@ public abstract class OperationResult implements Parcelable { MSG_VL_ERROR_MISSING_SIGLIST (LogLevel.ERROR, R.string.msg_vl_error_no_siglist), MSG_VL_ERROR_MISSING_LITERAL (LogLevel.ERROR, R.string.msg_vl_error_missing_literal), MSG_VL_ERROR_MISSING_KEY (LogLevel.ERROR, R.string.msg_vl_error_wrong_key), + MSG_VL_ERROR_NO_SIGNATURE (LogLevel.ERROR, R.string.msg_vl_error_no_signature), MSG_VL_CLEAR_SIGNATURE_CHECK (LogLevel.DEBUG, R.string.msg_vl_clear_signature_check), MSG_VL_ERROR_INTEGRITY_CHECK (LogLevel.ERROR, R.string.msg_vl_error_integrity_check), MSG_VL_OK (LogLevel.OK, R.string.msg_vl_ok), @@ -703,7 +705,6 @@ public abstract class OperationResult implements Parcelable { // pgpsignencrypt MSG_PSE_ASYMMETRIC (LogLevel.INFO, R.string.msg_pse_asymmetric), - MSG_PSE_CLEARSIGN_ONLY (LogLevel.DEBUG, R.string.msg_pse_clearsign_only), MSG_PSE_COMPRESSING (LogLevel.DEBUG, R.string.msg_pse_compressing), MSG_PSE_ENCRYPTING (LogLevel.DEBUG, R.string.msg_pse_encrypting), MSG_PSE_ERROR_BAD_PASSPHRASE (LogLevel.ERROR, R.string.msg_pse_error_bad_passphrase), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java index 18a27dd96..6f1e78ce6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -154,8 +154,13 @@ public abstract class CanonicalizedKeyRing extends KeyRing { return getRing().getEncoded(); } - public boolean containsSubkey(String expectedFingerprint) { + /// Returns true iff the keyring contains a primary key or mutually bound subkey with the expected fingerprint + public boolean containsBoundSubkey(String expectedFingerprint) { for (CanonicalizedPublicKey key : publicKeyIterator()) { + boolean isMasterOrMutuallyBound = key.isMasterKey() || key.canSign(); + if (!isMasterOrMutuallyBound) { + continue; + } if (KeyFormattingUtils.convertFingerprintToHex( key.getFingerprint()).equalsIgnoreCase(expectedFingerprint)) { return true; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java index 412468a48..476b4e59c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java @@ -44,13 +44,17 @@ import java.util.Iterator; public class CanonicalizedPublicKey extends UncachedPublicKey { // this is the parent key ring - final KeyRing mRing; + final CanonicalizedKeyRing mRing; - CanonicalizedPublicKey(KeyRing ring, PGPPublicKey key) { + CanonicalizedPublicKey(CanonicalizedKeyRing ring, PGPPublicKey key) { super(key); mRing = ring; } + public CanonicalizedKeyRing getKeyRing() { + return mRing; + } + public IterableIterator<String> getUserIds() { return new IterableIterator<String>(mPublicKey.getUserIDs()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java index 9d059b58f..2dd1e2dde 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java @@ -91,11 +91,12 @@ public class OpenPgpSignatureResultBuilder { return mInsecure; } - public void initValid(CanonicalizedPublicKeyRing signingRing, - CanonicalizedPublicKey signingKey) { + public void initValid(CanonicalizedPublicKey signingKey) { setSignatureAvailable(true); setKnownKey(true); + CanonicalizedKeyRing signingRing = signingKey.getKeyRing(); + // from RING setKeyId(signingRing.getMasterKeyId()); try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java index 3eef7759c..bc9b54cd6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java @@ -18,7 +18,7 @@ package org.sufficientlysecure.keychain.pgp; -import java.io.InputStream; + import java.util.HashSet; import android.net.Uri; @@ -36,7 +36,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable { private boolean mDecryptMetadataOnly; private byte[] mDetachedSignature; private String mRequiredSignerFingerprint; - private boolean mSignedLiteralData; public PgpDecryptVerifyInputParcel() { } @@ -61,7 +60,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable { mDecryptMetadataOnly = source.readInt() != 0; mDetachedSignature = source.createByteArray(); mRequiredSignerFingerprint = source.readString(); - mSignedLiteralData = source.readInt() != 0; } @Override @@ -80,7 +78,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable { dest.writeInt(mDecryptMetadataOnly ? 1 : 0); dest.writeByteArray(mDetachedSignature); dest.writeString(mRequiredSignerFingerprint); - dest.writeInt(mSignedLiteralData ? 1 : 0); } byte[] getInputBytes() { @@ -150,15 +147,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable { return this; } - boolean isSignedLiteralData() { - return mSignedLiteralData; - } - - public PgpDecryptVerifyInputParcel setSignedLiteralData(boolean signedLiteralData) { - mSignedLiteralData = signedLiteralData; - return this; - } - public static final Creator<PgpDecryptVerifyInputParcel> CREATOR = new Creator<PgpDecryptVerifyInputParcel>() { public PgpDecryptVerifyInputParcel createFromParcel(final Parcel source) { return new PgpDecryptVerifyInputParcel(source); 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 055f84b4d..2d28f70e0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java @@ -18,13 +18,23 @@ package org.sufficientlysecure.keychain.pgp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SignatureException; +import java.util.Date; +import java.util.Iterator; + import android.content.Context; import android.support.annotation.NonNull; import android.webkit.MimeTypeMap; import org.openintents.openpgp.OpenPgpDecryptionResult; import org.openintents.openpgp.OpenPgpMetadata; -import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.openpgp.PGPCompressedData; import org.spongycastle.openpgp.PGPDataValidationException; @@ -33,18 +43,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataList; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPKeyValidationException; import org.spongycastle.openpgp.PGPLiteralData; -import org.spongycastle.openpgp.PGPOnePassSignature; -import org.spongycastle.openpgp.PGPOnePassSignatureList; import org.spongycastle.openpgp.PGPPBEEncryptedData; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; -import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; import org.spongycastle.util.encoders.DecoderException; @@ -68,17 +74,6 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.ProgressScaler; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SignatureException; -import java.util.Date; -import java.util.Iterator; - public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInputParcel> { public PgpDecryptVerifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable) { @@ -153,9 +148,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp // it is ascii armored Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); - if (input.isSignedLiteralData()) { - return verifySignedLiteralData(input, aIn, outputStream, 0); - } else if (aIn.isClearText()) { + if (aIn.isClearText()) { // a cleartext signature, verify it with the other method return verifyCleartextSignature(aIn, outputStream, 0); } else { @@ -186,133 +179,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } } - /**Verify signed plaintext data (PGP/INLINE). */ - @NonNull - private DecryptVerifyResult verifySignedLiteralData( - PgpDecryptVerifyInputParcel input, InputStream in, OutputStream out, int indent) - throws IOException, PGPException { - OperationLog log = new OperationLog(); - log.add(LogType.MSG_VL, indent); - - // thinking that the proof-fetching operation is going to take most of the time - updateProgress(R.string.progress_reading_data, 75, 100); - - JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in); - Object o = pgpF.nextObject(); - if (o instanceof PGPCompressedData) { - log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent + 1); - - pgpF = new JcaPGPObjectFactory(((PGPCompressedData) o).getDataStream()); - o = pgpF.nextObject(); - updateProgress(R.string.progress_decompressing_data, 80, 100); - } - - // all we want to see is a OnePassSignatureList followed by LiteralData - if (!(o instanceof PGPOnePassSignatureList)) { - log.add(LogType.MSG_VL_ERROR_MISSING_SIGLIST, indent); - return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); - } - PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) o; - - // go through all signatures (should be just one), make sure we have - // the key and it matches the one we’re looking for - CanonicalizedPublicKeyRing signingRing = null; - CanonicalizedPublicKey signingKey = null; - int signatureIndex = -1; - for (int i = 0; i < sigList.size(); ++i) { - try { - long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) - ); - signingKey = signingRing.getPublicKey(sigKeyId); - signatureIndex = i; - } catch (ProviderHelper.NotFoundException e) { - Log.d(Constants.TAG, "key not found, trying next signature..."); - } - } - - // there has to be a key, and it has to be the right one - if (signingKey == null) { - log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent); - Log.d(Constants.TAG, "Failed to find key in signed-literal message"); - return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); - } - - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingRing.getFingerprint()); - if (!(input.getRequiredSignerFingerprint().equals(fingerprint))) { - log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent); - Log.d(Constants.TAG, "Fingerprint mismatch; wanted " + input.getRequiredSignerFingerprint() + - " got " + fingerprint + "!"); - return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); - } - - OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - - PGPOnePassSignature signature = sigList.get(signatureIndex); - signatureResultBuilder.initValid(signingRing, signingKey); - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); - - o = pgpF.nextObject(); - - if (!(o instanceof PGPLiteralData)) { - log.add(LogType.MSG_VL_ERROR_MISSING_LITERAL, indent); - return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); - } - - PGPLiteralData literalData = (PGPLiteralData) o; - - log.add(LogType.MSG_DC_CLEAR_DATA, indent + 1); - updateProgress(R.string.progress_decrypting, 85, 100); - - InputStream dataIn = literalData.getInputStream(); - - int length; - byte[] buffer = new byte[1 << 16]; - while ((length = dataIn.read(buffer)) > 0) { - out.write(buffer, 0, length); - signature.update(buffer, 0, length); - } - - updateProgress(R.string.progress_verifying_signature, 95, 100); - log.add(LogType.MSG_VL_CLEAR_SIGNATURE_CHECK, indent + 1); - - PGPSignatureList signatureList = (PGPSignatureList) pgpF.nextObject(); - PGPSignature messageSignature = signatureList.get(signatureIndex); - - // Verify signature and check binding signatures - boolean validSignature = signature.verify(messageSignature); - if (validSignature) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); - } else { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); - } - signatureResultBuilder.setValidSignature(validSignature); - - OpenPgpSignatureResult signatureResult = signatureResultBuilder.build(); - - if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_CONFIRMED - && signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_UNCONFIRMED) { - log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent); - return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); - } - - updateProgress(R.string.progress_done, 100, 100); - - log.add(LogType.MSG_VL_OK, indent); - - // Return a positive result, with metadata and verification info - DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); - result.setSignatureResult(signatureResult); - result.setDecryptionResult( - new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED)); - return result; - } - private static class EncryptStreamResult { // this is non-null iff an error occured, return directly @@ -368,7 +234,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } } - OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder(); JcaPGPObjectFactory plainFact; @@ -415,10 +280,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp log.add(LogType.MSG_DC_PREP_STREAMS, indent); - int signatureIndex = -1; - CanonicalizedPublicKeyRing signingRing = null; - CanonicalizedPublicKey signingKey = null; - log.add(LogType.MSG_DC_CLEAR, indent); indent += 1; @@ -435,58 +296,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp plainFact = fact; } - // resolve leading signature data - PGPOnePassSignature signature = null; - if (dataChunk instanceof PGPOnePassSignatureList) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1); - currentProgress += 2; - updateProgress(R.string.progress_processing_signature, currentProgress, 100); - - PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; - - // NOTE: following code is similar to processSignature, but for PGPOnePassSignature - - // go through all signatures - // and find out for which signature we have a key in our database - for (int i = 0; i < sigList.size(); ++i) { - try { - long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) - ); - signingKey = signingRing.getPublicKey(sigKeyId); - signatureIndex = i; - } catch (ProviderHelper.NotFoundException e) { - Log.d(Constants.TAG, "key not found, trying next signature..."); - } - } - - if (signingKey != null) { - // key found in our database! - signature = sigList.get(signatureIndex); - - signatureResultBuilder.initValid(signingRing, signingKey); - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); - } else { - // no key in our database -> return "unknown pub key" status including the first key id - if (!sigList.isEmpty()) { - signatureResultBuilder.setSignatureAvailable(true); - signatureResultBuilder.setKnownKey(false); - signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); - } - } - - // check for insecure signing key - // TODO: checks on signingRing ? - if (signingKey != null && ! PgpSecurityConstants.isSecureKey(signingKey)) { - log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); - signatureResultBuilder.setInsecure(true); - } - + PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper); + if (signatureChecker.initializeOnePassSignature(dataChunk, log, indent +1)) { dataChunk = plainFact.nextObject(); } @@ -567,16 +378,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp return result; } - int endProgress; - if (signature != null) { - endProgress = 90; - } else if (esResult != null && esResult.encryptedData.isIntegrityProtected()) { - endProgress = 95; - } else { - endProgress = 100; - } ProgressScaler progressScaler = - new ProgressScaler(mProgressable, currentProgress, endProgress, 100); + new ProgressScaler(mProgressable, currentProgress, 95, 100); InputStream dataIn = literalData.getInputStream(); @@ -592,9 +395,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } // update signature buffer if signature is also present - if (signature != null) { - signature.update(buffer, 0, length); - } + signatureChecker.updateSignatureData(buffer, 0, length); // note down first couple of bytes for "magic bytes" file type detection if (alreadyWritten == 0) { @@ -602,7 +403,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } alreadyWritten += length; - + // noinspection ConstantConditions, TODO progress if (wholeSize > 0) { long progress = 100 * alreadyWritten / wholeSize; // stop at 100% for wrong file sizes... @@ -611,7 +412,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } progressScaler.setProgress((int) progress, 100); } - // TODO: slow annealing to fake a progress? } // special treatment to detect pgp mime types @@ -628,28 +428,15 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp metadata = new OpenPgpMetadata( originalFilename, mimeType, literalData.getModificationTime().getTime(), alreadyWritten, charset); - if (signature != null) { - updateProgress(R.string.progress_verifying_signature, 90, 100); - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); - - PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject(); - PGPSignature messageSignature = signatureList.get(signatureIndex); + if (signatureChecker.isInitialized()) { - // Verify signature - boolean validSignature = signature.verify(messageSignature); - if (validSignature) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); - } else { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); - } + Object o = plainFact.nextObject(); + boolean signatureCheckOk = signatureChecker.verifySignatureOnePass(o, log, indent + 1); - // check for insecure hash algorithms - if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); - signatureResultBuilder.setInsecure(true); + if (!signatureCheckOk) { + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - signatureResultBuilder.setValidSignature(validSignature); } indent -= 1; @@ -664,7 +451,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp log.add(LogType.MSG_DC_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - } else if (signature == null) { + } else if ( ! signatureChecker.isInitialized() ) { // If no signature is present, we *require* an MDC! // Handle missing integrity protection like failed integrity protection! // The MDC packet can be stripped by an attacker! @@ -681,7 +468,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setCachedCryptoInputParcel(cryptoInput); - result.setSignatureResult(signatureResultBuilder.build()); + result.setSignatureResult(signatureChecker.getSignatureResult()); result.setDecryptionResult(decryptionResultBuilder.build()); result.setDecryptionMetadata(metadata); @@ -692,13 +479,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput, PGPEncryptedDataList enc, OperationLog log, int indent, int currentProgress) throws PGPException { - // TODO is this necessary? - /* - else if (obj instanceof PGPEncryptedDataList) { - enc = (PGPEncryptedDataList) pgpF.nextObject(); - } - */ - EncryptStreamResult result = new EncryptStreamResult(); boolean asymmetricPacketFound = false; @@ -739,11 +519,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } - if (secretKeyRing == null) { - // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); - continue; - } // allow only specific keys for decryption? if (input.getAllowedKeyIds() != null) { @@ -763,11 +538,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp // get subkey which has been used for this encryption packet secretEncryptionKey = secretKeyRing.getSecretKey(subKeyId); - if (secretEncryptionKey == null) { - // should actually never happen, so no need to be more specific. - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); - continue; - } /* secret key exists in database and is allowed! */ asymmetricPacketFound = true; @@ -969,30 +739,31 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp OperationLog log = new OperationLog(); - OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] clearText; + { // read cleartext + ByteArrayOutputStream out = new ByteArrayOutputStream(); - updateProgress(R.string.progress_reading_data, 0, 100); + updateProgress(R.string.progress_reading_data, 0, 100); - ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); - int lookAhead = readInputLine(lineOut, aIn); - byte[] lineSep = getLineSeparator(); + ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); + int lookAhead = readInputLine(lineOut, aIn); + byte[] lineSep = getLineSeparator(); - byte[] line = lineOut.toByteArray(); - out.write(line, 0, getLengthWithoutSeparator(line)); - out.write(lineSep); - - while (lookAhead != -1 && aIn.isClearText()) { - lookAhead = readInputLine(lineOut, lookAhead, aIn); - line = lineOut.toByteArray(); + byte[] line = lineOut.toByteArray(); out.write(line, 0, getLengthWithoutSeparator(line)); out.write(lineSep); - } - out.close(); + while (lookAhead != -1 && aIn.isClearText()) { + lookAhead = readInputLine(lineOut, lookAhead, aIn); + line = lineOut.toByteArray(); + out.write(line, 0, getLengthWithoutSeparator(line)); + out.write(lineSep); + } + + out.close(); + clearText = out.toByteArray(); + } - byte[] clearText = out.toByteArray(); if (outputStream != null) { outputStream.write(clearText); outputStream.close(); @@ -1001,51 +772,20 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp updateProgress(R.string.progress_processing_signature, 60, 100); JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(aIn); - PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); - if (sigList == null) { + PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper); + + Object o = pgpFact.nextObject(); + if (!signatureChecker.initializeSignature(o, log, indent+1)) { log.add(LogType.MSG_DC_ERROR_INVALID_DATA, 0); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent); - - if (signature != null) { + if (signatureChecker.isInitialized()) { try { updateProgress(R.string.progress_verifying_signature, 90, 100); - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); - - InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText)); - - lookAhead = readInputLine(lineOut, sigIn); - - processLine(signature, lineOut.toByteArray()); - if (lookAhead != -1) { - do { - lookAhead = readInputLine(lineOut, lookAhead, sigIn); - - signature.update((byte) '\r'); - signature.update((byte) '\n'); - - processLine(signature, lineOut.toByteArray()); - } while (lookAhead != -1); - } - - // Verify signature and check binding signatures - boolean validSignature = signature.verify(); - if (validSignature) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); - } else { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); - } - - // check for insecure hash algorithms - if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); - signatureResultBuilder.setInsecure(true); - } - - signatureResultBuilder.setValidSignature(validSignature); + signatureChecker.updateSignatureWithCleartext(clearText); + signatureChecker.verifySignature(log, indent); } catch (SignatureException e) { Log.d(Constants.TAG, "SignatureException", e); @@ -1064,7 +804,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp clearText.length); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); - result.setSignatureResult(signatureResultBuilder.build()); + result.setSignatureResult(signatureChecker.getSignatureResult()); result.setDecryptionResult( new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED)); result.setDecryptionMetadata(metadata); @@ -1078,30 +818,28 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp OperationLog log = new OperationLog(); - OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - updateProgress(R.string.progress_processing_signature, 0, 100); InputStream detachedSigIn = new ByteArrayInputStream(input.getDetachedSignature()); detachedSigIn = PGPUtil.getDecoderStream(detachedSigIn); JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(detachedSigIn); - PGPSignatureList sigList; Object o = pgpFact.nextObject(); if (o instanceof PGPCompressedData) { PGPCompressedData c1 = (PGPCompressedData) o; pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); - sigList = (PGPSignatureList) pgpFact.nextObject(); - } else if (o instanceof PGPSignatureList) { - sigList = (PGPSignatureList) o; - } else { + o = pgpFact.nextObject(); + } + + PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper); + + if ( ! signatureChecker.initializeSignature(o, log, indent+1)) { log.add(LogType.MSG_DC_ERROR_INVALID_DATA, 0); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent); + if (signatureChecker.isInitialized()) { - if (signature != null) { updateProgress(R.string.progress_reading_data, 60, 100); ProgressScaler progressScaler = new ProgressScaler(mProgressable, 60, 90, 100); @@ -1116,7 +854,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } // update signature buffer if signature is also present - signature.update(buffer, 0, length); + signatureChecker.updateSignatureData(buffer, 0, length); alreadyWritten += length; if (wholeSize > 0) { @@ -1127,105 +865,28 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp } progressScaler.setProgress((int) progress, 100); } - // TODO: slow annealing to fake a progress? } updateProgress(R.string.progress_verifying_signature, 90, 100); log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); - // Verify signature and check binding signatures - boolean validSignature = signature.verify(); - if (validSignature) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); - } else { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); - } - - // check for insecure hash algorithms - if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); - signatureResultBuilder.setInsecure(true); - } + signatureChecker.verifySignature(log, indent); - signatureResultBuilder.setValidSignature(validSignature); } updateProgress(R.string.progress_done, 100, 100); log.add(LogType.MSG_DC_OK, indent); + // TODO return metadata object? + DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); - result.setSignatureResult(signatureResultBuilder.build()); + result.setSignatureResult(signatureChecker.getSignatureResult()); result.setDecryptionResult( new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED)); return result; } - private PGPSignature processPGPSignatureList( - PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder, - OperationLog log, int indent) - throws PGPException { - CanonicalizedPublicKeyRing signingRing = null; - CanonicalizedPublicKey signingKey = null; - int signatureIndex = -1; - - // go through all signatures - // and find out for which signature we have a key in our database - for (int i = 0; i < sigList.size(); ++i) { - try { - long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) - ); - signingKey = signingRing.getPublicKey(sigKeyId); - signatureIndex = i; - } catch (ProviderHelper.NotFoundException e) { - Log.d(Constants.TAG, "key not found, trying next signature..."); - } - } - - PGPSignature signature = null; - - if (signingKey != null) { - // key found in our database! - signature = sigList.get(signatureIndex); - - signatureResultBuilder.initValid(signingRing, signingKey); - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); - } else { - // no key in our database -> return "unknown pub key" status including the first key id - if (!sigList.isEmpty()) { - signatureResultBuilder.setSignatureAvailable(true); - signatureResultBuilder.setKnownKey(false); - signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); - } - } - - // check for insecure signing key - // TODO: checks on signingRing ? - if (signingKey != null && ! PgpSecurityConstants.isSecureKey(signingKey)) { - log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); - signatureResultBuilder.setInsecure(true); - } - - return signature; - } - - /** - * Mostly taken from ClearSignedFileProcessor in Bouncy Castle - */ - private static void processLine(PGPSignature sig, byte[] line) - throws SignatureException { - int length = getLengthWithoutWhiteSpace(line); - if (length > 0) { - sig.update(line, 0, length); - } - } - private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn) throws IOException { bOut.reset(); @@ -1291,20 +952,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp return b == '\r' || b == '\n'; } - private static int getLengthWithoutWhiteSpace(byte[] line) { - int end = line.length - 1; - - while (end >= 0 && isWhiteSpace(line[end])) { - end--; - } - - return end + 1; - } - - private static boolean isWhiteSpace(byte b) { - return b == '\r' || b == '\n' || b == '\t' || b == ' '; - } - private static byte[] getLineSeparator() { String nl = System.getProperty("line.separator"); return nl.getBytes(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 6f156c201..59b840054 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -171,8 +171,8 @@ public class PgpKeyOperation { log.add(LogType.MSG_CR_ERROR_NO_KEYSIZE, indent); return null; } - if (add.mKeySize < 512) { - log.add(LogType.MSG_CR_ERROR_KEYSIZE_512, indent); + if (add.mKeySize < 2048) { + log.add(LogType.MSG_CR_ERROR_KEYSIZE_2048, indent); return null; } } 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 0879181a7..ecc190d97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -492,9 +492,7 @@ public class PgpSignEncryptOperation extends BaseOperation { literalGen.close(); } else { - pOut = null; - // TODO: Is this log right? - log.add(LogType.MSG_PSE_CLEARSIGN_ONLY, indent); + throw new AssertionError("cannot clearsign in non-ascii armored text, this is a bug!"); } if (enableSignature) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java new file mode 100644 index 000000000..4067372a1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java @@ -0,0 +1,344 @@ +package org.sufficientlysecure.keychain.pgp; + + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.SignatureException; + +import org.openintents.openpgp.OpenPgpSignatureResult; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.Log; + + +/** This class is used to track the state of a single signature verification. + * + * + */ +class PgpSignatureChecker { + + OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); + + private CanonicalizedPublicKey signingKey; + + private int signatureIndex; + PGPOnePassSignature onePassSignature; + PGPSignature signature; + + ProviderHelper mProviderHelper; + + PgpSignatureChecker(ProviderHelper providerHelper) { + mProviderHelper = providerHelper; + } + + boolean initializeSignature(Object dataChunk, OperationLog log, int indent) throws PGPException { + + if (!(dataChunk instanceof PGPSignatureList)) { + return false; + } + + PGPSignatureList sigList = (PGPSignatureList) dataChunk; + findAvailableSignature(sigList); + + if (signingKey != null) { + + // key found in our database! + signatureResultBuilder.initValid(signingKey); + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); + checkKeySecurity(log, indent); + + + } else if (!sigList.isEmpty()) { + + signatureResultBuilder.setSignatureAvailable(true); + signatureResultBuilder.setKnownKey(false); + signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); + + } + + return true; + + } + + boolean initializeOnePassSignature(Object dataChunk, OperationLog log, int indent) throws PGPException { + + if (!(dataChunk instanceof PGPOnePassSignatureList)) { + return false; + } + + log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1); + + PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; + findAvailableSignature(sigList); + + if (signingKey != null) { + + // key found in our database! + signatureResultBuilder.initValid(signingKey); + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + onePassSignature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); + + checkKeySecurity(log, indent); + + } else if (!sigList.isEmpty()) { + + signatureResultBuilder.setSignatureAvailable(true); + signatureResultBuilder.setKnownKey(false); + signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); + + } + + return true; + + } + + private void checkKeySecurity(OperationLog log, int indent) { + // TODO: checks on signingRing ? + if (!PgpSecurityConstants.isSecureKey(signingKey)) { + log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); + signatureResultBuilder.setInsecure(true); + } + } + + public boolean isInitialized() { + return signingKey != null; + } + + private void findAvailableSignature(PGPOnePassSignatureList sigList) { + // go through all signatures (should be just one), make sure we have + // the key and it matches the one we’re looking for + for (int i = 0; i < sigList.size(); ++i) { + try { + long sigKeyId = sigList.get(i).getKeyID(); + CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) + ); + CanonicalizedPublicKey keyCandidate = signingRing.getPublicKey(sigKeyId); + if ( ! signingKey.canSign()) { + continue; + } + signatureIndex = i; + signingKey = keyCandidate; + onePassSignature = sigList.get(i); + return; + } catch (ProviderHelper.NotFoundException e) { + Log.d(Constants.TAG, "key not found, trying next signature..."); + } + } + } + + public void findAvailableSignature(PGPSignatureList sigList) { + // go through all signatures (should be just one), make sure we have + // the key and it matches the one we’re looking for + for (int i = 0; i < sigList.size(); ++i) { + try { + long sigKeyId = sigList.get(i).getKeyID(); + CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) + ); + CanonicalizedPublicKey keyCandidate = signingRing.getPublicKey(sigKeyId); + if ( ! signingKey.canSign()) { + continue; + } + signatureIndex = i; + signingKey = keyCandidate; + signature = sigList.get(i); + return; + } catch (ProviderHelper.NotFoundException e) { + Log.d(Constants.TAG, "key not found, trying next signature..."); + } + } + } + + public void updateSignatureWithCleartext(byte[] clearText) throws IOException, SignatureException { + + InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText)); + + ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); + + int lookAhead = readInputLine(outputBuffer, sigIn); + + processLine(signature, outputBuffer.toByteArray()); + + while (lookAhead != -1) { + lookAhead = readInputLine(outputBuffer, lookAhead, sigIn); + + signature.update((byte) '\r'); + signature.update((byte) '\n'); + + processLine(signature, outputBuffer.toByteArray()); + } + + } + + public void updateSignatureData(byte[] buf, int off, int len) { + if (signature != null) { + signature.update(buf, off, len); + } else if (onePassSignature != null) { + onePassSignature.update(buf, off, len); + } + } + + void verifySignature(OperationLog log, int indent) throws PGPException { + + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); + + // Verify signature + boolean validSignature = signature.verify(); + if (validSignature) { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); + } else { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); + } + + // check for insecure hash algorithms + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); + signatureResultBuilder.setInsecure(true); + } + + signatureResultBuilder.setValidSignature(validSignature); + + } + + boolean verifySignatureOnePass(Object o, OperationLog log, int indent) throws PGPException { + + if (!(o instanceof PGPSignatureList)) { + log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent); + return false; + } + PGPSignatureList signatureList = (PGPSignatureList) o; + if (signatureList.size() <= signatureIndex) { + log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent); + return false; + } + + // PGPOnePassSignature and PGPSignature packets are "bracketed", + // so we need to take the last-minus-index'th element here + PGPSignature messageSignature = signatureList.get(signatureList.size() - 1 - signatureIndex); + + // Verify signature + boolean validSignature = onePassSignature.verify(messageSignature); + if (validSignature) { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); + } else { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); + } + + // check for insecure hash algorithms + if (!PgpSecurityConstants.isSecureHashAlgorithm(onePassSignature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); + signatureResultBuilder.setInsecure(true); + } + + signatureResultBuilder.setValidSignature(validSignature); + + return true; + + } + + public byte[] getSigningFingerprint() { + return signingKey.getFingerprint(); + } + + public OpenPgpSignatureResult getSignatureResult() { + return signatureResultBuilder.build(); + } + + /** + * Mostly taken from ClearSignedFileProcessor in Bouncy Castle + */ + + private static void processLine(PGPSignature sig, byte[] line) + throws SignatureException { + int length = getLengthWithoutWhiteSpace(line); + if (length > 0) { + sig.update(line, 0, length); + } + } + + private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn) + throws IOException { + bOut.reset(); + + int lookAhead = -1; + int ch; + + while ((ch = fIn.read()) >= 0) { + bOut.write(ch); + if (ch == '\r' || ch == '\n') { + lookAhead = readPastEOL(bOut, ch, fIn); + break; + } + } + + return lookAhead; + } + + private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn) + throws IOException { + bOut.reset(); + + int ch = lookAhead; + + do { + bOut.write(ch); + if (ch == '\r' || ch == '\n') { + lookAhead = readPastEOL(bOut, ch, fIn); + break; + } + } while ((ch = fIn.read()) >= 0); + + if (ch < 0) { + lookAhead = -1; + } + + return lookAhead; + } + + private static int readPastEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) + throws IOException { + int lookAhead = fIn.read(); + + if (lastCh == '\r' && lookAhead == '\n') { + bOut.write(lookAhead); + lookAhead = fIn.read(); + } + + return lookAhead; + } + + private static int getLengthWithoutWhiteSpace(byte[] line) { + int end = line.length - 1; + + while (end >= 0 && isWhiteSpace(line[end])) { + end--; + } + + return end + 1; + } + + private static boolean isWhiteSpace(byte b) { + return b == '\r' || b == '\n' || b == '\t' || b == ' '; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index c8cdbd59d..c967a5abc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -83,6 +83,8 @@ public class UncachedKeyRing { final PGPKeyRing mRing; final boolean mIsSecret; + private static final int CANONICALIZE_MAX_USER_IDS = 100; + UncachedKeyRing(PGPKeyRing ring) { mRing = ring; mIsSecret = ring instanceof PGPSecretKeyRing; @@ -460,7 +462,7 @@ public class UncachedKeyRing { // strip out the first found user id with this name modified = PGPPublicKey.removeCertification(modified, rawUserId); } - if (processedUserIds.size() > 100) { + if (processedUserIds.size() > CANONICALIZE_MAX_USER_IDS) { log.add(LogType.MSG_KC_UID_TOO_MANY, indent, userId); // strip out the user id modified = PGPPublicKey.removeCertification(modified, rawUserId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index a6823d3ac..375775ff1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -62,7 +62,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; @@ -968,7 +967,7 @@ public class ProviderHelper { // If we have an expected fingerprint, make sure it matches if (expectedFingerprint != null) { - if (!canPublicRing.containsSubkey(expectedFingerprint)) { + if (!canPublicRing.containsBoundSubkey(expectedFingerprint)) { log(LogType.MSG_IP_FINGERPRINT_ERROR); return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java index f7925b7f4..648c5f962 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java @@ -49,7 +49,7 @@ public class CreateYubiKeyImportFragment extends QueueingCryptoOperationFragment<ImportKeyringParcel, ImportKeyResult> implements NfcListenerFragment { - private static final String ARG_FINGERPRINT = "fingerprint"; + private static final String ARG_FINGERPRINTS = "fingerprint"; public static final String ARG_AID = "aid"; public static final String ARG_USER_ID = "user_ids"; @@ -72,7 +72,7 @@ public class CreateYubiKeyImportFragment CreateYubiKeyImportFragment frag = new CreateYubiKeyImportFragment(); Bundle args = new Bundle(); - args.putByteArray(ARG_FINGERPRINT, scannedFingerprints); + args.putByteArray(ARG_FINGERPRINTS, scannedFingerprints); args.putByteArray(ARG_AID, nfcAid); args.putString(ARG_USER_ID, userId); frag.setArguments(args); @@ -86,7 +86,7 @@ public class CreateYubiKeyImportFragment Bundle args = savedInstanceState != null ? savedInstanceState : getArguments(); - mNfcFingerprints = args.getByteArray(ARG_FINGERPRINT); + mNfcFingerprints = args.getByteArray(ARG_FINGERPRINTS); mNfcAid = args.getByteArray(ARG_AID); mNfcUserId = args.getString(ARG_USER_ID); @@ -149,7 +149,7 @@ public class CreateYubiKeyImportFragment public void onSaveInstanceState(Bundle args) { super.onSaveInstanceState(args); - args.putByteArray(ARG_FINGERPRINT, mNfcFingerprints); + args.putByteArray(ARG_FINGERPRINTS, mNfcFingerprints); args.putByteArray(ARG_AID, mNfcAid); args.putString(ARG_USER_ID, mNfcUserId); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java index dc06e9115..1060714f0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java @@ -36,7 +36,6 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; -import org.sufficientlysecure.keychain.util.ShareHelper; public class DisplayTextFragment extends DecryptFragment { @@ -60,22 +59,6 @@ public class DisplayTextFragment extends DecryptFragment { return frag; } - /** - * Create Intent Chooser but exclude decrypt activites - */ - private Intent sendWithChooserExcludingDecrypt(String text) { - Intent prototype = createSendIntent(text); - String title = getString(R.string.title_share_message); - - // we don't want to decrypt the decrypted, no inception ;) - String[] blacklist = new String[]{ - Constants.PACKAGE_NAME + ".ui.DecryptActivity", - "org.thialfihar.android.apg.ui.DecryptActivity" - }; - - return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist); - } - private Intent createSendIntent(String text) { Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, text); @@ -146,7 +129,8 @@ public class DisplayTextFragment extends DecryptFragment { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.decrypt_share: { - startActivity(sendWithChooserExcludingDecrypt(mText.getText().toString())); + startActivity(Intent.createChooser(createSendIntent(mText.getText().toString()), + getString(R.string.title_share_message))); break; } case R.id.decrypt_copy: { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index dab451537..3d1629ffb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -71,7 +71,6 @@ import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.util.ShareHelper; public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEncryptParcel, SignEncryptResult> { @@ -406,7 +405,7 @@ public class EncryptFilesFragment public void onDeleted() { if (mAfterEncryptAction == AfterEncryptAction.SHARE) { // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt()); + startActivity(Intent.createChooser(createSendIntent(), getString(R.string.title_share_file))); } else { Activity activity = getActivity(); if (activity == null) { @@ -426,7 +425,7 @@ public class EncryptFilesFragment case SHARE: // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt()); + startActivity(Intent.createChooser(createSendIntent(), getString(R.string.title_share_file))); break; case COPY: @@ -622,22 +621,6 @@ public class EncryptFilesFragment return data; } - /** - * Create Intent Chooser but exclude OK's EncryptActivity. - */ - private Intent sendWithChooserExcludingEncrypt() { - Intent prototype = createSendIntent(); - String title = getString(R.string.title_share_file); - - // we don't want to encrypt the encrypted, no inception ;) - String[] blacklist = new String[]{ - Constants.PACKAGE_NAME + ".ui.EncryptFilesActivity", - "org.thialfihar.android.apg.ui.EncryptActivity" - }; - - return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist); - } - private Intent createSendIntent() { Intent sendIntent; // file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index ab676285e..0513a6495 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -46,7 +46,6 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.util.ShareHelper; import java.util.Date; import java.util.HashSet; @@ -289,22 +288,6 @@ public class EncryptTextFragment result.createNotify(activity).show(); } - /** - * Create Intent Chooser but exclude OK's EncryptActivity. - */ - private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) { - Intent prototype = createSendIntent(resultBytes); - String title = getString(R.string.title_share_message); - - // we don't want to encrypt the encrypted, no inception ;) - String[] blacklist = new String[]{ - Constants.PACKAGE_NAME + ".ui.EncryptTextActivity", - "org.thialfihar.android.apg.ui.EncryptActivity" - }; - - return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist); - } - private Intent createSendIntent(byte[] resultBytes) { Intent sendIntent; sendIntent = new Intent(Intent.ACTION_SEND); @@ -343,7 +326,8 @@ public class EncryptTextFragment if (mShareAfterEncrypt) { // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes())); + startActivity(Intent.createChooser(createSendIntent(result.getResultBytes()), + getString(R.string.title_share_message))); } else { // Copy to clipboard copyToClipboard(result); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java index 43c8d2643..e29cd0204 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java @@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEnt import org.sufficientlysecure.keychain.operations.results.OperationResult.LogLevel; import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.ui.dialog.ShareLogDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; @@ -149,11 +150,9 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe } } - Intent intent = new Intent(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_STREAM, mLogTempFile); - intent.setType("text/plain"); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(intent); + + ShareLogDialogFragment shareLogDialog = ShareLogDialogFragment.newInstance(mLogTempFile); + shareLogDialog.show(getActivity().getSupportFragmentManager(), "shareLogDialog"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java index b51d081e1..cd5281c7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java @@ -348,30 +348,30 @@ public class AddSubkeyDialogFragment extends DialogFragment { /** * <h3>RSA</h3> - * <p>for RSA algorithm, key length must be greater than 1024 (according to - * <a href="https://github.com/open-keychain/open-keychain/issues/102">#102</a>). Possibility to generate keys bigger + * <p>for RSA algorithm, key length must be greater than 2048. Possibility to generate keys bigger * than 8192 bits is currently disabled, because it's almost impossible to generate them on a mobile device (check * <a href="http://www.javamex.com/tutorials/cryptography/rsa_key_length.shtml">RSA key length plot</a> and * <a href="http://www.keylength.com/">Cryptographic Key Length Recommendation</a>). Also, key length must be a * multiplicity of 8.</p> * <h3>ElGamal</h3> - * <p>For ElGamal algorithm, supported key lengths are 1536, 2048, 3072, 4096 or 8192 bits.</p> + * <p>For ElGamal algorithm, supported key lengths are 2048, 3072, 4096 or 8192 bits.</p> * <h3>DSA</h3> - * <p>For DSA algorithm key length must be between 512 and 1024. Also, it must me dividable by 64.</p> + * <p>For DSA algorithm key length must be between 2048 and 3072. Also, it must me dividable by 64.</p> * * @return correct key length, according to SpongyCastle specification. Returns <code>-1</code>, if key length is * inappropriate. */ private int getProperKeyLength(Algorithm algorithm, int currentKeyLength) { - final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192}; + final int[] elGamalSupportedLengths = {2048, 3072, 4096, 8192}; int properKeyLength = -1; switch (algorithm) { - case RSA: - if (currentKeyLength > 1024 && currentKeyLength <= 16384) { + case RSA: { + if (currentKeyLength >= 2048 && currentKeyLength <= 16384) { properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8); } break; - case ELGAMAL: + } + case ELGAMAL: { int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length]; for (int i = 0; i < elGamalSupportedLengths.length; i++) { elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength); @@ -386,11 +386,14 @@ public class AddSubkeyDialogFragment extends DialogFragment { } properKeyLength = elGamalSupportedLengths[minimalIndex]; break; - case DSA: - if (currentKeyLength >= 512 && currentKeyLength <= 1024) { + } + case DSA: { + // Bouncy Castle supports 4096 maximum + if (currentKeyLength >= 2048 && currentKeyLength <= 4096) { properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64); } break; + } } return properKeyLength; } @@ -424,7 +427,7 @@ public class AddSubkeyDialogFragment extends DialogFragment { final ArrayAdapter<CharSequence> keySizeAdapter = (ArrayAdapter<CharSequence>) mKeySizeSpinner.getAdapter(); keySizeAdapter.clear(); switch (algorithm) { - case RSA: + case RSA: { replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values); mKeySizeSpinner.setSelection(1); mKeySizeRow.setVisibility(View.VISIBLE); @@ -450,7 +453,8 @@ public class AddSubkeyDialogFragment extends DialogFragment { } mFlagAuthenticate.setChecked(false); break; - case ELGAMAL: + } + case ELGAMAL: { replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values); mKeySizeSpinner.setSelection(3); mKeySizeRow.setVisibility(View.VISIBLE); @@ -466,7 +470,8 @@ public class AddSubkeyDialogFragment extends DialogFragment { mFlagAuthenticate.setChecked(false); mFlagAuthenticate.setEnabled(false); break; - case DSA: + } + case DSA: { replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values); mKeySizeSpinner.setSelection(2); mKeySizeRow.setVisibility(View.VISIBLE); @@ -482,7 +487,8 @@ public class AddSubkeyDialogFragment extends DialogFragment { mFlagAuthenticate.setChecked(false); mFlagAuthenticate.setEnabled(false); break; - case ECDSA: + } + case ECDSA: { mKeySizeRow.setVisibility(View.GONE); mCurveRow.setVisibility(View.VISIBLE); mCustomKeyInfoTextView.setText(""); @@ -496,7 +502,8 @@ public class AddSubkeyDialogFragment extends DialogFragment { mFlagAuthenticate.setEnabled(true); mFlagAuthenticate.setChecked(false); break; - case ECDH: + } + case ECDH: { mKeySizeRow.setVisibility(View.GONE); mCurveRow.setVisibility(View.VISIBLE); mCustomKeyInfoTextView.setText(""); @@ -510,6 +517,7 @@ public class AddSubkeyDialogFragment extends DialogFragment { mFlagAuthenticate.setChecked(false); mFlagAuthenticate.setEnabled(false); break; + } } keySizeAdapter.notifyDataSetChanged(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java new file mode 100644 index 000000000..d4783fad2 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui.dialog; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.view.ContextThemeWrapper; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.util.ThemeChanger; + +public class ShareLogDialogFragment extends DialogFragment { + private static final String ARG_STREAM = "stream"; + + public static ShareLogDialogFragment newInstance(Uri stream) { + Bundle args = new Bundle(); + args.putParcelable(ARG_STREAM, stream); + + ShareLogDialogFragment fragment = new ShareLogDialogFragment(); + fragment.setArguments(args); + + return fragment; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + final Uri stream = getArguments().getParcelable(ARG_STREAM); + + ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(getActivity()); + + CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme); + builder.setTitle(R.string.share_log_dialog_title) + .setMessage(R.string.share_log_dialog_message) + .setNegativeButton(R.string.share_log_dialog_cancel_button, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismiss(); + } + }) + .setPositiveButton(R.string.share_log_dialog_share_button, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismiss(); + Intent intent = new Intent(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_STREAM, stream); + intent.setType("text/plain"); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + startActivity(intent); + } + }); + + return builder.show(); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java deleted file mode 100644 index 0297d149c..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.LabeledIntent; -import android.content.pm.ResolveInfo; -import android.os.Build; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class ShareHelper { - Context mContext; - - public ShareHelper(Context context) { - mContext = context; - } - - /** - * Create Intent Chooser but exclude specific activites, e.g., EncryptActivity to prevent encrypting again - * <p/> - * Put together from some stackoverflow posts... - */ - public Intent createChooserExcluding(Intent prototype, String title, String[] activityBlacklist) { - // Produced an empty list on Huawei U8860 with Android Version 4.0.3 - // TODO: test on 4.1, 4.2, 4.3, only tested on 4.4 - // Disabled on 5.0 because using EXTRA_INITIAL_INTENTS prevents the usage based sorting - // introduced in 5.0: https://medium.com/@xXxXxXxXxXam/how-lollipops-share-menu-is-organized-d204888f606d - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return Intent.createChooser(prototype, title); - } - - List<LabeledIntent> targetedShareIntents = new ArrayList<>(); - - List<ResolveInfo> resInfoList = mContext.getPackageManager().queryIntentActivities(prototype, 0); - List<ResolveInfo> resInfoListFiltered = new ArrayList<>(); - if (!resInfoList.isEmpty()) { - for (ResolveInfo resolveInfo : resInfoList) { - // do not add blacklisted ones - if (resolveInfo.activityInfo == null || Arrays.asList(activityBlacklist).contains(resolveInfo.activityInfo.name)) - continue; - - resInfoListFiltered.add(resolveInfo); - } - - if (!resInfoListFiltered.isEmpty()) { - // sorting for nice readability - Collections.sort(resInfoListFiltered, new Comparator<ResolveInfo>() { - @Override - public int compare(ResolveInfo first, ResolveInfo second) { - String firstName = first.loadLabel(mContext.getPackageManager()).toString(); - String secondName = second.loadLabel(mContext.getPackageManager()).toString(); - return firstName.compareToIgnoreCase(secondName); - } - }); - - // create the custom intent list - for (ResolveInfo resolveInfo : resInfoListFiltered) { - Intent targetedShareIntent = (Intent) prototype.clone(); - targetedShareIntent.setPackage(resolveInfo.activityInfo.packageName); - targetedShareIntent.setClassName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); - - LabeledIntent lIntent = new LabeledIntent(targetedShareIntent, - resolveInfo.activityInfo.packageName, - resolveInfo.loadLabel(mContext.getPackageManager()), - resolveInfo.activityInfo.icon); - targetedShareIntents.add(lIntent); - } - - // Create chooser with only one Intent in it - Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1), title); - // append all other Intents - // TODO this line looks wrong?! - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{})); - return chooserIntent; - } - - } - - // fallback to Android's default chooser - return Intent.createChooser(prototype, title); - } -} diff --git a/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml index d4ece38ac..c1f692a88 100644 --- a/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml @@ -62,6 +62,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_back" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" @@ -79,6 +80,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_next" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" diff --git a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml index 9a6c33f82..118f0661a 100644 --- a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml @@ -155,6 +155,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_back" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" @@ -172,6 +173,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_create_key" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" diff --git a/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml index 7b8ba3fc1..4e37dd713 100644 --- a/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml @@ -56,6 +56,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_back" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" @@ -73,6 +74,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_next" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" diff --git a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml index 9d10bbe70..9368aa1ef 100644 --- a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml @@ -74,6 +74,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/btn_back" android:textAllCaps="true" @@ -91,6 +92,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/btn_next" android:textAllCaps="true" diff --git a/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml index 20c434c02..622cdf5a0 100644 --- a/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml @@ -74,6 +74,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/first_time_import_key" android:textAllCaps="true" @@ -91,6 +92,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/btn_do_not_save" android:textAllCaps="true" diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml index ca203d0b5..7e2bf2246 100644 --- a/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml @@ -45,6 +45,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_back" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" @@ -52,8 +53,7 @@ android:drawablePadding="8dp" android:gravity="left|center_vertical" android:clickable="true" - style="?android:attr/borderlessButtonStyle" - android:layout_gravity="center_vertical" /> + style="?android:attr/borderlessButtonStyle" /> <TextView android:id="@+id/create_key_next_button" @@ -63,6 +63,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/first_time_blank_yubikey_yes" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" @@ -70,7 +71,6 @@ android:drawablePadding="8dp" android:gravity="center_vertical|right" android:clickable="true" - style="?android:attr/borderlessButtonStyle" - android:layout_gravity="center_vertical" /> + style="?android:attr/borderlessButtonStyle" /> </LinearLayout> </RelativeLayout> diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml index 838ee37b4..3a54f264f 100644 --- a/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml @@ -94,6 +94,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/btn_back" android:textAllCaps="true" @@ -111,6 +112,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/btn_import" android:textAllCaps="true" diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml index 393ec76d4..34871affe 100644 --- a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml @@ -80,6 +80,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_back" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" @@ -97,6 +98,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:text="@string/btn_next" android:textAllCaps="true" android:minHeight="?android:attr/listPreferredItemHeight" diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml index d233398ca..af9080f55 100644 --- a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml @@ -79,6 +79,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:clickable="true" android:drawableLeft="@drawable/ic_chevron_left_grey_24dp" android:drawablePadding="8dp" @@ -96,6 +97,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" android:clickable="true" android:drawablePadding="8dp" android:drawableRight="@drawable/ic_chevron_right_grey_24dp" diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml index a000dc82e..7f26995a7 100644 --- a/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml +++ b/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml @@ -56,27 +56,11 @@ android:minHeight="?android:attr/listPreferredItemHeight" android:drawableLeft="@drawable/ic_chevron_left_grey_24dp" android:drawablePadding="8dp" + android:layout_gravity="center_vertical" android:gravity="left|center_vertical" android:clickable="true" style="?android:attr/borderlessButtonStyle" /> - <TextView - android:id="@+id/create_key_next_button" - android:paddingLeft="16dp" - android:paddingRight="16dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/btn_next" - android:textAllCaps="true" - android:minHeight="?android:attr/listPreferredItemHeight" - android:drawableRight="@drawable/yubi_icon_24dp" - android:drawablePadding="16dp" - android:gravity="right|center_vertical" - android:clickable="false" - style="?android:attr/borderlessButtonStyle" /> - </LinearLayout> </RelativeLayout> diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml index 0e4a43c6f..7de834eea 100644 --- a/OpenKeychain/src/main/res/values-de/strings.xml +++ b/OpenKeychain/src/main/res/values-de/strings.xml @@ -922,7 +922,7 @@ <string name="msg_cr_error_no_user_id">Schlüsselbünde müssen mindestens eine User-ID enthalten!</string> <string name="msg_cr_error_no_certify">Hauptschlüssel benötigt das Attribut beglaubigen!</string> <string name="msg_cr_error_null_expiry">Ablaufdatum kann bei Schlüsselerstellung nicht \'gleiche wie vorher\' sein. Dies ist ein Programmierfehler, bitte reiche einen Fehlerbericht ein!</string> - <string name="msg_cr_error_keysize_512">Schlüssellänge muss größer/gleich 512 sein!</string> + <string name="msg_cr_error_keysize_2048">Schlüssellänge muss größer/gleich 512 sein!</string> <string name="msg_cr_error_no_curve">Keine Schlüssellänge spezifiziert! Dies ist ein Progammierfehler, bitte reiche einen Fehlerbericht ein!</string> <string name="msg_cr_error_no_keysize">Keine Elliptische Kurve spezifiziert! Dies ist ein Progammierfehler, bitte reiche einen Fehlerbericht ein!</string> <string name="msg_cr_error_internal_pgp">Interner OpenPGP Fehler!</string> diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml index a6849c542..fa0a53b88 100644 --- a/OpenKeychain/src/main/res/values-es/strings.xml +++ b/OpenKeychain/src/main/res/values-es/strings.xml @@ -921,7 +921,7 @@ <string name="msg_cr_error_no_user_id">¡Los juegos de claves tienen que crearse con al menos una identificación de usuario!</string> <string name="msg_cr_error_no_certify">¡La clave maestra debe tener el indicador de certificado!</string> <string name="msg_cr_error_null_expiry">El periodo hasta la expiración no puede ser \'el mismo que antes\' al crear clave. Esto es un error de programación, ¡por favor consigne un informe de error!</string> - <string name="msg_cr_error_keysize_512">¡El tamaño de la clave debe ser mayor o igual de 512!</string> + <string name="msg_cr_error_keysize_2048">¡El tamaño de la clave debe ser mayor o igual de 512!</string> <string name="msg_cr_error_no_curve">¡No se especificó tamaño de clave! ¡Esto es un error de programación, por favor consigne un informe de fallo!</string> <string name="msg_cr_error_no_keysize">¡No se especificó curva elíptica! ¡Esto es un error de programación, por favor consigne un informe de fallo!</string> <string name="msg_cr_error_internal_pgp">¡Error OpenPGP interno!</string> diff --git a/OpenKeychain/src/main/res/values-eu/strings.xml b/OpenKeychain/src/main/res/values-eu/strings.xml index f57297498..81daa67ef 100644 --- a/OpenKeychain/src/main/res/values-eu/strings.xml +++ b/OpenKeychain/src/main/res/values-eu/strings.xml @@ -850,7 +850,7 @@ <string name="msg_cr_error_no_user_id">Giltza-uztaiak gutxienez erabiltzaile ID batekin sortu behar dira!</string> <string name="msg_cr_error_no_certify">Maisu giltzak egiaztagiri ikurra izan behar du!</string> <string name="msg_cr_error_null_expiry">Epemuga ezin daiteke giltza sortzea baino \'lehenago\' izan. Hau programazio akats bat da, mesedez agiritu akats jakinarazpen bat!</string> - <string name="msg_cr_error_keysize_512">Giltza neurria 512 edo handiagoa izan behar da!</string> + <string name="msg_cr_error_keysize_2048">Giltza neurria 512 edo handiagoa izan behar da!</string> <string name="msg_cr_error_no_curve">Ez da giltzaren neurria adierazi! Hau programazio akats bat da, mesedez agiritu akats jakinarazpen bat!</string> <string name="msg_cr_error_internal_pgp">Barneko OpenPGP akatsa!</string> <string name="msg_cr_error_unknown_algo">Algoritmo ezezaguna hautatu da! Hau programazio akats bat da, mesedez agiritu akats jakinarazpen bat!</string> diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml index b5e5f3d53..d67a9560f 100644 --- a/OpenKeychain/src/main/res/values-fr/strings.xml +++ b/OpenKeychain/src/main/res/values-fr/strings.xml @@ -921,7 +921,7 @@ <string name="msg_cr_error_no_user_id">Les trousseaux doivent être créés avec au moins un ID utilisateur !</string> <string name="msg_cr_error_no_certify">La clef maîtresse doit avoir le drapeau « certifié » !</string> <string name="msg_cr_error_null_expiry">L\'expiration ne peut pas être « pareille qu\'avant » à la création de la clef. C\'est une erreur du programme, veuillez remplir un rapport de bogue !</string> - <string name="msg_cr_error_keysize_512">La taille de la clef doit être supérieure ou égale à 512 !</string> + <string name="msg_cr_error_keysize_2048">La taille de la clef doit être supérieure ou égale à 512 !</string> <string name="msg_cr_error_no_curve">Aucune taille de clef n\'a été spécifiée ! C\'est une erreur de programmation, veuillez remplir un rapport de bogue !</string> <string name="msg_cr_error_no_keysize">Aucune courbe elliptique n\'a été spécifiée ! C\'est une erreur de programmation, veuillez remplir un rapport de bogue !</string> <string name="msg_cr_error_internal_pgp">Erreur interne OpenPGP !</string> diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml index 5b87c6ced..c158e341c 100644 --- a/OpenKeychain/src/main/res/values-it/strings.xml +++ b/OpenKeychain/src/main/res/values-it/strings.xml @@ -658,7 +658,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars <string name="msg_cr_error_no_master">Nessuna opzione della chiave principale specificata!</string> <string name="msg_cr_error_no_certify">La chiave principale deve avere la caratteristica di certificazione!</string> <string name="msg_cr_error_null_expiry">La data di scadenza non può essere \'come prima\' sulla creazione di chiavi. Questo è un errore di programmazione, si prega di inviare una segnalazione di bug!</string> - <string name="msg_cr_error_keysize_512">La grandezza della chiave deve essere di 512bit o maggiore</string> + <string name="msg_cr_error_keysize_2048">La grandezza della chiave deve essere di 512bit o maggiore</string> <string name="msg_cr_error_no_keysize">Nessuna curva ellittica specificata! Questo è un errore di programmazione, per favore invia una segnalazione!</string> <!--modifySecretKeyRing--> <string name="msg_mr">Modifica del portachiavi %s</string> diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml index 789a35e75..3abf085c6 100644 --- a/OpenKeychain/src/main/res/values-ja/strings.xml +++ b/OpenKeychain/src/main/res/values-ja/strings.xml @@ -898,7 +898,7 @@ <string name="msg_cr_error_no_user_id">鍵輪は最低でも1つのユーザIDの生成が必要です!</string> <string name="msg_cr_error_no_certify">主鍵は検証フラグが必須です!</string> <string name="msg_cr_error_null_expiry">鍵の生成時に期限を\'過去\'とすることはできません。これはプログラムエラーで、バグレポートでファイルを送ってください!</string> - <string name="msg_cr_error_keysize_512">鍵サイズは512かそれ以上が必須です!</string> + <string name="msg_cr_error_keysize_2048">鍵サイズは512かそれ以上が必須です!</string> <string name="msg_cr_error_no_curve">鍵サイズが不明です! これはプログラムエラーで、バグレポートでファイルの提出をお願いします!</string> <string name="msg_cr_error_no_keysize">楕円暗号が不明です! これはプログラムエラーで、バグレポートでファイルの提出をお願いします!</string> <string name="msg_cr_error_internal_pgp">PGP内部エラー!</string> diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml index 812376026..29d0cd57d 100644 --- a/OpenKeychain/src/main/res/values-nl/strings.xml +++ b/OpenKeychain/src/main/res/values-nl/strings.xml @@ -877,7 +877,7 @@ <string name="msg_cr_error_no_user_id">Sleutelbossen moeten met minstens een gebruikers-ID aangemaakt worden!</string> <string name="msg_cr_error_no_certify">Hoofdsleutel moet certificeer-vlag hebben!</string> <string name="msg_cr_error_null_expiry">Verloopdatum kan niet hetzelfde als voordien zijn bij aanmaken van een sleutel. Dit is een bug, gelieve een verslag in te dienen!</string> - <string name="msg_cr_error_keysize_512">Sleutelgrootte moet groter dan of gelijk zijn aan 512!</string> + <string name="msg_cr_error_keysize_2048">Sleutelgrootte moet groter dan of gelijk zijn aan 512!</string> <string name="msg_cr_error_no_curve">Geen sleutelgrootte opgegeven! Dit is een bug, gelieve een verslag in te dienen!</string> <string name="msg_cr_error_no_keysize">Geen elliptische curve opgegeven! Dit is een bug, gelieve een verslag in te dienen!</string> <string name="msg_cr_error_internal_pgp">Interne OpenPGP-fout!</string> diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml index 6b73d367c..e3f9ccaea 100644 --- a/OpenKeychain/src/main/res/values-ru/strings.xml +++ b/OpenKeychain/src/main/res/values-ru/strings.xml @@ -768,7 +768,7 @@ <string name="msg_cr_error_no_user_id">Связки должны создаваться с хотя бы одним ID пользователя!</string> <string name="msg_cr_error_no_certify">Основной ключ должен иметь флаг сертификата!</string> <string name="msg_cr_error_null_expiry">Срок годности не может быть \'такой же как раньше\' при создании ключа. Это программная ошибка, пожалуйста, сообщите об этом!</string> - <string name="msg_cr_error_keysize_512">Размер ключа должен быть больше или равен 512!</string> + <string name="msg_cr_error_keysize_2048">Размер ключа должен быть больше или равен 512!</string> <string name="msg_cr_error_no_curve">Не задан размер ключа! Это программная ошибка, пожалуйста, сообщите об этом!</string> <string name="msg_cr_error_no_keysize">Не задана эллиптическая кривая! Это программная ошибка, пожалуйста, сообщите об этом!</string> <string name="msg_cr_error_internal_pgp">Внутренняя ошибка OpenPGP!</string> diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml index ed7bce5f7..db31cd414 100644 --- a/OpenKeychain/src/main/res/values-sr/strings.xml +++ b/OpenKeychain/src/main/res/values-sr/strings.xml @@ -944,7 +944,7 @@ <string name="msg_cr_error_no_user_id">Привесци морају садржати бар један кориснички ИД!</string> <string name="msg_cr_error_no_certify">Главни кључ мора имати заставицу овере!</string> <string name="msg_cr_error_null_expiry">Датум истицања не може бити „исти као пре“ на стварању кључа. Ово је грешка у програмирању, поднесите извештај о грешци!</string> - <string name="msg_cr_error_keysize_512">Величина кључа мора бити већа или једнака 512!</string> + <string name="msg_cr_error_keysize_2048">Величина кључа мора бити већа или једнака 512!</string> <string name="msg_cr_error_no_curve">Није наведена величина кључа! Ово је грешка у програмирању, поднесите извештај о грешци!</string> <string name="msg_cr_error_no_keysize">Није наведена елиптичка крива! Ово је грешка у програмирању, поднесите извештај о грешци!</string> <string name="msg_cr_error_internal_pgp">Унутрашња ОпенПГП грешка!</string> diff --git a/OpenKeychain/src/main/res/values-sv/strings.xml b/OpenKeychain/src/main/res/values-sv/strings.xml index 4a0a9d083..2f4986df9 100644 --- a/OpenKeychain/src/main/res/values-sv/strings.xml +++ b/OpenKeychain/src/main/res/values-sv/strings.xml @@ -727,7 +727,7 @@ <string name="msg_cr">Genererar ny huvudnyckel</string> <string name="msg_cr_error_no_user_id">Nyckelringar måste skapas med minst ett användar-ID!</string> <string name="msg_cr_error_no_certify">Huvudnyckel måste ha en certifieringsflagga!</string> - <string name="msg_cr_error_keysize_512">Nyckelstorlek måste vara större eller lika med 512!</string> + <string name="msg_cr_error_keysize_2048">Nyckelstorlek måste vara större eller lika med 512!</string> <string name="msg_cr_error_internal_pgp">Internt OpenPGP-fel!</string> <string name="msg_cr_error_unknown_algo">Okänd algoritm vald. Detta är ett programmeringsfel, skicka en buggrapport!</string> <string name="msg_cr_error_flags_dsa">Dåliga nyckelflaggor valda, DSA kan inte användas för kryptering!</string> diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml index 6c0420c0b..3dc19b573 100644 --- a/OpenKeychain/src/main/res/values-uk/strings.xml +++ b/OpenKeychain/src/main/res/values-uk/strings.xml @@ -454,7 +454,7 @@ <string name="msg_cr">Генерується новий основний ключ</string> <string name="msg_cr_error_no_master">Не вказано параметрів основного ключа!</string> <string name="msg_cr_error_no_certify">Основний ключ повинен мати прапорець certify!</string> - <string name="msg_cr_error_keysize_512">Розмір ключа має бути більшим або рівним 512!</string> + <string name="msg_cr_error_keysize_2048">Розмір ключа має бути більшим або рівним 512!</string> <!--modifySecretKeyRing--> <string name="msg_mr">Змінюється в\'язка %s</string> <string name="msg_mf_error_encode">Виняток шифрування!</string> diff --git a/OpenKeychain/src/main/res/values/arrays.xml b/OpenKeychain/src/main/res/values/arrays.xml index 28b6fcd78..393a1e091 100644 --- a/OpenKeychain/src/main/res/values/arrays.xml +++ b/OpenKeychain/src/main/res/values/arrays.xml @@ -48,17 +48,15 @@ <item>@string/key_size_custom</item> </string-array> <string-array name="elgamal_key_size_spinner_values" translatable="false"> - <item>@string/key_size_1536</item> <item>@string/key_size_2048</item> <item>@string/key_size_3072</item> <item>@string/key_size_4096</item> <item>@string/key_size_8192</item> </string-array> <string-array name="dsa_key_size_spinner_values" translatable="false"> - <item>@string/key_size_512</item> - <item>@string/key_size_768</item> - <item>@string/key_size_1024</item> - <item>@string/key_size_custom</item> + <item>@string/key_size_2048</item> + <item>@string/key_size_3072</item> + <item>@string/key_size_4096</item> </string-array> <string-array name="theme_entries" translatable="false"> diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index bad91d9f9..8f86d5976 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -437,7 +437,6 @@ <string name="progress_decrypting">"decrypting data…"</string> <string name="progress_preparing_signature">"preparing signature…"</string> <string name="progress_generating_signature">"generating signature…"</string> - <string name="progress_processing_signature">"processing signature…"</string> <string name="progress_verifying_signature">"verifying signature…"</string> <string name="progress_signing">"signing…"</string> <string name="progress_certifying">"certifying…"</string> @@ -459,10 +458,6 @@ <string name="hint_cloud_search_hint">"Search via Name, Email…"</string> <!-- key bit length selections --> - <string name="key_size_512">"512"</string> - <string name="key_size_768">"768"</string> - <string name="key_size_1024">"1024"</string> - <string name="key_size_1536">"1536"</string> <string name="key_size_2048">"2048"</string> <string name="key_size_3072">"3072"</string> <string name="key_size_4096">"4096"</string> @@ -1030,7 +1025,7 @@ <string name="msg_cr_error_no_user_id">"Keyrings must be created with at least one user ID!"</string> <string name="msg_cr_error_no_certify">"Master key must have certify flag!"</string> <string name="msg_cr_error_null_expiry">"Expiry time cannot be 'same as before' on key creation. This is a programming error, please file a bug report!"</string> - <string name="msg_cr_error_keysize_512">"Key size must be greater or equal 512!"</string> + <string name="msg_cr_error_keysize_2048">"Key size must be greater or equal 2048!"</string> <string name="msg_cr_error_no_curve">"No key size specified! This is a programming error, please file a bug report!"</string> <string name="msg_cr_error_no_keysize">"No elliptic curve specified! This is a programming error, please file a bug report!"</string> <string name="msg_cr_error_internal_pgp">"Internal OpenPGP error!"</string> @@ -1179,6 +1174,7 @@ <string name="msg_dc_error_input">"Error opening input data stream!"</string> <string name="msg_dc_error_no_data">"No encrypted data found in stream!"</string> <string name="msg_dc_error_no_key">"No encrypted data with known secret key found in stream!"</string> + <string name="msg_dc_error_no_signature">"Missing signature data!"</string> <string name="msg_dc_error_pgp_exception">"Encountered OpenPGP Exception during operation!"</string> <string name="msg_dc_integrity_check_ok">"Integrity check OK!"</string> <string name="msg_dc_ok_meta_only">"Only metadata was requested, skipping decryption"</string> @@ -1202,8 +1198,9 @@ <!-- Messages for VerifySignedLiteralData operation --> <string name="msg_vl">"Starting signature check"</string> - <string name="msg_vl_error_no_siglist">"No signature list in signed literal data"</string> - <string name="msg_vl_error_wrong_key">"Message not signed with right key"</string> + <string name="msg_vl_error_no_siglist">"No signature list in signed literal data!"</string> + <string name="msg_vl_error_wrong_key">"Message not signed with expected key!"</string> + <string name="msg_vl_error_no_signature">"Missing signature data!"</string> <string name="msg_vl_error_missing_literal">"No payload in signed literal data"</string> <string name="msg_vl_clear_meta_file">"Filename: %s"</string> <string name="msg_vl_clear_meta_mime">"MIME type: %s"</string> @@ -1225,7 +1222,6 @@ <!-- Messages for PgpSignEncrypt operation --> <string name="msg_pse_asymmetric">"Preparing public keys for encryption"</string> - <string name="msg_pse_clearsign_only">"Signing of cleartext input not supported!"</string> <string name="msg_pse_compressing">"Preparing compression"</string> <string name="msg_pse_encrypting">"Encrypting data"</string> <string name="msg_pse_error_bad_passphrase">"Bad password!"</string> @@ -1660,4 +1656,9 @@ <string name="snack_backup_saved_dir">"Saved to OpenKeychain directory"</string> <string name="btn_backup_back">Go back to check</string> + <string name="share_log_dialog_title">"Share log?"</string> + <string name="share_log_dialog_message">"While logs can be super helpful for developers to find bugs in OpenKeychain, they can contain potential sensitive information such as data about the updated keys. Please make sure you are okay with sharing this information."</string> + <string name="share_log_dialog_share_button">"Share"</string> + <string name="share_log_dialog_cancel_button">"Cancel"</string> + </resources> |