Search in sources :

Example 1 with SlowTest

use of com.google.security.wycheproof.WycheproofRunner.SlowTest in project wycheproof by google.

the class DhTest method testKeyPair.

@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE })
public void testKeyPair(KeyPair keyPair, int expectedKeySize) throws Exception {
    DHPrivateKey priv = (DHPrivateKey) keyPair.getPrivate();
    BigInteger p = priv.getParams().getP();
    BigInteger g = priv.getParams().getG();
    int keySize = p.bitLength();
    assertEquals("wrong key size", keySize, expectedKeySize);
    // Checks the key size of the private key.
    // NIST SP 800-56A requires that x is in the range (1, q-1).
    // Such a choice would require a full key validation. Since such a validation
    // requires the value q (which is not present in the DH parameters) larger keys
    // should be chosen to prevent attacks.
    int minPrivateKeyBits = keySize / 2;
    BigInteger x = priv.getX();
    assertTrue(x.bitLength() >= minPrivateKeyBits - 32);
    // TODO(bleichen): add tests for weak random number generators.
    // Verify the DH parameters.
    System.out.println("p=" + p.toString(16));
    System.out.println("g=" + g.toString(16));
    System.out.println("testKeyPairGenerator L=" + priv.getParams().getL());
    // Basic parameter checks
    assertTrue("Expecting g > 1", g.compareTo(BigInteger.ONE) > 0);
    assertTrue("Expecting g < p - 1", g.compareTo(p.subtract(BigInteger.ONE)) < 0);
    // Expecting p to be prime.
    // No high certainty is needed, since this is a unit test.
    assertTrue(p.isProbablePrime(4));
    // The order of g should be a large prime divisor q of p-1.
    // (see e.g. NIST SP 800-56A, section 5.5.1.1.)
    // If the order of g is composite then the the Decision Diffie Hellman assumption is
    // not satisfied for the group generated by g. Moreover, attacks using Pohlig-Hellman
    // might be feasible.
    // A good way to achieve these requirements is to select a safe prime p (i.e. a prime
    // where q=(p-1)/2 is prime too. NIST SP 800-56A does not require (or even recommend)
    // safe primes and allows Diffie-Hellman parameters where q is significantly smaller.
    // Unfortunately, the key does not contain q and thus the conditions above  cannot be
    // tested easily.
    // We perform a partial test that performs a partial factorization of p-1 and then
    // test whether one of the small factors found by the partial factorization divides
    // the order of g.
    boolean isSafePrime = p.shiftRight(1).isProbablePrime(4);
    System.out.println("p is a safe prime:" + isSafePrime);
    // p-1 divided by small prime factors.
    BigInteger r;
    if (isSafePrime) {
        r = p.shiftRight(1);
    } else {
        BigInteger p1 = p.subtract(BigInteger.ONE);
        r = p1.divide(smoothDivisor(p1));
    }
    System.out.println("r=" + r.toString(16));
    assertEquals("g likely does not generate a prime oder subgroup", BigInteger.ONE, g.modPow(r, p));
    // Checks that there are not too many short prime factors.
    // I.e., subgroup confinment attacks can find at least keySize - r.bitLength() bits of the key.
    // At least 160 unknown bits should remain.
    // Only very weak parameters are detected here, since the factorization above only finds small
    // prime factors.
    assertTrue(minPrivateKeyBits - (keySize - r.bitLength()) > 160);
    // A large g that divides p-1 is suspicious.
    if (g.bitLength() >= 160) {
        assertTrue(p.mod(g).compareTo(BigInteger.ONE) > 0);
    }
}
Also used : DHPrivateKey(javax.crypto.interfaces.DHPrivateKey) BigInteger(java.math.BigInteger) SlowTest(com.google.security.wycheproof.WycheproofRunner.SlowTest)

Example 2 with SlowTest

use of com.google.security.wycheproof.WycheproofRunner.SlowTest in project wycheproof by google.

the class DhiesTest method testDhiesCorrupt.

/**
   * WARNING: This test uses weak crypto (i.e. DHIESWithAES). DHIES should be secure against chosen
   * ciphertexts. Checks that a modification of the ciphertext is dectected.
   */
