aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-08-02 23:34:00 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-08-10 09:35:23 +0200
commit3d8eda6e3e3748e32e4c47a405cd8c6962e28a96 (patch)
tree9bd5ab479d0fc5b38cc3f921c39d98a0500a05e7 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java
parent7c40d89eeaf1d50b00a3c6a901894a1db64c0142 (diff)
downloadopen-keychain-3d8eda6e3e3748e32e4c47a405cd8c6962e28a96.tar.gz
open-keychain-3d8eda6e3e3748e32e4c47a405cd8c6962e28a96.tar.bz2
open-keychain-3d8eda6e3e3748e32e4c47a405cd8c6962e28a96.zip
Improve comments and reasons in PgpConstants, simple checks for insecure asymmetric keys
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java282
1 files changed, 282 insertions, 0 deletions
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 <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.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<Integer> 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<Integer> 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<String> 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;
+
+}