From 3d8eda6e3e3748e32e4c47a405cd8c6962e28a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 2 Aug 2015 23:34:00 +0200 Subject: Improve comments and reasons in PgpConstants, simple checks for insecure asymmetric keys --- .../operations/results/OperationResult.java | 7 +- .../keychain/pgp/CanonicalizedSecretKey.java | 3 +- .../pgp/OpenPgpDecryptionResultBuilder.java | 59 +++++ .../keychain/pgp/PgpConstants.java | 174 ------------- .../keychain/pgp/PgpDecryptVerify.java | 55 ++-- .../keychain/pgp/PgpKeyOperation.java | 36 +-- .../keychain/pgp/PgpSecurityConstants.java | 282 +++++++++++++++++++++ .../keychain/pgp/PgpSignEncryptInputParcel.java | 4 +- .../keychain/pgp/PgpSignEncryptOperation.java | 13 +- .../keychain/pgp/UncachedPublicKey.java | 9 +- .../keychain/provider/ProviderHelper.java | 6 +- .../keychain/remote/OpenPgpService.java | 12 +- .../keychain/ui/EncryptFilesFragment.java | 11 +- .../keychain/ui/EncryptTextFragment.java | 11 +- 14 files changed, 437 insertions(+), 245 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java (limited to 'OpenKeychain/src/main/java/org') 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 b063e1e74..d498bd9a1 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 @@ -611,14 +611,12 @@ public abstract class OperationResult implements Parcelable { MSG_DC_ERROR_CORRUPT_DATA (LogLevel.ERROR, R.string.msg_dc_error_corrupt_data), MSG_DC_ERROR_EXTRACT_KEY (LogLevel.ERROR, R.string.msg_dc_error_extract_key), MSG_DC_ERROR_INTEGRITY_CHECK (LogLevel.ERROR, R.string.msg_dc_error_integrity_check), - MSG_DC_ERROR_INTEGRITY_MISSING (LogLevel.ERROR, R.string.msg_dc_error_integrity_missing), MSG_DC_ERROR_INVALID_DATA (LogLevel.ERROR, R.string.msg_dc_error_invalid_data), MSG_DC_ERROR_IO (LogLevel.ERROR, R.string.msg_dc_error_io), 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_PGP_EXCEPTION (LogLevel.ERROR, R.string.msg_dc_error_pgp_exception), - MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO (LogLevel.ERROR, R.string.msg_dc_error_unsupported_hash_algo), 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), MSG_DC_OK (LogLevel.OK, R.string.msg_dc_ok), @@ -633,7 +631,10 @@ public abstract class OperationResult implements Parcelable { MSG_DC_TRAIL_SYM (LogLevel.DEBUG, R.string.msg_dc_trail_sym), MSG_DC_TRAIL_UNKNOWN (LogLevel.DEBUG, R.string.msg_dc_trail_unknown), MSG_DC_UNLOCKING (LogLevel.INFO, R.string.msg_dc_unlocking), - MSG_DC_OLD_SYMMETRIC_ENCRYPTION_ALGO (LogLevel.WARN, R.string.msg_dc_old_symmetric_encryption_algo), + MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO(LogLevel.WARN, R.string.msg_dc_insecure_symmetric_encryption_algo), + MSG_DC_INSECURE_HASH_ALGO(LogLevel.ERROR, R.string.msg_dc_insecure_hash_algo), + MSG_DC_INSECURE_MDC_MISSING(LogLevel.ERROR, R.string.msg_dc_insecure_mdc_missing), + MSG_DC_INSECURE_KEY(LogLevel.ERROR, R.string.msg_dc_insecure_key), // verify signed literal data MSG_VL (LogLevel.INFO, R.string.msg_vl), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 23f02ac08..7394c07c3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -43,7 +43,6 @@ import org.sufficientlysecure.keychain.util.Passphrase; import java.nio.ByteBuffer; import java.security.PrivateKey; import java.security.interfaces.RSAPrivateCrtKey; -import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -195,7 +194,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { public PGPSignatureGenerator getCertSignatureGenerator(Map signedHashes) { PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder( - PgpConstants.CERTIFY_HASH_ALGO, signedHashes); + PgpSecurityConstants.CERTIFY_HASH_ALGO, signedHashes); if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { throw new PrivateKeyNotUnlockedException(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java new file mode 100644 index 000000000..c4525e5cd --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.pgp; + +import org.openintents.openpgp.OpenPgpDecryptionResult; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; + +public class OpenPgpDecryptionResultBuilder { + + // builder + private boolean mInsecure = false; + private boolean mEncrypted = false; + + public void setInsecure(boolean insecure) { + this.mInsecure = insecure; + } + + public void setEncrypted(boolean encrypted) { + this.mEncrypted = encrypted; + } + + public OpenPgpDecryptionResult build() { + OpenPgpDecryptionResult result = new OpenPgpDecryptionResult(); + + if (mInsecure) { + Log.d(Constants.TAG, "RESULT_INSECURE"); + result.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); + return result; + } + + if (mEncrypted) { + Log.d(Constants.TAG, "RESULT_ENCRYPTED"); + result.setResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED); + } else { + Log.d(Constants.TAG, "RESULT_NOT_ENCRYPTED"); + result.setResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED); + } + + return result; + } + + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java deleted file mode 100644 index 7162a3366..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConstants.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; - -import java.util.HashSet; - -/** - * NIST requirements for 2011-2030 (http://www.keylength.com/en/4/): - * - RSA: 2048 bit - * - ECC: 224 bit - * - Symmetric: 3TDEA - * - Digital Signature (hash A): SHA-224 - SHA-512 - * - * Many decisions are based on https://gist.github.com/coruus/68a8c65571e2b4225a69 - */ -public class PgpConstants { - -// public interface MIN_REQUIREMENT { -// int MIN_BITS; -// int BINDING_SIGNATURE_HASH_ALGO; // for User IDs, subkeys,... -// int SYMMETRIC_ALGO; -// } - // https://tools.ietf.org/html/rfc6637#section-13 - - /* - PgpDecryptVerify: Secure Algorithms Whitelist - all other algorithms will be rejected with OpenPgpDecryptionResult.RESULT_INSECURE - - No broken ciphers or ciphers with key length smaller than 128 bit are allowed! - */ - public static HashSet sSymmetricAlgorithmsWhitelist = new HashSet<>(); - static { - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_256); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_192); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_128); - sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); // 128 bit - } - - // all other algorithms will be rejected with OpenPgpSignatureResult.RESULT_INVALID_INSECURE - public static HashSet sHashAlgorithmsWhitelist = new HashSet<>(); - static { - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA512); - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA384); - /* - TODO: SHA256 and SHA224 are still allowed even though - coruus advises against it, to enable better backward compatibility - - coruus: - Implementations MUST NOT sign SHA-224 hashes. They SHOULD NOT accept signatures over SHA-224 hashes. - ((collision resistance of 112-bits)) - Implementations SHOULD NOT sign SHA-256 hashes. They MUST NOT default to signing SHA-256 hashes. - */ - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); - sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA224); - } - - /* - * Most preferred is first - * These arrays are written as preferred algorithms into the keys on creation. - * Other implementations may choose to honor this selection. - */ - public static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ - SymmetricKeyAlgorithmTags.AES_256, - SymmetricKeyAlgorithmTags.AES_192, - SymmetricKeyAlgorithmTags.AES_128, - }; - - /* - coorus: - Implementations SHOULD use SHA-512 for RSA or DSA signatures. They SHOULD NOT use SHA-384. - ((cite to affine padding attacks; unproven status of RSA-PKCSv15)) - */ - public static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{ - HashAlgorithmTags.SHA512, - }; - - /* - * Prefer ZIP - * "ZLIB provides no benefit over ZIP and is more malleable" - * - (OpenPGP WG mailinglist: "[openpgp] Intent to deprecate: Insecure primitives") - * BZIP2: very slow - */ - public static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ - CompressionAlgorithmTags.ZIP, - }; - - public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA512; - - - /* - Always use AES-256! Ignore the preferred encryption algos of the recipient! - - coorus: - Implementations SHOULD ignore the symmetric algorithm preferences of a recipient's public key; - in particular, implementations MUST NOT choose an algorithm forbidden by this - document because a recipient prefers it. - - NEEDCITE downgrade attacks on TLS, other protocols - */ - public static final int DEFAULT_SYMMETRIC_ALGORITHM = SymmetricKeyAlgorithmTags.AES_256; - public interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { - int USE_DEFAULT = -1; - } - - /* - Always use SHA-512! Ignore the preferred hash algos of the recipient! - - coorus: - Implementations MUST ignore the hash algorithm preferences of a recipient when signing - a message to a recipient. The difficulty of forging a signature under a given key, - using generic attacks on hash functions, is the difficulty of the weakest hash signed by that key. - - Implementations MUST default to using SHA-512 for RSA signatures, - - and either SHA-512 or the matched instance of SHA-2 for ECDSA signatures. - TODO: Ed25519 - CITE: zooko's hash function table CITE: distinguishers on SHA-256 - */ - public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA512; - public interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { - int USE_DEFAULT = -1; - } - - public static final int DEFAULT_COMPRESSION_ALGORITHM = CompressionAlgorithmTags.ZIP; - public interface OpenKeychainCompressionAlgorithmTags extends CompressionAlgorithmTags { - int USE_DEFAULT = -1; - } - - /* - * Note: s2kcount is a number between 0 and 0xff that controls the - * number of times to iterate the password hash before use. More - * iterations are useful against offline attacks, as it takes more - * time to check each password. The actual number of iterations is - * rather complex, and also depends on the hash function in use. - * Refer to Section 3.7.1.3 in rfc4880.txt. Bigger numbers give - * you more iterations. As a rough rule of thumb, when using - * SHA256 as the hashing function, 0x10 gives you about 64 - * iterations, 0x20 about 128, 0x30 about 256 and so on till 0xf0, - * or about 1 million iterations. The maximum you can go to is - * 0xff, or about 2 million iterations. - * from http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html - * - * Bouncy Castle default: 0x60 - * kbsriram proposes: 0xc0 - * OpenKeychain: 0x90 - */ - public static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x90; - public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512; - public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256; - public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA512; - // NOTE: only SHA1 is supported for key checksum calculations in OpenPGP, - // see http://tools.ietf.org/html/rfc488 0#section-5.5.3 - public static final int SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO = HashAlgorithmTags.SHA1; - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index d40bad3aa..1e51403fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -321,7 +321,7 @@ public class PgpDecryptVerify extends BaseOperation InputStream in, OutputStream out, int indent) throws IOException, PGPException { OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - OpenPgpDecryptionResult decryptionResult = new OpenPgpDecryptionResult(); + OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder(); OperationLog log = new OperationLog(); log.add(LogType.MSG_DC, indent); @@ -464,6 +464,12 @@ public class PgpDecryptVerify extends BaseOperation } } + // check for insecure encryption key + if ( ! PgpSecurityConstants.isSecureKey(secretEncryptionKey)) { + log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1); + decryptionResultBuilder.setInsecure(true); + } + // break out of while, only decrypt the first packet where we have a key break; @@ -614,12 +620,12 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED); + decryptionResultBuilder.setEncrypted(true); // Check for insecure encryption algorithms! - if (!PgpConstants.sSymmetricAlgorithmsWhitelist.contains(symmetricEncryptionAlgo)) { - log.add(LogType.MSG_DC_OLD_SYMMETRIC_ENCRYPTION_ALGO, indent + 1); - decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); + if (!PgpSecurityConstants.isSecureSymmetricAlgorithm(symmetricEncryptionAlgo)) { + log.add(LogType.MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO, indent + 1); + decryptionResultBuilder.setInsecure(true); } JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); @@ -687,6 +693,13 @@ public class PgpDecryptVerify extends BaseOperation } } + // 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); + } + dataChunk = plainFact.nextObject(); } @@ -821,8 +834,8 @@ public class PgpDecryptVerify extends BaseOperation } // check for insecure hash algorithms - if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); signatureResultBuilder.setInsecure(true); } @@ -850,8 +863,8 @@ public class PgpDecryptVerify extends BaseOperation // The MDC packet can be stripped by an attacker! Log.d(Constants.TAG, "MDC fail"); if (!signatureResultBuilder.isValidSignature()) { - log.add(LogType.MSG_DC_ERROR_INTEGRITY_MISSING, indent); - decryptionResult.setResult(OpenPgpDecryptionResult.RESULT_INSECURE); + log.add(LogType.MSG_DC_INSECURE_MDC_MISSING, indent); + decryptionResultBuilder.setInsecure(true); } } @@ -864,7 +877,7 @@ public class PgpDecryptVerify extends BaseOperation result.setCachedCryptoInputParcel(cryptoInput); result.setSignatureResult(signatureResultBuilder.build()); result.setCharset(charset); - result.setDecryptionResult(decryptionResult); + result.setDecryptionResult(decryptionResultBuilder.build()); result.setDecryptionMetadata(metadata); return result; @@ -921,7 +934,7 @@ public class PgpDecryptVerify extends BaseOperation return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent); if (signature != null) { try { @@ -954,8 +967,8 @@ public class PgpDecryptVerify extends BaseOperation } // check for insecure hash algorithms - if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); signatureResultBuilder.setInsecure(true); } @@ -1013,7 +1026,7 @@ public class PgpDecryptVerify extends BaseOperation return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent); if (signature != null) { updateProgress(R.string.progress_reading_data, 60, 100); @@ -1056,8 +1069,8 @@ public class PgpDecryptVerify extends BaseOperation } // check for insecure hash algorithms - if (!PgpConstants.sHashAlgorithmsWhitelist.contains(signature.getHashAlgorithm())) { - log.add(LogType.MSG_DC_ERROR_UNSUPPORTED_HASH_ALGO, indent + 1); + if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) { + log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1); signatureResultBuilder.setInsecure(true); } @@ -1076,7 +1089,8 @@ public class PgpDecryptVerify extends BaseOperation } private PGPSignature processPGPSignatureList( - PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder) + PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder, + OperationLog log, int indent) throws PGPException { CanonicalizedPublicKeyRing signingRing = null; CanonicalizedPublicKey signingKey = null; @@ -1118,6 +1132,13 @@ public class PgpDecryptVerify extends BaseOperation } } + // 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; } 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 a7eead939..6f156c201 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -316,14 +316,14 @@ public class PgpKeyOperation { // Build key encrypter and decrypter based on passphrase PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, - encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, + encryptorHashCalc, PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray()); PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), sha1Calc, true, keyEncryptor); @@ -1021,15 +1021,15 @@ public class PgpKeyOperation { PGPSecretKey sKey; { // Build key encrypter and decrypter based on passphrase PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, - PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( cryptoInput.getPassphrase().getCharArray()); PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() - .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); + .build().get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor); } @@ -1206,7 +1206,7 @@ public class PgpKeyOperation { // add packet with EMPTY notation data (updates old one, but will be stripped later) PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPrivateKey.getPublicKeyPacket().getAlgorithm(), - PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) + PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); { // set subpackets @@ -1233,7 +1233,7 @@ public class PgpKeyOperation { // add packet with "pin" notation data PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPrivateKey.getPublicKeyPacket().getAlgorithm(), - PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) + PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); { // set subpackets @@ -1280,13 +1280,13 @@ public class PgpKeyOperation { OperationLog log, int indent) throws PGPException { PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build() - .get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); + .get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); // Build key encryptor based on new passphrase PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder( - PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, - PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, + PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(newPassphrase.getCharArray()); // noinspection unchecked @@ -1440,13 +1440,13 @@ public class PgpKeyOperation { if (divertToCard) { // use synchronous "NFC based" SignerBuilder builder = new NfcSyncPGPContentSignerBuilder( - pKey.getAlgorithm(), PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO, + pKey.getAlgorithm(), PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO, pKey.getKeyID(), cryptoInput.getCryptoData()) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); } else { // content signer based on signing key algorithm and chosen hash algorithm builder = new JcaPGPContentSignerBuilder( - pKey.getAlgorithm(), PgpConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) + pKey.getAlgorithm(), PgpSecurityConstants.SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); } @@ -1472,11 +1472,11 @@ public class PgpKeyOperation { */ /* non-critical subpackets: */ hashedPacketsGen.setPreferredSymmetricAlgorithms(false, - PgpConstants.PREFERRED_SYMMETRIC_ALGORITHMS); + PgpSecurityConstants.PREFERRED_SYMMETRIC_ALGORITHMS); hashedPacketsGen.setPreferredHashAlgorithms(false, - PgpConstants.PREFERRED_HASH_ALGORITHMS); + PgpSecurityConstants.PREFERRED_HASH_ALGORITHMS); hashedPacketsGen.setPreferredCompressionAlgorithms(false, - PgpConstants.PREFERRED_COMPRESSION_ALGORITHMS); + PgpSecurityConstants.PREFERRED_COMPRESSION_ALGORITHMS); hashedPacketsGen.setPrimaryUserID(false, primary); /* critical subpackets: we consider those important for a modern pgp implementation */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java new file mode 100644 index 000000000..8762cde00 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.asn1.nist.NISTNamedCurves; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; + +import java.util.HashSet; + +/** + * NIST requirements for 2011-2030 (http://www.keylength.com/en/4/): + * - RSA: 2048 bit + * - ECC: 224 bit + * - Symmetric: 3TDEA + * - Digital Signature (hash A): SHA-224 - SHA-512 + * + * Extreme Decisions for Yahoo's End-to-End: + * https://github.com/yahoo/end-to-end/issues/31 + * https://gist.github.com/coruus/68a8c65571e2b4225a69 + */ +public class PgpSecurityConstants { + + /* + * TODO: + * 1. Check binding signatures for requirements on import! throw out binding signatures with insecure + * signatures (bit length, hash algo) + * + * - put checks for curve OIDs and algorithm tags into import instead of PgpDecryptVerify? + * - check signingRing in PgpDecryptVerify? + * - ECC checks https://tools.ietf.org/html/rfc6637#section-13 + * - check encryption algo used for encrypting secret keys? + * - check S2K security? + * - check for min rsa/dsa/elgamal/ecc requirements in key creation backend + */ + + /** + * Whitelist of accepted symmetric encryption algorithms + * all other algorithms are rejected with OpenPgpDecryptionResult.RESULT_INSECURE + */ + private static HashSet sSymmetricAlgorithmsWhitelist = new HashSet<>(); + static { + // General remarks: We try to keep the whitelist short to reduce attack surface + // TODO: block IDEA?: Bad key schedule (weak keys), implementation difficulties (easy to make errors) + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.IDEA); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TRIPLE_DES); // a MUST in RFC + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.CAST5); // default in many gpg, pgp versions, 128 bit key + // BLOWFISH: Twofish is the successor + // SAFER: not used widely + // DES: < 128 bit security + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_128); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_192); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.AES_256); + sSymmetricAlgorithmsWhitelist.add(SymmetricKeyAlgorithmTags.TWOFISH); // 128 bit + // CAMELLIA_128: not used widely + // CAMELLIA_192: not used widely + // CAMELLIA_256: not used widely + } + + public static boolean isSecureSymmetricAlgorithm(int id) { + return sSymmetricAlgorithmsWhitelist.contains(id); + } + + /** + * Whitelist of accepted hash algorithms + * all other algorithms are rejected with OpenPgpSignatureResult.RESULT_INSECURE + * + * coorus: + * Implementations SHOULD use SHA-512 for RSA or DSA signatures. They SHOULD NOT use SHA-384. + * ((cite to affine padding attacks; unproven status of RSA-PKCSv15)) + * + * Implementations MUST NOT sign SHA-224 hashes. They SHOULD NOT accept signatures over SHA-224 hashes. + * ((collision resistance of 112-bits)) + * Implementations SHOULD NOT sign SHA-256 hashes. They MUST NOT default to signing SHA-256 hashes. + */ + private static HashSet sHashAlgorithmsWhitelist = new HashSet<>(); + static { + // MD5: broken + // SHA1: broken + // RIPEMD160: same security properties as SHA1 + // DOUBLE_SHA: not used widely + // MD2: not used widely + // TIGER_192: not used widely + // HAVAL_5_160: not used widely + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA256); // compatibility for old Mailvelope versions + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA384); + sHashAlgorithmsWhitelist.add(HashAlgorithmTags.SHA512); + // SHA224: Not used widely, Yahoo argues against it + } + + public static boolean isSecureHashAlgorithm(int id) { + return sHashAlgorithmsWhitelist.contains(id); + } + + /** + * Whitelist of accepted asymmetric algorithms in switch statement + * all other algorithms are rejected with OpenPgpSignatureResult.RESULT_INSECURE or + * OpenPgpDecryptionResult.RESULT_INSECURE + * + * REASON: + * Don't allow ELGAMAL_GENERAL (20), reason in RFC + * + * coorus: + * Implementations MUST NOT accept, or treat any signature as valid, by an RSA key with + * bitlength less than 1023 bits. + * Implementations MUST NOT accept any RSA keys with bitlength less than 2047 bits after January 1, 2016. + */ + private static HashSet sCurveWhitelist = new HashSet<>(); + static { + sCurveWhitelist.add(NISTNamedCurves.getOID("P-256").getId()); + sCurveWhitelist.add(NISTNamedCurves.getOID("P-384").getId()); + sCurveWhitelist.add(NISTNamedCurves.getOID("P-521").getId()); + } + + public static boolean isSecureKey(CanonicalizedPublicKey key) { + switch (key.getAlgorithm()) { + case PublicKeyAlgorithmTags.RSA_GENERAL: + case PublicKeyAlgorithmTags.RSA_ENCRYPT: + case PublicKeyAlgorithmTags.RSA_SIGN: { + return (key.getBitStrength() >= 2048); + } + + case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: { + return (key.getBitStrength() >= 2048); + } + + case PublicKeyAlgorithmTags.DSA: { + return (key.getBitStrength() >= 2048); + } + + case PublicKeyAlgorithmTags.ECDH: + case PublicKeyAlgorithmTags.ECDSA: { + return PgpSecurityConstants.sCurveWhitelist.contains(key.getCurveOid()); + } + // ELGAMAL_GENERAL: Must not be used, use ELGAMAL_ENCRYPT + // DIFFIE_HELLMAN: unsure + default: + return false; + } + } + + /** + * These array is written as a list of preferred encryption algorithms into keys created by us. + * Other implementations may choose to honor this selection. + * (Most preferred is first) + * + * REASON: See corresponding whitelist. AES received most cryptanalysis over the years + * and is still secure! + */ + public static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ + SymmetricKeyAlgorithmTags.AES_256, + SymmetricKeyAlgorithmTags.AES_192, + SymmetricKeyAlgorithmTags.AES_128, + }; + + /** + * These array is written as a list of preferred hash algorithms into keys created by us. + * Other implementations may choose to honor this selection. + * (Most preferred is first) + * + * REASON: See corresponding whitelist. If possible use SHA-512, this is state of the art! + */ + public static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{ + HashAlgorithmTags.SHA512, + }; + + /** + * These array is written as a list of preferred compression algorithms into keys created by us. + * Other implementations may choose to honor this selection. + * (Most preferred is first) + * + * REASON: See DEFAULT_COMPRESSION_ALGORITHM + */ + public static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ + CompressionAlgorithmTags.ZIP, + }; + + /** + * Hash algorithm used to certify public keys + */ + public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA512; + + + /** + * Always use AES-256! We always ignore the preferred encryption algos of the recipient! + * + * coorus: + * Implementations SHOULD ignore the symmetric algorithm preferences of a recipient's public key; + * in particular, implementations MUST NOT choose an algorithm forbidden by this + * document because a recipient prefers it. + * + * NEEDCITE downgrade attacks on TLS, other protocols + */ + public static final int DEFAULT_SYMMETRIC_ALGORITHM = SymmetricKeyAlgorithmTags.AES_256; + + public interface OpenKeychainSymmetricKeyAlgorithmTags extends SymmetricKeyAlgorithmTags { + int USE_DEFAULT = -1; + } + + /** + * Always use SHA-512! We always ignore the preferred hash algos of the recipient! + * + * coorus: + * Implementations MUST ignore the hash algorithm preferences of a recipient when signing + * a message to a recipient. The difficulty of forging a signature under a given key, + * using generic attacks on hash functions, is the difficulty of the weakest hash signed by that key. + * + * Implementations MUST default to using SHA-512 for RSA signatures, + * + * and either SHA-512 or the matched instance of SHA-2 for ECDSA signatures. + * TODO: Ed25519 + * CITE: zooko's hash function table CITE: distinguishers on SHA-256 + */ + public static final int DEFAULT_HASH_ALGORITHM = HashAlgorithmTags.SHA512; + + public interface OpenKeychainHashAlgorithmTags extends HashAlgorithmTags { + int USE_DEFAULT = -1; + } + + /** + * Compression is disabled by default. + * + * The default compression algorithm is only used if explicitly enabled in the activity's + * overflow menu or via the OpenPGP API's extra OpenPgpApi.EXTRA_ENABLE_COMPRESSION + * + * REASON: Enabling compression can lead to a sidechannel. Consider a voting that is done via + * OpenPGP. Compression can lead to different ciphertext lengths based on the user's voting. + * This has happened in a voting done by Wikipedia (Google it). + * + * ZLIB: the format provides no benefits over DEFLATE, and is more malleable + * BZIP2: very slow + */ + public static final int DEFAULT_COMPRESSION_ALGORITHM = CompressionAlgorithmTags.ZIP; + + public interface OpenKeychainCompressionAlgorithmTags extends CompressionAlgorithmTags { + int USE_DEFAULT = -1; + } + + /** + * Note: s2kcount is a number between 0 and 0xff that controls the + * number of times to iterate the password hash before use. More + * iterations are useful against offline attacks, as it takes more + * time to check each password. The actual number of iterations is + * rather complex, and also depends on the hash function in use. + * Refer to Section 3.7.1.3 in rfc4880.txt. Bigger numbers give + * you more iterations. As a rough rule of thumb, when using + * SHA256 as the hashing function, 0x10 gives you about 64 + * iterations, 0x20 about 128, 0x30 about 256 and so on till 0xf0, + * or about 1 million iterations. The maximum you can go to is + * 0xff, or about 2 million iterations. + * from http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html + * + * Bouncy Castle default: 0x60 + * kbsriram proposes: 0xc0 + * Yahoo's End-to-End: 96 (65536 iterations) (https://github.com/yahoo/end-to-end/blob/master/src/javascript/crypto/e2e/openpgp/keyring.js) + */ + public static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 96; + public static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512; + public static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256; + public static final int SECRET_KEY_BINDING_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA512; + // NOTE: only SHA1 is supported for key checksum calculations in OpenPGP, + // see http://tools.ietf.org/html/rfc488 0#section-5.5.3 + public static final int SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO = HashAlgorithmTags.SHA1; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index 44e4b9221..7ae3f50aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -33,10 +33,10 @@ public class PgpSignEncryptInputParcel implements Parcelable { protected int mCompressionAlgorithm = CompressionAlgorithmTags.UNCOMPRESSED; protected long[] mEncryptionMasterKeyIds = null; protected Passphrase mSymmetricPassphrase = null; - protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; + protected int mSymmetricEncryptionAlgorithm = PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; protected long mSignatureMasterKeyId = Constants.key.none; protected Long mSignatureSubKeyId = null; - protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; + protected int mSignatureHashAlgorithm = PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; protected long mAdditionalEncryptId = Constants.key.none; protected boolean mFailOnMissingEncryptionKeyIds = false; protected String mCharset; 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 8701c27dc..1798baa8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -62,7 +62,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.SignatureException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Set; @@ -228,8 +227,8 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use requested hash algo int requestedAlgorithm = input.getSignatureHashAlgorithm(); - if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { - input.setSignatureHashAlgorithm(PgpConstants.DEFAULT_HASH_ALGORITHM); + if (requestedAlgorithm == PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { + input.setSignatureHashAlgorithm(PgpSecurityConstants.DEFAULT_HASH_ALGORITHM); } } updateProgress(R.string.progress_preparing_streams, 2, 100); @@ -240,8 +239,8 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use requested encryption algo int algo = input.getSymmetricEncryptionAlgorithm(); - if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { - algo = PgpConstants.DEFAULT_SYMMETRIC_ALGORITHM; + if (algo == PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { + algo = PgpSecurityConstants.DEFAULT_SYMMETRIC_ALGORITHM; } // has Integrity packet enabled! JcePGPDataEncryptorBuilder encryptorBuilder = @@ -337,8 +336,8 @@ public class PgpSignEncryptOperation extends BaseOperation { // Use preferred compression algo int algo = input.getCompressionAlgorithm(); - if (algo == PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { - algo = PgpConstants.DEFAULT_COMPRESSION_ALGORITHM; + if (algo == PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { + algo = PgpSecurityConstants.DEFAULT_COMPRESSION_ALGORITHM; } compressGen = new PGPCompressedDataGenerator(algo); bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 9276cba10..26f046372 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -211,12 +211,19 @@ public class UncachedPublicKey { return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; } + public boolean isRSA() { + return getAlgorithm() == PGPPublicKey.RSA_GENERAL + || getAlgorithm() == PGPPublicKey.RSA_ENCRYPT + || getAlgorithm() == PGPPublicKey.RSA_SIGN; + } + public boolean isDSA() { return getAlgorithm() == PGPPublicKey.DSA; } public boolean isEC() { - return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA; + return getAlgorithm() == PGPPublicKey.ECDH + || getAlgorithm() == PGPPublicKey.ECDSA; } public byte[] getFingerprint() { 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 9abdbf8be..0c37bfc2a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -45,7 +45,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; @@ -1434,9 +1434,9 @@ public class ProviderHelper { // DEPRECATED and thus hardcoded values.put(KeychainContract.ApiAccounts.COMPRESSION, CompressionAlgorithmTags.ZLIB); values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, - PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); return values; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 10a7e1a88..e1d7c0bc9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; @@ -248,7 +248,7 @@ public class OpenPgpService extends RemoteService { .setCleartextSignature(cleartextSign) .setDetachedSignature(!cleartextSign) .setVersionHeader(null) - .setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); + .setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); Intent signKeyIdIntent = getSignKeyMasterId(data); // NOTE: Fallback to return account settings (Old API) @@ -359,9 +359,9 @@ public class OpenPgpService extends RemoteService { boolean enableCompression = data.getBooleanExtra(OpenPgpApi.EXTRA_ENABLE_COMPRESSION, true); int compressionId; if (enableCompression) { - compressionId = PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT; + compressionId = PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT; } else { - compressionId = PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED; + compressionId = PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED; } // first try to get key ids from non-ambiguous key id extra @@ -392,7 +392,7 @@ public class OpenPgpService extends RemoteService { pseInput.setEnableAsciiArmorOutput(asciiArmor) .setVersionHeader(null) .setCompressionAlgorithm(compressionId) - .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) + .setSymmetricEncryptionAlgorithm(PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) .setEncryptionMasterKeyIds(keyIds) .setFailOnMissingEncryptionKeyIds(true); @@ -421,7 +421,7 @@ public class OpenPgpService extends RemoteService { } // sign and encrypt - pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) + pseInput.setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) .setAdditionalEncryptId(signKeyId); // add sign key for encryption } 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 7bf662da3..63d37f296 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -50,12 +50,11 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -554,17 +553,17 @@ public class EncryptFilesFragment if (mUseCompression) { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); } else { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); } data.setHiddenRecipients(mHiddenRecipients); data.setEnableAsciiArmorOutput(mAfterEncryptAction == AfterEncryptAction.COPY || mUseArmor); data.setSymmetricEncryptionAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); data.setSignatureHashAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); EncryptActivity encryptActivity = (EncryptActivity) getActivity(); EncryptModeFragment modeFragment = encryptActivity.getModeFragment(); 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 60a2c9905..ab676285e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -33,12 +33,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; @@ -224,16 +223,16 @@ public class EncryptTextFragment if (mUseCompression) { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT); } else { data.setCompressionAlgorithm( - PgpConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); + PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED); } data.setHiddenRecipients(mHiddenRecipients); data.setSymmetricEncryptionAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); data.setSignatureHashAlgorithm( - PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); + PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT); // Always use armor for messages data.setEnableAsciiArmorOutput(true); -- cgit v1.2.3