@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE })
@SuppressWarnings("InsecureCryptoUsage")
public void testDhiesCorrupt() throws Exception {
    KeyPairGenerator kf = KeyPairGenerator.getInstance("DH");
    kf.initialize(ike2048());
    KeyPair keyPair = kf.generateKeyPair();
    PrivateKey priv = keyPair.getPrivate();
    PublicKey pub = keyPair.getPublic();
    byte[] message = new byte[32];
    Cipher dhies;
    try {
        dhies = Cipher.getInstance("DHIESwithAES");
    } catch (NoSuchAlgorithmException ex) {
        // The algorithm isn't supported - even better!
        return;
    }
    dhies.init(Cipher.ENCRYPT_MODE, pub);
    byte[] ciphertext = dhies.doFinal(message);
    for (int i = 0; i < ciphertext.length; i++) {
        byte[] corrupt = Arrays.copyOf(ciphertext, ciphertext.length);
        corrupt[i] ^= (byte) 1;
        try {
            dhies.init(Cipher.DECRYPT_MODE, priv);
            dhies.doFinal(corrupt);
            fail("Corrupt ciphertext accepted:" + i);
        } catch (GeneralSecurityException ex) {
        // This is expected
        }
    }
}
Also used : KeyPair(java.security.KeyPair) PrivateKey(java.security.PrivateKey) PublicKey(java.security.PublicKey) GeneralSecurityException(java.security.GeneralSecurityException) KeyPairGenerator(java.security.KeyPairGenerator) Cipher(javax.crypto.Cipher) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SlowTest(com.google.security.wycheproof.WycheproofRunner.SlowTest)

Example 3 with SlowTest

use of com.google.security.wycheproof.WycheproofRunner.SlowTest in project wycheproof by google.

the class DsaTest method testBiasSha1WithDSA.

/**
   * Checks whether CVE-2016-0695 has been fixed. Before the April 2016 security update, the SUN
   * provider had a serious flaw that leaked the private key with about 3-5 signatures. In
   * particular, "Sha1WithDSA" always generated 160 bit k's independently of q. Unfortunately, it is
   * easily possible to use 2048 and 3072 bit DSA keys together with SHA1WithDSA. All a user has to
   * do is to use the algorithm name "DSA" instead of "SHA256WithDSA" rsp. "SHA224WithDSA".
   *
   * <p>An algorithm to extract the key from the signatures has been described for example in the
   * paper <a href="http://www.hpl.hp.com/techreports/1999/HPL-1999-90.pdf">Lattice Attacks on
   * Digital Signature Schemes</a> by N.A. Howgrave-Graham, N.P. Smart.
   *
   * <p>This bug is the same as US-CERT: VU # 940388: GnuPG generated ElGamal signatures that leaked
   * the private key.
   */
@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE })
@SuppressWarnings("InsecureCryptoUsage")
public void testBiasSha1WithDSA() throws Exception {
    String hashAlgorithm = "SHA";
    String message = "Hello";
    byte[] messageBytes = message.getBytes("UTF-8");
    byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
    BigInteger h = new BigInteger(1, digest);
    KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("DSA");
    generator.initialize(2048);
    KeyPair keyPair = generator.generateKeyPair();
    DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
    Signature signer = Signature.getInstance("DSA");
    try {
        // Private key and selected algorithm by signer do not match.
        // Hence throwing an exception at this point would be the reasonable.
        signer.initSign(priv);
        signer.update(messageBytes);
        byte[] signature = signer.sign();
        BigInteger q = priv.getParams().getQ();
        BigInteger k = extractK(signature, h, priv, true);
        // Now check if k is heavily biased.
        int lengthDiff = q.bitLength() - k.bitLength();
        if (lengthDiff > 32) {
            fail("Severly biased DSA signature:" + " len(q)=" + q.bitLength() + " len(k)=" + k.bitLength());
        }
    } catch (GeneralSecurityException ex) {
        // The key is invalid, hence getting here is reasonable.
        return;
    }
}
Also used : KeyPair(java.security.KeyPair) Signature(java.security.Signature) GeneralSecurityException(java.security.GeneralSecurityException) BigInteger(java.math.BigInteger) DSAPrivateKey(java.security.interfaces.DSAPrivateKey) KeyPairGenerator(java.security.KeyPairGenerator) SlowTest(com.google.security.wycheproof.WycheproofRunner.SlowTest)

Example 4 with SlowTest

use of com.google.security.wycheproof.WycheproofRunner.SlowTest in project wycheproof by google.

the class DsaTest method testTiming.

