From f7ecb0dfad2cc15d42eacefb13e8675dd664dd38 Mon Sep 17 00:00:00 2001 From: Emilia Kasper Date: Fri, 14 Oct 2016 15:58:23 +0200 Subject: Initial GitHub export --- .../security/wycheproof/BouncyCastleAllTests.java | 53 + .../security/wycheproof/BouncyCastleTest.java | 55 + .../google/security/wycheproof/ConscryptTest.java | 51 + java/com/google/security/wycheproof/EcUtil.java | 454 ++++++++ .../security/wycheproof/OpenJDKAllTests.java | 34 + .../google/security/wycheproof/OpenJDKTest.java | 36 + .../wycheproof/ProviderIndependentTest.java | 26 + .../com/google/security/wycheproof/RandomUtil.java | 185 ++++ .../security/wycheproof/SpongyCastleAllTests.java | 54 + .../security/wycheproof/SpongyCastleTest.java | 56 + java/com/google/security/wycheproof/TestUtil.java | 99 ++ .../security/wycheproof/WycheproofRunner.java | 206 ++++ .../security/wycheproof/testcases/AesEaxTest.java | 268 +++++ .../security/wycheproof/testcases/AesGcmTest.java | 405 +++++++ .../security/wycheproof/testcases/BasicTest.java | 45 + .../wycheproof/testcases/BigIntegerTest.java | 461 ++++++++ .../testcases/CipherInputStreamTest.java | 279 +++++ .../testcases/CipherOutputStreamTest.java | 239 +++++ .../security/wycheproof/testcases/DhTest.java | 396 +++++++ .../security/wycheproof/testcases/DhiesTest.java | 157 +++ .../security/wycheproof/testcases/DsaTest.java | 655 ++++++++++++ .../security/wycheproof/testcases/EcKeyTest.java | 230 ++++ .../security/wycheproof/testcases/EcdhTest.java | 1125 ++++++++++++++++++++ .../security/wycheproof/testcases/EcdsaTest.java | 462 ++++++++ .../security/wycheproof/testcases/EciesTest.java | 347 ++++++ .../wycheproof/testcases/RsaEncryptionTest.java | 138 +++ .../security/wycheproof/testcases/RsaKeyTest.java | 139 +++ .../wycheproof/testcases/RsaSignatureTest.java | 140 +++ 28 files changed, 6795 insertions(+) create mode 100644 java/com/google/security/wycheproof/BouncyCastleAllTests.java create mode 100644 java/com/google/security/wycheproof/BouncyCastleTest.java create mode 100644 java/com/google/security/wycheproof/ConscryptTest.java create mode 100644 java/com/google/security/wycheproof/EcUtil.java create mode 100644 java/com/google/security/wycheproof/OpenJDKAllTests.java create mode 100644 java/com/google/security/wycheproof/OpenJDKTest.java create mode 100644 java/com/google/security/wycheproof/ProviderIndependentTest.java create mode 100644 java/com/google/security/wycheproof/RandomUtil.java create mode 100644 java/com/google/security/wycheproof/SpongyCastleAllTests.java create mode 100644 java/com/google/security/wycheproof/SpongyCastleTest.java create mode 100644 java/com/google/security/wycheproof/TestUtil.java create mode 100644 java/com/google/security/wycheproof/WycheproofRunner.java create mode 100644 java/com/google/security/wycheproof/testcases/AesEaxTest.java create mode 100644 java/com/google/security/wycheproof/testcases/AesGcmTest.java create mode 100644 java/com/google/security/wycheproof/testcases/BasicTest.java create mode 100644 java/com/google/security/wycheproof/testcases/BigIntegerTest.java create mode 100644 java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java create mode 100644 java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java create mode 100644 java/com/google/security/wycheproof/testcases/DhTest.java create mode 100644 java/com/google/security/wycheproof/testcases/DhiesTest.java create mode 100644 java/com/google/security/wycheproof/testcases/DsaTest.java create mode 100644 java/com/google/security/wycheproof/testcases/EcKeyTest.java create mode 100644 java/com/google/security/wycheproof/testcases/EcdhTest.java create mode 100644 java/com/google/security/wycheproof/testcases/EcdsaTest.java create mode 100644 java/com/google/security/wycheproof/testcases/EciesTest.java create mode 100644 java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java create mode 100644 java/com/google/security/wycheproof/testcases/RsaKeyTest.java create mode 100644 java/com/google/security/wycheproof/testcases/RsaSignatureTest.java (limited to 'java/com') diff --git a/java/com/google/security/wycheproof/BouncyCastleAllTests.java b/java/com/google/security/wycheproof/BouncyCastleAllTests.java new file mode 100644 index 0000000..47a4dcf --- /dev/null +++ b/java/com/google/security/wycheproof/BouncyCastleAllTests.java @@ -0,0 +1,53 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; + +/** + * BouncyCastleAllTests runs all tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesEaxTest.class, + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + DhTest.class, + DhiesTest.class, + DsaTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + EciesTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class, +}) +@Provider(ProviderType.BOUNCY_CASTLE) +public final class BouncyCastleAllTests { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyThisProvider(new BouncyCastleProvider()); + } +} diff --git a/java/com/google/security/wycheproof/BouncyCastleTest.java b/java/com/google/security/wycheproof/BouncyCastleTest.java new file mode 100644 index 0000000..941b94f --- /dev/null +++ b/java/com/google/security/wycheproof/BouncyCastleTest.java @@ -0,0 +1,55 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Fast; +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; + +/** + * BouncyCastleTest excludes {@code @SlowTest} tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesEaxTest.class, + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + DhTest.class, + DhiesTest.class, + DsaTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + EciesTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class, +}) +@Provider(ProviderType.BOUNCY_CASTLE) +@Fast +public final class BouncyCastleTest { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyThisProvider(new BouncyCastleProvider()); + } +} diff --git a/java/com/google/security/wycheproof/ConscryptTest.java b/java/com/google/security/wycheproof/ConscryptTest.java new file mode 100644 index 0000000..c4f58d5 --- /dev/null +++ b/java/com/google/security/wycheproof/ConscryptTest.java @@ -0,0 +1,51 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Fast; +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.conscrypt.OpenSSLProvider; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; + +/** + * Conscrypt is a Java security provider that uses OpenSSL. See {@link https://conscrypt.org/}. + * ConscryptTest excludes {@code @SlowTest} tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class +}) +@Provider(ProviderType.CONSCRYPT) +@Fast +public final class ConscryptTest { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyThisProvider(new OpenSSLProvider()); + } +} diff --git a/java/com/google/security/wycheproof/EcUtil.java b/java/com/google/security/wycheproof/EcUtil.java new file mode 100644 index 0000000..f464cba --- /dev/null +++ b/java/com/google/security/wycheproof/EcUtil.java @@ -0,0 +1,454 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECField; +import java.security.spec.ECFieldFp; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; +import java.security.spec.InvalidParameterSpecException; +import java.util.Arrays; + +/** + * Some utilities for testing Elliptic curve crypto. This code is for testing only and hasn't been + * reviewed for production. + */ +public class EcUtil { + /** + * Returns the ECParameterSpec for a named curve. Not every provider implements the + * AlgorithmParameters. Therefore, most test use alternative functions. + */ + public static ECParameterSpec getCurveSpec(String name) + throws NoSuchAlgorithmException, InvalidParameterSpecException { + AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC"); + parameters.init(new ECGenParameterSpec(name)); + return parameters.getParameterSpec(ECParameterSpec.class); + } + + /** + * Returns the ECParameterSpec for a named curve. Only a handful curves that are used in the tests + * are implemented. + */ + public static ECParameterSpec getCurveSpecRef(String name) throws NoSuchAlgorithmException { + if (name.equals("secp224r1")) { + return getNistP224Params(); + } else if (name.equals("secp256r1")) { + return getNistP256Params(); + } else if (name.equals("secp384r1")) { + return getNistP384Params(); + } else if (name.equals("secp521r1")) { + return getNistP521Params(); + } else if (name.equals("brainpoolp256r1")) { + return getBrainpoolP256r1Params(); + } else { + throw new NoSuchAlgorithmException("Curve not implemented:" + name); + } + } + + public static ECParameterSpec getNistCurveSpec( + String decimalP, String decimalN, String hexB, String hexGX, String hexGY) { + final BigInteger p = new BigInteger(decimalP); + final BigInteger n = new BigInteger(decimalN); + final BigInteger three = new BigInteger("3"); + final BigInteger a = p.subtract(three); + final BigInteger b = new BigInteger(hexB, 16); + final BigInteger gx = new BigInteger(hexGX, 16); + final BigInteger gy = new BigInteger(hexGY, 16); + final int h = 1; + ECFieldFp fp = new ECFieldFp(p); + java.security.spec.EllipticCurve curveSpec = new java.security.spec.EllipticCurve(fp, a, b); + ECPoint g = new ECPoint(gx, gy); + ECParameterSpec ecSpec = new ECParameterSpec(curveSpec, g, n, h); + return ecSpec; + } + + public static ECParameterSpec getNistP224Params() { + return getNistCurveSpec( + "26959946667150639794667015087019630673557916260026308143510066298881", + "26959946667150639794667015087019625940457807714424391721682722368061", + "b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"); + } + + public static ECParameterSpec getNistP256Params() { + return getNistCurveSpec( + "115792089210356248762697446949407573530086143415290314195533631308867097853951", + "115792089210356248762697446949407573529996955224135760342422259061068512044369", + "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"); + } + + public static ECParameterSpec getNistP384Params() { + return getNistCurveSpec( + "3940200619639447921227904010014361380507973927046544666794829340" + + "4245721771496870329047266088258938001861606973112319", + "3940200619639447921227904010014361380507973927046544666794690527" + + "9627659399113263569398956308152294913554433653942643", + "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" + + "c656398d8a2ed19d2a85c8edd3ec2aef", + "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" + + "5502f25dbf55296c3a545e3872760ab7", + "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" + + "0a60b1ce1d7e819d7a431d7c90ea0e5f"); + } + + public static ECParameterSpec getNistP521Params() { + return getNistCurveSpec( + "6864797660130609714981900799081393217269435300143305409394463459" + + "18554318339765605212255964066145455497729631139148085803712198" + + "7999716643812574028291115057151", + "6864797660130609714981900799081393217269435300143305409394463459" + + "18554318339765539424505774633321719753296399637136332111386476" + + "8612440380340372808892707005449", + "051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" + + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d" + + "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6" + + "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"); + } + + public static ECParameterSpec getBrainpoolP256r1Params() { + BigInteger p = + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16); + BigInteger a = + new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16); + BigInteger b = + new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16); + BigInteger x = + new BigInteger("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16); + BigInteger y = + new BigInteger("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16); + BigInteger n = + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16); + final int h = 1; + ECFieldFp fp = new ECFieldFp(p); + EllipticCurve curve = new EllipticCurve(fp, a, b); + ECPoint g = new ECPoint(x, y); + return new ECParameterSpec(curve, g, n, h); + } + + /** + * Compute the Legendre symbol of x mod p. This implementation is slow. Faster would be the + * computation for the Jacobi symbol. + * + * @param x an integer + * @param p a prime modulus + * @returns 1 if x is a quadratic residue, -1 if x is a non-quadratic residue and 0 if x and p are + * not coprime. + * @throws GeneralSecurityException when the computation shows that p is not prime. + */ + public static int legendre(BigInteger x, BigInteger p) throws GeneralSecurityException { + BigInteger q = p.subtract(BigInteger.ONE).shiftRight(1); + BigInteger t = x.modPow(q, p); + if (t.equals(BigInteger.ONE)) { + return 1; + } else if (t.equals(BigInteger.ZERO)) { + return 0; + } else if (t.add(BigInteger.ONE).equals(p)) { + return -1; + } else { + throw new GeneralSecurityException("p is not prime"); + } + } + + /** + * Computes a modular square root. Timing and exceptions can leak information about the inputs. + * Therefore this method must only be used in tests. + * + * @param x the square + * @param p the prime modulus + * @returns a value s such that s^2 mod p == x mod p + * @throws GeneralSecurityException if the square root could not be found. + */ + public static BigInteger modSqrt(BigInteger x, BigInteger p) throws GeneralSecurityException { + if (p.signum() != 1) { + throw new GeneralSecurityException("p must be positive"); + } + x = x.mod(p); + BigInteger squareRoot = null; + // Special case for x == 0. + // This check is necessary for Cipolla's algorithm. + if (x.equals(BigInteger.ZERO)) { + return x; + } + if (p.testBit(0) && p.testBit(1)) { + // Case p % 4 == 3 + // q = (p + 1) / 4 + BigInteger q = p.add(BigInteger.ONE).shiftRight(2); + squareRoot = x.modPow(q, p); + } else if (p.testBit(0) && !p.testBit(1)) { + // Case p % 4 == 1 + // For this case we use Cipolla's algorithm. + // This alogorithm is preferrable to Tonelli-Shanks for primes p where p-1 is divisible by + // a large power of 2, which is a frequent choice since it simplifies modular reduction. + BigInteger a = BigInteger.ONE; + BigInteger d = null; + while (true) { + d = a.multiply(a).subtract(x).mod(p); + // Computes the Legendre symbol. Using the Jacobi symbol would be a faster. Using Legendre + // has the advantage, that it detects a non prime p with high probability. + // On the other hand if p = q^2 then the Jacobi (d/p)==1 for almost all d's and thus + // using the Jacobi symbol here can result in an endless loop with invalid inputs. + int t = legendre(d, p); + if (t == -1) { + break; + } else { + a = a.add(BigInteger.ONE); + } + } + // Since d = a^2 - n is a non-residue modulo p, we have + // a - sqrt(d) == (a+sqrt(d))^p (mod p), + // and hence + // n == (a + sqrt(d))(a - sqrt(d) == (a+sqrt(d))^(p+1) (mod p). + // Thus if n is square then (a+sqrt(d))^((p+1)/2) (mod p) is a square root of n. + BigInteger q = p.add(BigInteger.ONE).shiftRight(1); + BigInteger u = a; + BigInteger v = BigInteger.ONE; + for (int bit = q.bitLength() - 2; bit >= 0; bit--) { + // Compute (u + v sqrt(d))^2 + BigInteger tmp = u.multiply(v); + u = u.multiply(u).add(v.multiply(v).mod(p).multiply(d)).mod(p); + v = tmp.add(tmp).mod(p); + if (q.testBit(bit)) { + tmp = u.multiply(a).add(v.multiply(d)).mod(p); + v = a.multiply(v).add(u).mod(p); + u = tmp; + } + } + squareRoot = u; + } + // The methods used to compute the square root only guarantee a correct result if the + // preconditions (i.e. p prime and x is a square) are satisfied. Otherwise the value is + // undefined. Hence, it is important to verify that squareRoot is indeed a square root. + if (squareRoot != null && squareRoot.multiply(squareRoot).mod(p).compareTo(x) != 0) { + throw new GeneralSecurityException("Could not find square root"); + } + return squareRoot; + } + + /** + * Returns the modulus of the field used by the curve specified in ecParams. + * + * @param curve must be a prime order elliptic curve + * @return the order of the finite field over which curve is defined. + */ + public static BigInteger getModulus(EllipticCurve curve) throws GeneralSecurityException { + java.security.spec.ECField field = curve.getField(); + if (field instanceof java.security.spec.ECFieldFp) { + return ((java.security.spec.ECFieldFp) field).getP(); + } else { + throw new GeneralSecurityException("Only curves over prime order fields are supported"); + } + } + + /** + * Returns the size of an element of the field over which the curve is defined. + * + * @param curve must be a prime order elliptic curve + * @return the size of an element in bits + */ + public static int fieldSizeInBits(EllipticCurve curve) throws GeneralSecurityException { + return getModulus(curve).subtract(BigInteger.ONE).bitLength(); + } + + /** + * Returns the size of an element of the field over which the curve is defined. + * + * @param curve must be a prime order elliptic curve + * @return the size of an element in bytes. + */ + public static int fieldSizeInBytes(EllipticCurve curve) throws GeneralSecurityException { + return (fieldSizeInBits(curve) + 7) / 8; + } + + /** + * Checks that a point is on a given elliptic curve. This method implements the partial public key + * validation routine from Section 5.6.2.6 of NIST SP 800-56A + * http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf A partial + * public key validation is sufficient for curves with cofactor 1. See Section B.3 of + * http://www.nsa.gov/ia/_files/SuiteB_Implementer_G-113808.pdf The point validations above are + * taken from recommendations for ECDH, because parameter checks in ECDH are much more important + * than for the case of ECDSA. Performing this test for ECDSA keys is mainly a sanity check. + * + * @param point the point that needs verification + * @param ec the elliptic curve. This must be a curve over a prime order field. + * @throws GeneralSecurityException if the field is binary or if the point is not on the curve. + */ + public static void checkPointOnCurve(ECPoint point, EllipticCurve ec) + throws GeneralSecurityException { + BigInteger p = getModulus(ec); + BigInteger x = point.getAffineX(); + BigInteger y = point.getAffineY(); + if (x == null || y == null) { + throw new GeneralSecurityException("point is at infinity"); + } + // Check 0 <= x < p and 0 <= y < p. + if (x.signum() == -1 || x.compareTo(p) != -1) { + throw new GeneralSecurityException("x is out of range"); + } + if (y.signum() == -1 || y.compareTo(p) != -1) { + throw new GeneralSecurityException("y is out of range"); + } + // Check y^2 == x^3 + a x + b (mod p) + BigInteger lhs = y.multiply(y).mod(p); + BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p); + if (!lhs.equals(rhs)) { + throw new GeneralSecurityException("Point is not on curve"); + } + } + + /** + * Checks a public key. I.e. this checks that the point defining the public key is on the curve. + * + * @param key must be a key defined over a curve using a prime order field. + * @throws GeneralSecurityException if the key is not valid. + */ + public static void checkPublicKey(ECPublicKey key) throws GeneralSecurityException { + checkPointOnCurve(key.getW(), key.getParams().getCurve()); + } + + /** + * Decompress a point + * + * @param x The x-coordinate of the point + * @param bit0 true if the least significant bit of y is set. + * @param ecParams contains the curve of the point. This must be over a prime order field. + */ + public static ECPoint getPoint(BigInteger x, boolean bit0, ECParameterSpec ecParams) + throws GeneralSecurityException { + EllipticCurve ec = ecParams.getCurve(); + ECField field = ec.getField(); + if (!(field instanceof ECFieldFp)) { + throw new GeneralSecurityException("Only curves over prime order fields are supported"); + } + BigInteger p = ((java.security.spec.ECFieldFp) field).getP(); + if (x.compareTo(BigInteger.ZERO) == -1 || x.compareTo(p) != -1) { + throw new GeneralSecurityException("x is out of range"); + } + // Compute rhs == x^3 + a x + b (mod p) + BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p); + BigInteger y = modSqrt(rhs, p); + if (bit0 != y.testBit(0)) { + y = p.subtract(y).mod(p); + } + return new ECPoint(x, y); + } + + /** + * Decompress a point on an elliptic curve. + * + * @param bytes The compressed point. Its representation is z || x where z is 2+lsb(y) and x is + * using a unsigned fixed length big-endian representation. + * @param ecParams the specification of the curve. Only Weierstrass curves over prime order fields + * are implemented. + */ + public static ECPoint decompressPoint(byte[] bytes, ECParameterSpec ecParams) + throws GeneralSecurityException { + EllipticCurve ec = ecParams.getCurve(); + ECField field = ec.getField(); + if (!(field instanceof ECFieldFp)) { + throw new GeneralSecurityException("Only curves over prime order fields are supported"); + } + BigInteger p = ((java.security.spec.ECFieldFp) field).getP(); + int expectedLength = 1 + (p.bitLength() + 7) / 8; + if (bytes.length != expectedLength) { + throw new GeneralSecurityException("compressed point has wrong length"); + } + boolean lsb; + switch (bytes[0]) { + case 2: + lsb = false; + break; + case 3: + lsb = true; + break; + default: + throw new GeneralSecurityException("Invalid format"); + } + BigInteger x = new BigInteger(1, Arrays.copyOfRange(bytes, 1, bytes.length)); + if (x.compareTo(BigInteger.ZERO) == -1 || x.compareTo(p) != -1) { + throw new GeneralSecurityException("x is out of range"); + } + // Compute rhs == x^3 + a x + b (mod p) + BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p); + BigInteger y = modSqrt(rhs, p); + if (lsb != y.testBit(0)) { + y = p.subtract(y).mod(p); + } + return new ECPoint(x, y); + } + + /** + * Returns a weak public key of order 3 such that the public key point is on the curve specified + * in ecParams. This method is used to check ECC implementations for missing step in the + * verification of the public key. E.g. implementations of ECDH must verify that the public key + * contains a point on the curve as well as public and secret key are using the same curve. + * + * @param ecParams the parameters of the key to attack. This must be a curve in Weierstrass form + * over a prime order field. + * @return a weak EC group with a genrator of order 3. + */ + public static ECPublicKeySpec getWeakPublicKey(ECParameterSpec ecParams) + throws GeneralSecurityException { + EllipticCurve curve = ecParams.getCurve(); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); + keyGen.initialize(ecParams); + BigInteger p = getModulus(curve); + BigInteger three = new BigInteger("3"); + while (true) { + // Generate a point on the original curve + KeyPair keyPair = keyGen.generateKeyPair(); + ECPublicKey pub = (ECPublicKey) keyPair.getPublic(); + ECPoint w = pub.getW(); + BigInteger x = w.getAffineX(); + BigInteger y = w.getAffineY(); + // Find the curve parameters a,b such that 3*w = infinity. + // This is the case if the following equations are satisfied: + // 3x == l^2 (mod p) + // l == (3x^2 + a) / 2*y (mod p) + // y^2 == x^3 + ax + b (mod p) + BigInteger l; + try { + l = modSqrt(x.multiply(three), p); + } catch (GeneralSecurityException ex) { + continue; + } + BigInteger xSqr = x.multiply(x).mod(p); + BigInteger a = l.multiply(y.add(y)).subtract(xSqr.multiply(three)).mod(p); + BigInteger b = y.multiply(y).subtract(x.multiply(xSqr.add(a))).mod(p); + EllipticCurve newCurve = new EllipticCurve(curve.getField(), a, b); + // Just a sanity check. + checkPointOnCurve(w, newCurve); + // Cofactor and order are of course wrong. + ECParameterSpec spec = new ECParameterSpec(newCurve, w, p, 1); + return new ECPublicKeySpec(w, spec); + } + } +} diff --git a/java/com/google/security/wycheproof/OpenJDKAllTests.java b/java/com/google/security/wycheproof/OpenJDKAllTests.java new file mode 100644 index 0000000..a2b3b06 --- /dev/null +++ b/java/com/google/security/wycheproof/OpenJDKAllTests.java @@ -0,0 +1,34 @@ +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; + +/** + * Tests for OpenJDK's providers: SunJCE, SunEC, etc. + * OpenJDKAllTests runs all tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + DhTest.class, + DsaTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class +}) +@Provider(ProviderType.OPENJDK) +public final class OpenJDKAllTests { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyOpenJDKProviders(); + } +} diff --git a/java/com/google/security/wycheproof/OpenJDKTest.java b/java/com/google/security/wycheproof/OpenJDKTest.java new file mode 100644 index 0000000..b326fef --- /dev/null +++ b/java/com/google/security/wycheproof/OpenJDKTest.java @@ -0,0 +1,36 @@ +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Fast; +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; + +/** + * Tests for OpenJDK's providers: SunJCE, SunEC, etc. + * OpenJDKTest excludes slow tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + DhTest.class, + DsaTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class +}) +@Provider(ProviderType.OPENJDK) +@Fast +public final class OpenJDKTest { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyOpenJDKProviders(); + } +} diff --git a/java/com/google/security/wycheproof/ProviderIndependentTest.java b/java/com/google/security/wycheproof/ProviderIndependentTest.java new file mode 100644 index 0000000..931fc64 --- /dev/null +++ b/java/com/google/security/wycheproof/ProviderIndependentTest.java @@ -0,0 +1,26 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +/** Provider independent tests */ +@RunWith(Suite.class) +@SuiteClasses({BigIntegerTest.class}) +public final class ProviderIndependentTest {} diff --git a/java/com/google/security/wycheproof/RandomUtil.java b/java/com/google/security/wycheproof/RandomUtil.java new file mode 100644 index 0000000..388c272 --- /dev/null +++ b/java/com/google/security/wycheproof/RandomUtil.java @@ -0,0 +1,185 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.util.Random; + +/** + * A collection of utilities for testing random number generators. So far this util simply checks + * that random numbers are not generated by java.util.Random. Eventually we plan to add detection + * for other random number generators too. + * + * @author bleichen@google.com (Daniel Bleichenbacher) + */ +public class RandomUtil { + // Constants for java.util.Random; + static final long A = 0x5DEECE66DL; + static final long A_INVERSE = 246154705703781L; + static final long C = 0xBL; + + /** Given a state of a java.util.Random object compute the next state. */ + protected static long nextState(long seed) { + return (seed * A + C) & ((1L << 48) - 1); + } + + /** Give the state after stepping java.util.Random n times. */ + protected static long step(long seed, long n) { + long a = A; + long c = C; + n = n & 0xffffffffffffL; + while (n != 0) { + if ((n & 1) == 1) { + seed = seed * a + c; + } + c = c * (a + 1); + a = a * a; + n = n >> 1; + } + return seed & 0xffffffffffffL; + } + + /** Given a state of a java.util.Random object compute the previous state. */ + protected static long previousState(long seed) { + return ((seed - C) * A_INVERSE) & ((1L << 48) - 1); + } + + /** Computes a seed that would initialize a java.util.Random object with a given state. */ + protected static long getSeedForState(long seed) { + return seed ^ A; + } + + protected static long getStateForSeed(long seed) { + return (seed ^ A) & 0xffffffffffffL; + } + + /** + * Given two subsequent outputs x0 and x1 from java.util.Random this function computes the + * internal state of java.util.Random after returning x0 or returns -1 if no such state exists. + */ + protected static long getState(int x0, int x1) { + long mask = (1L << 48) - 1; + long multiplier = A; + // The state of the random number generator after returning x0 is + // l0 + eps for some 0 <= eps < 2**16. + long l0 = ((long) x0 << 16) & mask; + // The state of the random number generator after returning x1 is + // l1 + delta for some 0 <= delta < 2**16. + long l1 = ((long) x1 << 16) & mask; + // We have l1 + delta = (l0 + eps)*multiplier + 0xBL (mod 2**48). + // This allows to find an upper bound w for eps * multiplier mod 2**48 + // by assuming delta = 2**16-1. + long w = (l1 - l0 * multiplier + 65535L - 0xBL) & mask; + // The reduction eps * multiplier mod 2**48 only cuts off at most 3 bits. + // Hence a simple search is sufficient. The maximal number of loops is 6. + for (long em = w; em < (multiplier << 16); em += 1L << 48) { + // If the high order bits of em are guessed correctly then + // em == eps * multiplier + 65535 - delta. + long eps = em / multiplier; + long state0 = l0 + eps; + long state1 = nextState(state0); + if ((state1 & 0xffffffff0000L) == l1) { + return state0; + } + } + return -1; + } + + /** + * Find a seed such that this integer is the result of + * + *
{@code
+   * Random rand = new Random();
+   * rand.setSeed(seed);
+   * return new BigInteger(k, rand);
+   * }
+ * + * where k is max(64, x.BitLength()); + * + *

Returns -1 if no such seed exists. + */ + // TODO(bleichen): We want to detect cases where some of the bits + // (i.e. most significant bits or least significant bits have + // been modified. Often this happens during the generation + // of primes or other things. + // TODO(bleichen): This method is incomplete. + protected static long getSeedFor(java.math.BigInteger x) { + byte[] bytes = x.toByteArray(); + if (bytes.length == 0) { + return -1; + } + ByteBuffer buffer = ByteBuffer.allocate(8); + int offset = bytes[0] == 0 ? 1 : 0; + if (bytes.length - offset < 8) { + int size = bytes.length - offset; + buffer.position(8 - size); + buffer.put(bytes, offset, size); + } else { + buffer.put(bytes, offset, 8); + } + buffer.flip(); + buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN); + int x0 = buffer.getInt(); + int x1 = buffer.getInt(); + long state = getState(x0, x1); + if (state == -1) { + return -1; + } + return getSeedForState(previousState(state)); + } + + /** Attempts to find a seed such that it generates the prime p. Returns -1 if no seed is found. */ + static long getSeedForPrime(BigInteger p) { + int confidence = 64; + Random rand = new Random(); + int size = p.bitLength(); + // Prime generation often sets the most significant bit. + // Hence, clearing the most significant bit can help to find + // the seed used for the prime generation. + for (BigInteger x : new BigInteger[] {p, p.clearBit(size - 1)}) { + long seed = getSeedFor(x); + if (seed != -1) { + rand.setSeed(seed); + BigInteger q = new BigInteger(size, confidence, rand); + if (q.equals(p)) { + return seed; + } + } + } + return -1; + } + + /** + * Checks whether p is a random prime. A prime generated with a secure random number generator + * passes with probability > 1-2^{-32}. No checks are performed for primes smaller than 96 bits. + * + * @throws GeneralSecurityException if the prime was generated using java.util.Random + */ + static void checkPrime(BigInteger p) throws GeneralSecurityException { + // We can't reliably detect java.util.Random for small primes. + if (p.bitLength() < 96) { + return; + } + long seed = getSeedForPrime(p); + if (seed != -1) { + throw new GeneralSecurityException( + "java.util.Random with seed " + seed + " was likely used to generate prime"); + } + } +} diff --git a/java/com/google/security/wycheproof/SpongyCastleAllTests.java b/java/com/google/security/wycheproof/SpongyCastleAllTests.java new file mode 100644 index 0000000..5566827 --- /dev/null +++ b/java/com/google/security/wycheproof/SpongyCastleAllTests.java @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; +import org.spongycastle.jce.provider.BouncyCastleProvider; + +/** + * SpongyCastleTest excludes {@code @SlowTest} tests. + * SpongyCastleAllTests runs all tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesEaxTest.class, + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + DhTest.class, + DhiesTest.class, + DsaTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + EciesTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class, +}) +@Provider(ProviderType.SPONGY_CASTLE) +public final class SpongyCastleAllTests { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyThisProvider(new BouncyCastleProvider()); + } +} diff --git a/java/com/google/security/wycheproof/SpongyCastleTest.java b/java/com/google/security/wycheproof/SpongyCastleTest.java new file mode 100644 index 0000000..73c8ca1 --- /dev/null +++ b/java/com/google/security/wycheproof/SpongyCastleTest.java @@ -0,0 +1,56 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import com.google.security.wycheproof.WycheproofRunner.Fast; +import com.google.security.wycheproof.WycheproofRunner.Provider; +import com.google.security.wycheproof.WycheproofRunner.ProviderType; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite.SuiteClasses; +import org.spongycastle.jce.provider.BouncyCastleProvider; + +/** + * Spongy Castle is a Bouncy Castle clone with a few changes to make it work on Android. + * SpongyCastleTest excludes {@code @SlowTest} tests. + */ +@RunWith(WycheproofRunner.class) +@SuiteClasses({ + AesEaxTest.class, + AesGcmTest.class, + BasicTest.class, + CipherInputStreamTest.class, + CipherOutputStreamTest.class, + DhTest.class, + DhiesTest.class, + DsaTest.class, + EcKeyTest.class, + EcdhTest.class, + EcdsaTest.class, + EciesTest.class, + RsaEncryptionTest.class, + RsaKeyTest.class, + RsaSignatureTest.class, +}) +@Provider(ProviderType.SPONGY_CASTLE) +@Fast +public final class SpongyCastleTest { + @BeforeClass + public static void setUp() throws Exception { + TestUtil.installOnlyThisProvider(new BouncyCastleProvider()); + } +} diff --git a/java/com/google/security/wycheproof/TestUtil.java b/java/com/google/security/wycheproof/TestUtil.java new file mode 100644 index 0000000..ae21adc --- /dev/null +++ b/java/com/google/security/wycheproof/TestUtil.java @@ -0,0 +1,99 @@ +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import java.nio.ByteBuffer; +import java.security.Provider; +import java.security.Security; + +/** Test utilities */ +public class TestUtil { + + public static String bytesToHex(byte[] bytes) { + // bytesToHex is used to convert output from Cipher. + // cipher.update can return null, which is equivalent to returning + // no plaitext rsp. ciphertext. + if (bytes == null) { + return ""; + } + String chars = "0123456789abcdef"; + StringBuilder result = new StringBuilder(2 * bytes.length); + for (byte b : bytes) { + // convert to unsigned + int val = b & 0xff; + result.append(chars.charAt(val / 16)); + result.append(chars.charAt(val % 16)); + } + return result.toString(); + } + + /** + * Returns a hexadecimal representation of the bytes written to ByteBuffer (i.e. all the bytes + * before position()). + */ + public static String byteBufferToHex(ByteBuffer buffer) { + ByteBuffer tmp = buffer.duplicate(); + tmp.flip(); + byte[] bytes = new byte[tmp.remaining()]; + tmp.get(bytes); + return bytesToHex(bytes); + } + + public static byte[] hexToBytes(String hex) throws IllegalArgumentException { + if (hex.length() % 2 != 0) { + throw new IllegalArgumentException("Expected a string of even length"); + } + int size = hex.length() / 2; + byte[] result = new byte[size]; + for (int i = 0; i < size; i++) { + int hi = Character.digit(hex.charAt(2 * i), 16); + int lo = Character.digit(hex.charAt(2 * i + 1), 16); + if ((hi == -1) || (lo == -1)) { + throw new IllegalArgumentException("input is not hexadecimal"); + } + result[i] = (byte) (16 * hi + lo); + } + return result; + } + + public static void installOnlyThisProvider(Provider provider) { + for (Provider p : Security.getProviders()) { + Security.removeProvider(p.getName()); + } + Security.insertProviderAt(provider, 1); + } + + public static void installOnlyOpenJDKProviders() throws Exception { + for (Provider p : Security.getProviders()) { + Security.removeProvider(p.getName()); + } + installOpenJDKProvider("com.sun.net.ssl.internal.ssl.Provider"); + installOpenJDKProvider("com.sun.crypto.provider.SunJCE"); + installOpenJDKProvider("com.sun.security.sasl.Provider"); + installOpenJDKProvider("org.jcp.xml.dsig.internal.dom.XMLDSigRI"); + installOpenJDKProvider("sun.security.ec.SunEC"); + installOpenJDKProvider("sun.security.jgss.SunProvider"); + installOpenJDKProvider("sun.security.provider.Sun"); + installOpenJDKProvider("sun.security.rsa.SunRsaSign"); + installOpenJDKProvider("sun.security.smartcardio.SunPCSC"); + } + + private static void installOpenJDKProvider(String className) throws Exception { + Provider provider = (Provider) Class.forName(className).getConstructor().newInstance(); + Security.insertProviderAt(provider, 1); + } +} diff --git a/java/com/google/security/wycheproof/WycheproofRunner.java b/java/com/google/security/wycheproof/WycheproofRunner.java new file mode 100644 index 0000000..e4da431 --- /dev/null +++ b/java/com/google/security/wycheproof/WycheproofRunner.java @@ -0,0 +1,206 @@ +/** + * @license + * Copyright 2013 Google Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.security.wycheproof; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Arrays; +import org.junit.runner.Description; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +/** + *

A custom JUnit4 runner that, with annotations, allows choosing tests to run on a specific + * provider. To use it, annotate a runner class with {@code RunWith(WycheproofRunner.class)}, and + * {@code SuiteClasses({AesGcmTest.class, ...})}. When you run this class, it will run all the tests + * in all the suite classes. + * + *

To exclude certain tests, a runner class should be annotated with {@code @Provider} which + * indicates the target provider. Test exclusion is defined as follows: + *