]> WPIA git - gigi.git/commitdiff
add: public key check searching for small primes (less than 10k)
authorBenny Baumann <BenBE1987@gmx.net>
Wed, 18 Oct 2017 23:28:46 +0000 (01:28 +0200)
committerBenny Baumann <BenBE1987@gmx.net>
Wed, 1 Nov 2017 23:43:11 +0000 (00:43 +0100)
Change-Id: If8bc26381bb2e8f4f267cfd211f1154bcb3a7d65

src/club/wpia/gigi/crypto/key/KeyCheck.java
src/club/wpia/gigi/crypto/key/KeyCheckSmallFactors.java [new file with mode: 0644]
tests/club/wpia/gigi/crypto/key/KeyCheckSmallFactorsTest.java [new file with mode: 0644]
tests/club/wpia/gigi/crypto/key/KeyCheckTest.java

index 7c1ed82bf026a87160f5f8bf72e30cb06b5b7ff3..d95ad514364c52be9ef26910bf89290cf59c0923 100644 (file)
@@ -24,8 +24,9 @@ public abstract class KeyCheck {
 
     public static void checkKey(PublicKey key) throws GigiApiException {
 
-        if (checks.isEmpty()) {
+        if (checks.isEmpty() || checks.size() < 1) {
             // Mandatory checks are registered here
+            register(new KeyCheckSmallFactors());
         }
 
         if (key == null) {
diff --git a/src/club/wpia/gigi/crypto/key/KeyCheckSmallFactors.java b/src/club/wpia/gigi/crypto/key/KeyCheckSmallFactors.java
new file mode 100644 (file)
index 0000000..a096534
--- /dev/null
@@ -0,0 +1,52 @@
+package club.wpia.gigi.crypto.key;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.output.template.SprintfCommand;
+
+public class KeyCheckSmallFactors extends KeyCheck {
+
+    private static final long MAX_CHECKED_SMALL_PRIME_BOUNDARY = 10000;
+
+    private static final BigInteger[] primes;
+
+    static {
+        ArrayList<BigInteger> prims = new ArrayList<>(1024);
+
+        NextPrime:
+        for (long i = 2; i < MAX_CHECKED_SMALL_PRIME_BOUNDARY; i++) {
+            for (BigInteger p : prims) {
+                if (BigInteger.ZERO.equals(BigInteger.valueOf(i).mod(p))) {
+                    continue NextPrime;
+                }
+            }
+
+            prims.add(BigInteger.valueOf(i));
+        }
+
+        primes = prims.toArray(new BigInteger[0]);
+
+        register(new KeyCheckSmallFactors());
+    }
+
+    @Override
+    public void check(PublicKey key) throws GigiApiException {
+        if ( !(key instanceof RSAPublicKey)) {
+            return;
+        }
+
+        BigInteger modulus = ((RSAPublicKey) key).getModulus();
+
+        // Check for small prime factors below 10000
+        for (BigInteger n : primes) {
+            if (BigInteger.ZERO.equals(modulus.mod(n))) {
+                throw new GigiApiException(SprintfCommand.createSimple("Small factors check of public key: Key is divisible by {0}.", n.toString()));
+            }
+        }
+    }
+
+}
diff --git a/tests/club/wpia/gigi/crypto/key/KeyCheckSmallFactorsTest.java b/tests/club/wpia/gigi/crypto/key/KeyCheckSmallFactorsTest.java
new file mode 100644 (file)
index 0000000..2d5e4cb
--- /dev/null
@@ -0,0 +1,67 @@
+package club.wpia.gigi.crypto.key;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+
+import org.junit.Test;
+
+import club.wpia.gigi.GigiApiException;
+
+public class KeyCheckSmallFactorsTest {
+
+    @Test
+    public void testSmallPrimesSaneKey() throws GeneralSecurityException, IOException {
+
+        // Normal public key generated with OpenSSL:
+        // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048
+        // -pkeyopt rsa_keygen_pubexp:7331 2>/dev/null |
+        // openssl pkey -pubout -outform pem
+        String sfk = "-----BEGIN PUBLIC KEY-----\n" + //
+                "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQEArcAPmy3RnXdwyFg3V9k1\n" + //
+                "RaFR/peHa3hLsmh25BInRVArbaMctSBaJBVZwQIgBdqjyITQQZP38i6k+WdsETn9\n" + //
+                "J491UDLKU3E3UG60ZS3BzcJllNdpn4g0IZROxmmUz2JlAXkGtIglmWWDx14qHSNj\n" + //
+                "ON58mc3ihfn/oWkPk2hk/csDxGQq5jSaBUwa9THBg9UQHHBqQbhp2nGfa5a5VRlI\n" + //
+                "0QeIy+8GmKlXYMchReUI25ksLOzaqETD0UXiAPyt+vpvkKCDjWGc3kjabn6OkuTt\n" + //
+                "na7N/52qrEC2ImuanYlzR5gv9jkbFF2PiMIEBD+3B0842rLx0X/lbXhRr1MtuHtN\n" + //
+                "tQICHKM=\n" + //
+                "-----END PUBLIC KEY-----\n";
+
+        PublicKey pk = KeyCheckTest.pkFromString(sfk);
+        try {
+            KeyCheck c = new KeyCheckSmallFactors();
+            c.check(pk);
+        } catch (GigiApiException gae) {
+            throw new Error("Valid key (regarding small factors) rejected.", gae);
+        }
+
+    }
+
+    @Test
+    public void testSmallPrimes() throws GeneralSecurityException, IOException {
+
+        // The following key is the above one multiplied by 7331.
+        String sfk = "-----BEGIN PUBLIC KEY-----\n" + //
+                "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQITb6L+6NEZsFNiuTY42LEg\n" + //
+                "iPqvDa1K+pXftgWEpTPalebLpKX/Ft11V09pQh/bB6QgNzNXxfBVXE2+UhyrsU+c\n" + //
+                "g+Esd55384MjBFI37W1U50Xi9VS1s3ls3ZoL2+GAbs6yeSzLA9bMt8YMtj2QAGxi\n" + //
+                "ZYtKKHLd4qYja0OZCkaED8ys4QB4flRWpbJn+4/Yoj5sXmcy2AP/SoPIRf09T/MQ\n" + //
+                "OerCZ/3p5blhOGZt1I3MqJNcCoK5oKkzkeQ3AkPqOjGo2qSXObJPMYBHKjIs2JHA\n" + //
+                "ioTVHwAOgsEfu69srVcgOzsleAVSeDNFWUv5BayWVlGpHtJi4mGHDdyLL7r2SfMC\n" + //
+                "Rj8CAhyj\n" + //
+                "-----END PUBLIC KEY-----\n";
+
+        PublicKey pk = KeyCheckTest.pkFromString(sfk);
+        try {
+            KeyCheck c = new KeyCheckSmallFactors();
+            c.check(pk);
+            fail("Invalid key (containing small factors) accepted.");
+        } catch (GigiApiException gae) {
+            // expected
+        }
+
+    }
+
+}
index 203e830a350ebd72aa9119836bc88cee81d497a1..aaca8b87cd7b2b247133be0c2d41b88dc701a366 100644 (file)
@@ -29,8 +29,11 @@ public class KeyCheckTest {
             KeyCheck.checkKey(null);
             fail("Providing a null key should fail!");
         } catch (GigiApiException gae) {
-            assertTrue(true);
+            // Expected failure
         }
+
+        // Check that at least one key check has been loaded
+        assertFalse(KeyCheck.getChecks().isEmpty());
     }
 
 }