/**
   * This test checks for potential of a timing attack. The test generates a number of signatures,
   * selects a fraction of them with a small timing and then compares the values k for the selected
   * signatures with a normal distribution. The test fails if these ks are much smaller than
   * expected. An implementation flaw that can lead to a test failure is to compute the signature
   * with a modular exponentiation with a runtime that depend on the length of the exponent.
   *
   * <p>A failing test simply means that the timing can be used to get information about k. Further
   * analysis is necessary to determine if the bias is exploitable and how many timings are
   * necessary for an attack. A passing test does not mean that the implementation is secure against
   * timing attacks. The test only catches relatively big timing differences. It requires high
   * confidence to fail. Noise on the test machine can prevent that a relation between timing and k
   * can be detected.
   *
   * <p>Claims of what is exploitable: http://www.hpl.hp.com/techreports/1999/HPL-1999-90.pdf 30
   * signatures are sufficient to find the private key if the attacker knows 8 bits of each k.
   * http://eprint.iacr.org/2004/277.pdf 27 signatures are sufficient if 8 bits of each k is known.
   * Our own old experiments (using 1GB memory on a Pentium-4? CPU): 2^11 signatures are sufficient
   * with a 3 bit leakage. 2^15 signatures are sufficient with a 2 bit leakage. 2^24 signatures are
   * sufficient with a 1 bit leakage. Estimate for biased generation in the NIST standard: e.g. 2^22
   * signatures, 2^40 memory, 2^64 time
   *
   * <p><b>Sample output for the SUN provider:</b> <code>
   * count:50000 cutoff:4629300 relative average:0.9992225872624547 sigmas:0.3010906585642381
   * count:25000 cutoff:733961 relative average:0.976146066585879 sigmas:6.532668708070148
   * count:12500 cutoff:688305 relative average:0.9070352192339134 sigmas:18.00255238454385
   * count:6251 cutoff:673971 relative average:0.7747148791368986 sigmas:30.850903417893825
   * count:3125 cutoff:667045 relative average:0.5901994097874541 sigmas:39.67877152897901
   * count:1563 cutoff:662088 relative average:0.4060286694971057 sigmas:40.67294313795137
   * count:782 cutoff:657921 relative average:0.2577955312387898 sigmas:35.94906247333319
   * count:391 cutoff:653608 relative average:0.1453438859272699 sigmas:29.271192100879457
   * count:196 cutoff:649280 relative average:0.08035497211567771 sigmas:22.300206785132406
   * count:98 cutoff:645122 relative average:0.05063589092661368 sigmas:16.27820353139225
   * count:49 cutoff:641582 relative average:0.018255560447883384 sigmas:11.903018745467488
   * count:25 cutoff:638235 relative average:0.009082660721102722 sigmas:8.581595888660086
   * count:13 cutoff:633975 relative average:0.0067892346039088326 sigmas:6.20259924188633
   * </code>
   *
   * <p><b>What this shows:</b> The first line uses all 50'000 signatures. The average k of these
   * signatures is close to the expected value q/2. Being more selective gives us signatures with a
   * more biased k. For example, the 196 signatures with the fastest timing have about a 3-bit bias.
   * From this we expect that 2^19 signatures and timings are sufficient to find the private key.
   *
   * <p>A list of problems caught by this test:
   * <ul>
   * <li> CVE-2016-5548 OpenJDK8's DSA is vulnerable to timing attacks.
   * <li> CVE-2016-1000341 BouncyCastle before v 1.56 is vulnernerable to timing attacks.
   * </ul>
   */
@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.OPENJDK, ProviderType.SPONGY_CASTLE })
@SuppressWarnings("InsecureCryptoUsage")
public void testTiming() throws Exception {
    ThreadMXBean bean = ManagementFactory.getThreadMXBean();
    if (!bean.isCurrentThreadCpuTimeSupported()) {
        System.out.println("getCurrentThreadCpuTime is not supported. Skipping");
        return;
    }
    String hashAlgorithm = "SHA-1";
    String message = "Hello";
    byte[] messageBytes = message.getBytes("UTF-8");
    byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
    BigInteger h = new BigInteger(1, digest);
    KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("DSA");
    generator.initialize(1024);
    KeyPair keyPair = generator.generateKeyPair();
    DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
    Signature signer = Signature.getInstance("SHA1WITHDSA");
    signer.initSign(priv);
    // The timings below are quite noisy. Thus we need a large number of samples.
    int samples = 50000;
    long[] timing = new long[samples];
    BigInteger[] k = new BigInteger[samples];
    for (int i = 0; i < samples; i++) {
        long start = bean.getCurrentThreadCpuTime();
        signer.update(messageBytes);
        byte[] signature = signer.sign();
        timing[i] = bean.getCurrentThreadCpuTime() - start;
        k[i] = extractK(signature, h, priv, false);
    }
    long[] sorted = Arrays.copyOf(timing, timing.length);
    Arrays.sort(sorted);
    // Here we are only interested in roughly the 8 most significant bits of the ks.
    // Hence, using double is sufficiently precise.
    double q = priv.getParams().getQ().doubleValue();
    double expectedAverage = q / 2;
    double maxSigmas = 0;
    System.out.println("testTiming: SHA1WITHDSA");
    for (int idx = samples - 1; idx > 10; idx /= 2) {
        long cutoff = sorted[idx];
        int count = 0;
        double total = 0;
        for (int i = 0; i < samples; i++) {
            if (timing[i] <= cutoff) {
                total += k[i].doubleValue();
                count += 1;
            }
        }
        double expectedStdDev = q / Math.sqrt(12 * count);
        double average = total / count;
        // Number of standard deviations that the average is away from
        // the expected value:
        double sigmas = (expectedAverage - average) / expectedStdDev;
        if (sigmas > maxSigmas) {
            maxSigmas = sigmas;
        }
        System.out.println("count:" + count + " cutoff:" + cutoff + " relative average:" + (average / expectedAverage) + " sigmas:" + sigmas);
    }
    // than 10^{-10}.
    if (maxSigmas >= 7) {
        fail("Signatures with short timing have a biased k");
    }
}
Also used : ThreadMXBean(java.lang.management.ThreadMXBean) KeyPair(java.security.KeyPair) KeyPairGenerator(java.security.KeyPairGenerator) Signature(java.security.Signature) BigInteger(java.math.BigInteger) DSAPrivateKey(java.security.interfaces.DSAPrivateKey) SlowTest(com.google.security.wycheproof.WycheproofRunner.SlowTest)

Example 5 with SlowTest

use of com.google.security.wycheproof.WycheproofRunner.SlowTest in project wycheproof by google.

the class DsaTest method testBasic.

/**
   * This is just a test for basic functionality of DSA. The test generates a public and private
   * key, generates a signature, verifies it and prints the whole thing out. This test is useful
   * when an implementation is seriously broken.
   */
@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE })
@SuppressWarnings("InsecureCryptoUsage")
public void testBasic() throws Exception {
    int keySize = 2048;
    String algorithm = "SHA256WithDSA";
    String hashAlgorithm = "SHA-256";
    String message = "Hello";
    byte[] messageBytes = message.getBytes("UTF-8");
    KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("DSA");
    generator.initialize(keySize);
    KeyPair keyPair = generator.generateKeyPair();
    DSAPublicKey pub = (DSAPublicKey) keyPair.getPublic();
    DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
    Signature signer = Signature.getInstance(algorithm);
    Signature verifier = Signature.getInstance(algorithm);
    signer.initSign(priv);
    signer.update(messageBytes);
    byte[] signature = signer.sign();
    verifier.initVerify(pub);
    verifier.update(messageBytes);
    assertTrue(verifier.verify(signature));
    // Extract some parameters.
    byte[] rawHash = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
    DSAParams params = priv.getParams();
    // Print keys and signature, so that it can be used to generate new test vectors.
    System.out.println("Message:" + message);
    System.out.println("Hash:" + TestUtil.bytesToHex(rawHash));
    System.out.println("Params:");
    System.out.println("p:" + params.getP().toString());
    System.out.println("q:" + params.getQ().toString());
    System.out.println("g:" + params.getG().toString());
    System.out.println("Private key:");
    System.out.println("X:" + priv.getX().toString());
    System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
    System.out.println("Public key:");
    System.out.println("Y:" + pub.getY().toString());
    System.out.println("encoded:" + TestUtil.bytesToHex(pub.getEncoded()));
    System.out.println("Signature:" + TestUtil.bytesToHex(signature));
    System.out.println("r:" + extractR(signature).toString());
    System.out.println("s:" + extractS(signature).toString());
}
Also used : KeyPair(java.security.KeyPair) Signature(java.security.Signature) DSAPrivateKey(java.security.interfaces.DSAPrivateKey) KeyPairGenerator(java.security.KeyPairGenerator) DSAParams(java.security.interfaces.DSAParams) DSAPublicKey(java.security.interfaces.DSAPublicKey) SlowTest(com.google.security.wycheproof.WycheproofRunner.SlowTest)

Aggregations

SlowTest (com.google.security.wycheproof.WycheproofRunner.SlowTest)5 KeyPair (java.security.KeyPair)4 KeyPairGenerator (java.security.KeyPairGenerator)4 BigInteger (java.math.BigInteger)3 Signature (java.security.Signature)3 DSAPrivateKey (java.security.interfaces.DSAPrivateKey)3 GeneralSecurityException (java.security.GeneralSecurityException)2 ThreadMXBean (java.lang.management.ThreadMXBean)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 PrivateKey (java.security.PrivateKey)1 PublicKey (java.security.PublicKey)1 DSAParams (java.security.interfaces.DSAParams)1 DSAPublicKey (java.security.interfaces.DSAPublicKey)1 Cipher (javax.crypto.Cipher)1 DHPrivateKey (javax.crypto.interfaces.DHPrivateKey)1